16 手動によるデータ暗号化

DBMS_CRYPTO PL/SQLパッケージを使用して、データを手動で暗号化できます。

暗号化で解決しないセキュリティの問題

データの暗号化には多くのメリットがありますが、多くのデメリットもあります。

原則1: 暗号化はアクセス制御の問題を解決しない

データを暗号化するとき、暗号化によってアクセス制御の構成が妨げられないように注意する必要があります。

ほとんどの組織で、データのアクセスを、そのデータを参照する必要があるユーザーのみに制限する必要があります。たとえば、人事管理システムでは、従業員には各自の雇用レコードのみを参照できるように制限し、従業員の上司には直属の部下の雇用レコードを参照できるようにする場合があります。人事部門の担当者が複数の従業員の従業員レコードを参照する必要がある場合もあります。

一般的には、アクセス制御メカニズムを使用して、データを見る必要がある人にデータ・アクセスを制限するセキュリティ・ポリシーに対処できます。Oracle Databaseは、強力で独自に評価されたアクセス制御メカニズムを何年もの間提供してきました。仮想プライベート・データベースにより、アクセス制御を詳細なレベルまで規定できます。

人事部門のレコードは機密情報とみなされるため、セキュリティをより強化するためにこの情報はすべて暗号化する必要があると考えがちです。しかし、暗号化によってきめ細かいアクセス制御を規定できなくなるため、データ・アクセスの妨げとなる場合があります。たとえば、従業員、その上司および人事部門の担当者すべてが、従業員レコードにアクセスする必要がある場合があります。従業員データがすべて暗号化されている場合、この3人は暗号化されていない形式のデータにアクセスできる必要があります。したがって、従業員、上司および人事部門の担当者はデータを復号化するために同じ暗号化キーを共有する必要があります。このように、アクセス制御の向上という観点では、暗号化によってセキュリティが強化されず、アプリケーションの正しい機能や効率的な機能の妨げとなる場合があります。さらに、システムの複数のユーザー間で暗号化キーの送信および共有を安全に行うことは難しいという別の問題もあります。

格納データを暗号化するときの基本原則は、暗号化によってアクセス制御が妨げられないようにすることです。たとえば、empに対するSELECT権限を持つユーザーが、基本的には参照できるすべてのデータへの参照を暗号化メカニズムによって制限されないようにする必要があります。また、ユーザーが表のすべての暗号化データを参照する必要がある場合は、あるキーを使用して表の一部を暗号化し、別のキーを使用して表の他の部分を暗号化するメリットはほとんどありません。この場合、ユーザーがデータを参照できるように、データを復号化するオーバーヘッドが増加するのみです。アクセス制御が適切に実装されている場合は、暗号化によってデータベース自体の中でセキュリティが強化されることはほとんどありません。データベース内のデータにアクセスする権限を持つユーザーについては、暗号化しても権限は変わりません。したがって、アクセス制御の問題解決に暗号化を使用しないでください。

原則2: 暗号化は不正な管理者からデータを保護しない

Oracle Database VaultなどのOracle機能を使用して、不正なデータベース管理者からデータベースを保護できます。

不正なユーザーがパスワードを推測して上位(データベース管理者)の権限を取得する可能性を懸念して、この脅威から保護するために格納データを暗号化することを考える組織もあります。

ただし、この問題の正しい解決策は、データベース管理者アカウントを保護し、その他の権限付きアカウントのデフォルトのパスワードを変更することです。データベースに侵入する最も簡単な方法は、管理者が変更しないままにしている権限付きアカウントのデフォルトのパスワードを使用することです。その一例がSYS/CHANGE_ON_INSTALLです。

不正なユーザーがDBA権限を取得すると、データベースに対して多くの破壊的な行為を実行できますが、暗号化ではそれらの行為の多くからデータベースを保護できません。たとえば、データを破壊または削除する行為、ユーザー・データをファイル・システムにエクスポートし、そのデータを電子メールで自分自身に戻してパスワード・クラッカを実行するなどの行為があります。

データベース管理者は通常すべての権限を所有しているため、データベース管理者がデータベース内のすべてのデータを参照できることについて懸念を持つ組織もあります。そのような組織では、データベース管理者はデータベースを管理するのみで、そのデータベースに含まれるデータを参照できないようにする必要があると考えます。また、1人のユーザーに非常に多くの権限が集中することを懸念し、DBA機能を分割するか、または2人でアクセスするルールを規定する方が望ましいと考える組織もあります。

すべてのデータ(または大量のデータ)を暗号化すると、前述の問題が解決すると考えがちですが、このような不正行為からデータを保護するためのより優れた方法があります。たとえば、Oracle DatabaseではDBA権限の制限付きの分割がサポートされています。Oracle Databaseでは、SYSDBAユーザーとSYSOPERユーザーに対するネイティブなサポートが提供されています。SYSDBAはすべての権限を所有しますが、SYSOPERは制限付き権限セット(データベースの起動および停止など)を所有します。

さらに、複数のシステム権限を網羅する、より小さなロールを作成することもできます。たとえば、jr_dbaロールには、すべてのシステム権限を含めるのではなく、準データベース管理者に適切なロールのみ(CREATE TABLECREATE USERなど)を含めます。

Oracle Databaseは、SYS(またはSYS権限を持つユーザー)によって実行されたアクションを監査し、オペレーティング・システムの保護位置にその監査証跡を格納できます。このモデルを使用すると、オペレーティング・システムに対してルート権限を持つ別の監査人が、SYSによって実行されたすべてのアクションを監査できるため、監査人は、すべてのデータベース管理者が実行したアクションに対する責任をデータベース管理者自身に持たせることができます。

データベース管理者のアクセス権と制御権をOracle Database Vaultを使用して調整することもできます。

データベース管理者は信頼される立場にいます。諜報機関のような最も機密性の高いデータを扱う組織においても、通常、データベース管理者機能は分割されません。かわりに、データベース管理者には信頼性が必要なため、厳しく管理されます。定期的な監査によって不適切なアクティビティを明らかにできます。

格納データの暗号化が、データベースの管理を妨げないことが重要です。そうでない場合は、より大きいセキュリティ問題になる可能性があります。たとえば、データを暗号化することでそのデータが破損した場合セキュリティ問題となり、データ自体を解釈できず、修復不可能になる可能性があります。

暗号化を使用すると、データベース管理者(または権限を持つその他のユーザー)がデータベース内のデータを参照する機能を制限できます。ただし、これは、データベース管理者の権限を適切に管理すること、または強力なシステム権限の使用を制御することの代用にはなりません。信頼できないユーザーが重要な権限を持っている場合、そのユーザーが組織に多くの脅威をもたらすこととなり、暗号化されていないクレジット・カード番号を参照されるよりもはるかに深刻な状況に陥る場合もあります。

関連項目:

Oracle Database Vaultを使用したデータベース管理者のアクセス権と制御権の調整の詳細は、『Oracle Database Vault管理者ガイド』を参照してください。

原則3: すべてのデータを暗号化してもデータは保護されない

通常、データの暗号化によってセキュリティが強化されるのであれば、すべてのデータを暗号化することにより、データはすべて保護されると考えますが、これは誤りです。

前述の2つの原則で説明したとおり、暗号化ではアクセス制御の問題に適切に対処できないため、暗号化によって通常のアクセス制御を妨げないことが重要になります。さらに、本番データベース全体を暗号化すると、読取り、更新または削除を行うために、すべてのデータを復号化する必要があります。暗号化は、本来、パフォーマンス集中型の操作であるため、すべてのデータを暗号化するとパフォーマンスに大きい影響を与えます。

可用性はセキュリティの重要な側面です。データの暗号化によって、データを使用できなくなったり、パフォーマンスが低下して可用性に悪影響を与えた場合は、すべてのデータを暗号化することで新たなセキュリティ問題が発生することになります。セキュリティの適切な手続きとして、暗号化キーを定期的に変更する必要がありますが、このときデータベースにアクセスできなくなります。これも可用性に悪影響を与えます。キーを変更する場合は、データを復号化して新しいキーで再度暗号化するまでの間、データベースにアクセスできなくなります。

格納データをオフラインで暗号化することは、メリットもあります。たとえば、組織が半年から1年単位で遠隔地にオフラインでバックアップを格納する場合があります。もちろん、保護の第1段階は、物理的なアクセス制御を確立することによって、データを格納する施設を保護することです。さらに、このデータを格納する前に暗号化すると、メリットがあります。このデータはオンラインでアクセスされないため、パフォーマンスについて考慮する必要はありません。Oracleデータベースにはこの機能が備わっていませんが、暗号化サービスを提供するベンダーがあります。この方法を検討する組織は、バックアップ・データの大規模な暗号化を実施する前に、プロセスを徹底的にテストする必要があります。オフラインで格納する前に、暗号化されたデータを正常に復号化でき、正しく再インポートできることを確認する必要があります。

データ暗号化の課題

暗号化によってセキュリティが強化される場合、いくつかの技術的な課題が伴います。

暗号化され索引付けされたデータ

暗号化データが索引付けされている場合は、特別な問題が発生します。

たとえば、ある会社が国民識別番号(米国社会保障番号(SSN)など)を各従業員の従業員番号として使用しているとします。会社は従業員番号を機密性の高いデータと考えているため、employees表のemployee_number列のデータを暗号化します。employee_number列には一意の値が含まれているため、データベース設計者は、パフォーマンスを向上するためにそのデータを索引付けします。

ただし、DBMS_CRYPTO (または別のメカニズム)を使用して列のデータを暗号化した場合、その列の索引にも暗号化された値が含まれます。列の索引に暗号化された値が含まれている場合、この索引は等価性チェック(たとえば、SELECT * FROM emp WHERE employee_number = '987654321')には使用できますが、それ以外の目的には事実上使用できません。索引付けされたデータを暗号化しないでください。

国民識別番号は一意のIDとして使用しないことをお薦めします。かわりに、CREATE SEQUENCE文を使用して、一意の識別番号を生成してください。国民識別番号を使用しない理由は、次のとおりです。

  • 国民識別番号の乱用に関連するプライバシの問題があること(識別情報の盗難など)

  • 国民識別番号に一部の重複があること(例: 米国社会保障番号)

生成された暗号化キー

暗号化されたデータの安全性は、データの暗号化に使用されるキーの安全性に依存します。

暗号化キーは、安全な暗号化キー生成方法を使用して安全に生成する必要があります。Oracle Databaseは、DBMS_CRYPTORANDOMBYTESファンクションを使用した完全な乱数の生成を提供しています。DBMS_CRYPTOは、以前にRSA Securityによって認証された安全な乱数ジェネレータ(RNG)をコールします。

ノート:

DBMS_RANDOMパッケージは使用しないでください。DBMS_RANDOMパッケージは擬似乱数を生成します。「セキュリティのための乱雑性についての推奨事項(RFC-1750)」には、擬似乱数プロセスを使用して機密の数値を生成すると、真のセキュリティを維持できなくなると述べられています。

キーの値を暗号化する場合は、必ず正しいバイト数を指定してください。たとえば、ENCRYPT_AES128暗号化アルゴリズムの場合は、16バイトのキーを指定する必要があります。

転送された暗号化キー

暗号化キーがアプリケーションによってデータベースに渡される場合は、暗号化キーを暗号化する必要があります。

暗号化しないと、キーの転送時に、侵入者がキーにアクセスできる可能性があります。ネットワーク・データの暗号化では、暗号化キーを含む送信中のデータはすべて、改ざんまたは傍受から保護されます。

暗号化キーの格納

データベースまたはオペレーティング・システムに暗号化キーを格納できます。

暗号化キーの格納について

暗号化キーの格納は、暗号化で最も重要で難しい問題の1つです。

対称キーで暗号化されたデータを復元するには、データを復号化しようとする承認済のアプリケーションまたはユーザーがキーにアクセスできる必要があります。同時に、アクセス権のない暗号化データに不正アクセスしようとするユーザーは、キーにアクセスできないようにする必要があります。

データベースへの暗号化キーの格納

データベースに暗号化キーを格納しても、データベース管理者が暗号化データにアクセスできなくなるとは限りません。

すべての権限を持つデータベース管理者は暗号化キーを含む表にもアクセスできます。ただし、明確な意図のない詮索好きなユーザーまたはオペレーティング・システム上のデータベース・ファイルを破壊しようとするユーザーに対しては、適切なセキュリティ対策になる可能性があります。

簡単な例として、従業員データを含む表(EMP)を作成するとします。列の1つに格納されている各従業員の社会保障番号(SSN)を暗号化します。従業員のSSNは、別の列に格納されているキーを使用して暗号化できます。ただし、表全体に対するSELECT権限を持っているユーザーは、暗号化キーを取得し、対応するSSNを復号化できます。

この暗号化スキーマは簡単に侵害できるようにみえますが、多少の取り組みで、非常に強力な不正侵入対策ソリューションを作成できます。たとえば、この方法を使用してSSNを暗号化する前に、employee_numberのデータをさらに変換するテクニックを使用することで、SSNを暗号化できます。これは、employee_numberと従業員の誕生日のXOR(排他的論理和)演算を使用して値の妥当性を判別するような単純なテクニックの場合もあります。

別の保護として、暗号化を実行するPL/SQLパッケージの本体を(WRAPユーティリティを使用して)ラップして、コードを不明瞭化(スクランブル化)する方法もあります。WRAPユーティリティは入力SQLファイルを処理し、その中のPL/SQLユニットを不明瞭化します。たとえば、次のコマンドではkeymanage.sqlファイルを入力として使用しています。

wrap iname=/mydir/keymanage.sql

開発者は次に、ラップされたパッケージに含まれるキーを使用して、パッケージ内のファンクションにDBMS_CRYPTOパッケージ・コールをコールさせることができます。

Oracle Databaseでは、動的に生成されたPL/SQLコードを不明瞭化できます。DBMS_DDLパッケージには、動的に生成されたPL/SQLプログラム・ユニットを不明瞭化するために使用できるサブプログラムが2つ含まれています。たとえば、次のブロックでは、DBMS_DDL.CREATE_WRAPPEDプロシージャを使用して、動的に生成されたPL/SQLコードをラップします。

BEGIN
......
SYS.DBMS_DDL.CREATE_WRAPPED(function_returning_PLSQL_code());
......
END;

ラップは解読不可能ではありませんが、侵入者が暗号化キーにアクセスするのはかなり困難になります。各暗号化データの値ごとに異なるキーが提供されている場合でも、キーの値をパッケージ内に埋め込まないでください。かわりに、キーの管理を実行するパッケージをラップ(つまり、データ変換またはパディング)してください。

関連項目:

WRAPコマンドライン・ユーティリティと動的ラップのためのDBMS_DDLサブプログラムの詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください。

また、データをラップするかわりに暗号化キーを別の表に格納し、プロシージャを使用してキー表に対するコールをエンベロープする方法もあります。キー表は、主キーと外部キー関係を使用してデータ表に結合できます。たとえば、employee_numberは、従業員情報と暗号化されたSSNを格納するemployees表の主キーです。また、employee_number列は、従業員のSSNの暗号化キーを格納するssn_keys表に対する外部キーです。ssn_keys表に格納されたキーも使用前に(XOR演算により)変換できるため、キー自体が暗号化されずに格納されることはありません。プロシージャをラップすると、キーを使用前に変換する方法を隠すことができます。

この方法のメリットは次のとおりです。

  • 表への直接アクセス権を持つユーザーは、暗号化されていない機密データを参照することも、キーを取得してデータを復号化することもできません。

  • 復号化されたデータへのアクセスは、暗号化されたデータの選択、キー表からの復号化キーの取得、およびデータの復号化に使用するキーの変換を実行するプロシージャを介して制御できます。

  • データ変換アルゴリズムは、プロシージャをラップし、プロシージャ・コードを不明瞭化することによって、偶発的な傍受から隠されます。

  • データ表とキー表の両方に対するSELECT権限があっても、キーは使用前に変換されるため、この権限を持つユーザーがそのデータを復号化できる保証はありません。

この方法のデメリットは、キー表とデータ表の両方に対するSELECT権限があり、キー変換アルゴリズムを導出できるユーザーが、暗号化スキームを解読できることです。

前述の方法は完全ではありませんが、クリアテキストで格納されている機密情報を簡単に取得できないように保護するには十分です。

オペレーティング・システムへの暗号化キーの格納

暗号化キーをオペレーティング・システムのフラット・ファイルに格納する場合、PL/SQLからコールアウトを実行して暗号化キーを取得できます。

ただし、オペレーティング・システムにキーを格納し、それに対してコールアウトを行う場合、データはオペレーティング・システムでの保護と同じ程度にのみ保護されます。

セキュリティ上の主な懸念が、オペレーティング・システムからデータベースに侵入される可能性があるということである場合、オペレーティング・システムにキーを格納することは、データベース自体にキーを格納することより、侵入者にとっては暗号化されたデータを取得しやすくなります。

ユーザー自身による暗号化キーの管理

ユーザーにキーを提供させる場合は、ユーザー自身がそのキーに責任を持つことを想定しています。

ヘルプ・デスクへのコールの40%が、パスワードを忘れたユーザーからのコールであることから、ユーザーが暗号化キーを管理することのリスクは明らかです。多くの場合、ユーザーは暗号化キーを忘れるか、キーを書き留めておくため、セキュリティ上の弱点が生じます。ユーザーが暗号化キーを忘れたり、会社を退職した場合、データは復元できなくなります。

ユーザーにキーを提供する、またはユーザーがキーを管理する場合は、ネイティブ・ネットワーク暗号化を使用して、キーがクリアテキストでクライアントからサーバーに渡されないようにする必要があります。また、キー・アーカイブ・メカニズムを開発する必要があります。これも困難なセキュリティの問題です。キー・アーカイブおよびバックドアは、暗号化によって解決しようとしているセキュリティ上の弱点を生み出すことになります。

透過的データベース暗号化および表領域暗号化を使用した手動暗号化

透過的データベース暗号化および表領域暗号化は、暗号化された表および表領域に対するキーを自動的に管理して、安全な暗号化を提供します。

アプリケーションで、メディアに格納されている機密性の高い列データの保護を必要とする場合は、これらの2種類の暗号化を使用することで、これを簡単にすばやく行えます。

関連項目:

透過的データ暗号化の詳細は、『Oracle Database Advanced Securityガイド』を参照してください。

暗号化キーの変更の重要性

慎重なセキュリティの手続きでは、暗号化キーを定期的に変更するように指示されます。

格納データの場合、これを実行するには、データを定期的に暗号解除し、適切な別のキーを使用して再度暗号化する必要があります。

暗号化キーの変更は、おそらくデータへのアクセスがない間に実行しますが、また別の課題が生まれます。クレジット・カード番号を暗号化するWebベースのアプリケーションでは、暗号化キーを切り替える間はアプリケーション全体を停止できないため、特に問題になります。

バイナリ・ラージ・オブジェクトの暗号化

一部のデータ型は、暗号化に手間がかかります。

たとえば、Oracle Databaseでは、非常に大規模なオブジェクト(たとえば、数GB)をデータベースに格納するバイナリ・ラージ・オブジェクト(BLOB)をサポートしています。BLOBは、列として内部的に格納するか、または外部ファイルに格納できます。

DBMS_CRYPTOパッケージを使用したデータ暗号化ストレージ

DBMS_CRYPTOパッケージは、セキュリティ問題に取り組むための様々な方法を提供します。

暗号化は、複数のセキュリティへの脅威に対処できる理想的なソリューションではありませんが、データベースに格納する前に機密性の高いデータを選択的に暗号化することによって、セキュリティを強化できます。このようなデータの例としては、クレジット・カード番号や国民識別番号などがあります。

Oracle Databaseには、格納データの暗号化および復号化のためのPL/SQLパッケージDBMS_CRYPTOが用意されています。このパッケージは、Advanced Encryption Standard(AES)の暗号化アルゴリズムも含めて、複数の業界標準暗号化およびハッシング・アルゴリズムをサポートしています。AESは、データ暗号化規格(DES)にかわる規格として、National Institute of Standards and Technology(NIST)によって承認されました。

DBMS_CRYPTOパッケージは、RAWおよびイメージやサウンドなどのラージ・オブジェクト(LOB)を含むOracle Databaseの一般的なデータ型の暗号化および復号化に使用できます。特に、BLOBとCLOBをサポートしています。さらに、様々なデータベース文字セット間でデータを暗号化するためのグローバリゼーション・サポートも提供します。

次の暗号化アルゴリズムがサポートされています。

  • Advanced Encryption Standard(AES)

  • SHA-2暗号化ハッシュ設定:

    • HASH_SH256

    • HASH_SH384

    • HASH_SH512

  • SHA-2メッセージ認証コード(MAC)

DBMS_CRYPTOではブロック暗号修飾子も提供されています。Public Key Cryptographic Standard(PKCS)#5を含む複数のパディング・オプションおよびCipher Block Chaining(CBC)を含む4つのブロック暗号連鎖モードから選択できます。パディングは8バイトの倍数で実行する必要があります。

ノート:

  • DESはNational Institute of Standards and Technology(NIST)の推奨対象ではなくなりました。

  • SHA-1を使用する方がMD5より安全性が高くなります。(MD5は、Oracle Database 20c以降では非推奨となっています)。

    Oracle Database 20c以降、DBMS_CRYPTO内に含まれる古い暗号化およびハッシュ・アルゴリズムは非推奨になりました。

    非推奨になったアルゴリズムとしては、MD4、MD5およびRC4関連のアルゴリズムがあります。古い安全性の低い暗号化アルゴリズムの削除により、これらのAPIが誤って使用されるのを防ぎます。セキュリティ要件を満たすために、最新の暗号化アルゴリズムを使用することをお薦めします。

    これらが非推奨となったことから、RC4暗号文を復号化し、より安全なアルゴリズムで暗号化することをお薦めします。Oracle Database 20cを使用している場合は、これらの非推奨となったアルゴリズムがサポートされている間に、復号化と再暗号化を完了する必要があります。将来のリリースでは、これらの非推奨となったアルゴリズムは削除される予定です。RC4のサポートが終了すると、RC4を使用して暗号化された暗号文を復号化できなくなります。また、MD4およびMD5ハッシュ・アルゴリズムをより新しいバージョンに更新することをお薦めします。通常、これらのハッシュ・アルゴリズムは、整合性チェックの形式としてデータに使用されます。しかしながら、これらのハッシュ・アルゴリズムが削除されると、データの整合性チェックが問題となります。Oracle Database 20cリリースのフェーズにおいて、それらすべてのハッシュを、DBMS_CRYPTOでサポートされている他のいずれかのハッシュ・アルゴリズムを使用して再生成することをお薦めします。

  • SHA-2を使用する方がSHA-1より安全性が高くなります。

  • キー付きMD5は、無防備ではありません。

表16-1に、DBMS_CRYPTOパッケージ機能の概要を示します。

表16-1 DBMS_CRYPTOパッケージ機能の概要

機能 DBMS_CRYPTOでサポートされている機能

暗号化アルゴリズム

AES

パディング形式

PKCS5、複数ゼロ

ブロック暗号連鎖モード

CBC、CFB、ECB、OFB

暗号化ハッシュ・アルゴリズム

SHA-1、SHA-2、HASH_SH256、HASH_SH384、HASH_SH512

キー・ハッシュ(MAC)・アルゴリズム

HMAC_MD5、HMAC_SH1、HMAC_SH256、HMAC_SH384、HMAC_SH512

暗号化擬似乱数ジェネレータ

RAWNUMBERBINARY_INTEGER

暗号化アルゴリズム

AES

パディング形式

PKCS5、複数ゼロ

ブロック暗号連鎖モード

CBC、CFB、ECB、OFB

暗号化ハッシュ・アルゴリズム

SHA-1、SHA-2、MD4、MD5、HASH_SH256、HASH_SH384、HASH_SH512

キー・ハッシュ(MAC)・アルゴリズム

HMAC_MD5、HMAC_SH1、HMAC_SH256、HMAC_SH384、HMAC_SH512

暗号化擬似乱数ジェネレータ

RAWNUMBERBINARY_INTEGER

データベース型

RAWCLOBBLOB

DBMS_CRYPTOは、新しいシステムと既存のシステムの両方に対応する広範囲のアルゴリズムをサポートしています。3DES_2KEYおよびMD4は下位互換性を維持するために提供されていますが、3DES、AESまたはSHA-1を使用するとセキュリティをより強化できます。3DES_2KEYおよびMD4の使用はお薦めしません。

DBMS_CRYPTOパッケージには、比較の際に便利な暗号チェックサム機能(MD5)と、安全な乱数を生成する機能(RANDOMBYTES関数)が含まれています。安全な乱数生成は暗号化の重要な部分です。予測可能なキーは簡単に推定されるキーであり、キーを簡単に推定できることによってデータが簡単に復号化される可能性があります。ほとんどの暗号解読が、総当たり解析(可能性のあるすべてのキーを繰り返す)によってではなく、脆弱なキーや適切に格納されていないキーを見つけ出すことによって行われています。

ノート:

DBMS_RANDOMは暗号化キーの生成には不適切なため、使用しないでください。

キーの管理はプログラムによって実行されます。つまり、アプリケーション(またはファンクションのコール側)が、暗号化キーを提供する必要があります。これは、アプリケーション開発者がキーを安全に格納し、取得する方法を検討する必要があることを意味します。様々なキー管理方法の相対的なメリットとデメリットについては、後続の項で説明します。DESアルゴリズム自体の有効なキーの長さは56ビットです。

関連項目:

OFBモードで暗号化された暗号文のOracle Databaseリリース11gでの使用

Oracle Databaseリリース11gでは、出力フィードバック(OFB)を使用するように暗号文が構成されても、かわりに電子コードブック(ECB)モードが使用されました。

Oracle Databaseリリース11gで、DBMS_CRYPTO.CHAIN_OFB暗号ブロック連鎖修飾子を設定して、出力フィードバック(OFB)モードを使用するように暗号文の暗号化を構成すると、Oracle Bug 13001552のため、その構成で電子コードブック(ECB)モードが誤って使用されました。この不具合はOracle Databaseリリース12cで修正されています。したがって、Oracle Databaseリリース11gからリリース12cにアップグレードした後、リリース11gでOFBノードを使用して暗号化された暗号文は、Oracle Databaseリリース12cでは修正されたOFBモードで正しく復号化されません。

この問題を解決するには:

  1. DBMS_CRYPTO PL/SQLパッケージに対するEXECUTE権限があるユーザーとして、データベースにログインします。
  2. DBMS_CRYPTO.CHAIN_ECBブロック暗号連鎖修飾子を使用して、暗号文を復号化します。

次の例のdbmscrypto11.sqlは、Oracle Databaseリリース11gでの誤った動作を示します。

dbmscrypto11.sql:
set serveroutput on

declare
  l_mod_ofb pls_integer;
  l_mod_ecb pls_integer;
  v_key raw(32);
  v_iv  raw(16);
  v_test_in raw(16);
  v_ciphertext raw(16);
  v_test_out_ECB raw(16);
  v_test_out_OFB raw(16);
begin
  l_mod_ofb := dbms_crypto.ENCRYPT_AES256
       + dbms_crypto.CHAIN_OFB
       + DBMS_CRYPTO.PAD_NONE ;
  l_mod_ecb := dbms_crypto.ENCRYPT_AES256
       + dbms_crypto.CHAIN_ECB
       + DBMS_CRYPTO.PAD_NONE ;

  v_key := hextoraw
  ('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4');
  v_iv :=   hextoraw('000102030405060708090A0B0C0D0E0F');
  v_test_in := hextoraw('6bc1bee22e409f96e93d7e117393172a');
  v_ciphertext := dbms_crypto.encrypt(src => v_test_in,
                                  TYP => l_mod_ofb,
                                  key => v_key,
                                  iv => v_iv);
  v_test_out_ECB := dbms_crypto.decrypt(src => v_ciphertext,
                                  TYP => l_mod_ecb,
                                  key => v_key,
                                  iv => v_iv);
  v_test_out_OFB := dbms_crypto.decrypt(src => v_ciphertext,
                                  TYP => l_mod_ofb,
                                  key => v_key,
                                  iv => v_iv);
  dbms_output.put_line
  ('Input plaintext                      : '||rawtohex(v_test_in));
  dbms_output.put_line
  ('11g: Ciphertext (encrypt in OFB mode): '||rawtohex(v_ciphertext));
  dbms_output.put_line
  ('11g: Output of decrypt in ECB mode   : '||rawtohex(v_test_out_ECB));
  dbms_output.put_line
  ('11g: Output of decrypt in OFB mode   : '||rawtohex(v_test_out_OFB));
end;
/

生成される出力は次のようになります。

SQL> @dbmscrypto11.sql

Input plaintext                      : 6BC1BEE22E409F96E93D7E117393172A
11g: Ciphertext (encrypt in OFB mode): F3EED1BDB5D2A03C064B5A7E3DB181F8
11g: Output of decrypt in ECB mode   : 6BC1BEE22E409F96E93D7E117393172A
11g: Output of decrypt in OFB mode   : 6BC1BEE22E409F96E93D7E117393172A

この出力は、Oracle Databaseリリース11gではOFBモードが誤ってECBモードになるため、OFBまたはECBモードのどちらで復号化しても正しいプレーンテキストになることを示しています。

次の例のdbmscrypto12from11.sqlは、Oracle Databaseリリース11gからリリース12cにアップグレードした後、リリース11gのOFBモードで暗号化した暗号文を適切に復号化するには、OFBモードではなく、ECBモードを使用する必要があることを示します。

dbmscrypto12from11.sql:
set serveroutput on

declare
  l_mod_ofb pls_integer;
  l_mod_ecb pls_integer;
  v_key raw(32);
  v_iv  raw(16);
  v_test_in raw(16);
  v_ciphertext11 raw(16);
  v_test_out_ECB raw(16);
  v_test_out_OFB raw(16);
begin
  l_mod_ofb := dbms_crypto.ENCRYPT_AES256
       + dbms_crypto.CHAIN_OFB
       + DBMS_CRYPTO.PAD_NONE ;
  l_mod_ecb := dbms_crypto.ENCRYPT_AES256
       + dbms_crypto.CHAIN_ECB
       + DBMS_CRYPTO.PAD_NONE ;

  v_key := hextoraw
  ('603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4');
  v_iv :=   hextoraw('000102030405060708090A0B0C0D0E0F');
  v_test_in := hextoraw('6bc1bee22e409f96e93d7e117393172a');
  v_ciphertext11 := hextoraw('F3EED1BDB5D2A03C064B5A7E3DB181F8');

  v_test_out_ECB := dbms_crypto.decrypt(src => v_ciphertext11,
                                  TYP => l_mod_ecb,
                                  key => v_key,
                                  iv => v_iv);
  v_test_out_OFB := dbms_crypto.decrypt(src => v_ciphertext11,
                                  TYP => l_mod_ofb,
                                  key => v_key,
                                  iv => v_iv);
  dbms_output.put_line
  ('Input plaintext (to 11g)             : '||rawtohex(v_test_in));
  dbms_output.put_line
  ('11g: Ciphertext (encrypt in OFB mode): '||rawtohex(v_ciphertext11));
  dbms_output.put_line
  ('12c: Output of decrypt in ECB mode   : '||rawtohex(v_test_out_ECB));
  dbms_output.put_line
  ('12c: Output of decrypt in OFB mode   : '||rawtohex(v_test_out_OFB));
end;
/

生成される出力は次のようになります。

SQL> @dbmscrypto12from11.sql
Input plaintext (to 11g)             : 6BC1BEE22E409F96E93D7E117393172A
11g: Ciphertext (encrypt in OFB mode): F3EED1BDB5D2A03C064B5A7E3DB181F8
12c: Output of decrypt in ECB mode   : 6BC1BEE22E409F96E93D7E117393172A
12c: Output of decrypt in OFB mode   : 4451EBE041EB29E191BBA0E9D67FAEB2

Oracle Databaseリリース11gからリリース12cへのアップグレードを予定している場合は、復号化操作でECBモードを使用するように、OFBモードが指定されたすべてのスクリプトを編集してください。この方法によって、スクリプトはリリース11gとリリース12c以降の両方で使用できるため、ビジネスの継続性を確保できます。

データの暗号化APIの使用例

データ暗号化APIの使用例として、DBMS_CRYPTO.SQLプロシージャの使用、AES 256ビット・データの暗号化およびBLOBデータの暗号化などがあります。

データ暗号化プロシージャの例

DBMS_CRYPTO.SQL PL/SQLプログラムを使用してデータを暗号化できます。

このサンプル・コードでは、次の処理を実行します。

  • 文字列(VARCHAR2型)をRAWデータ型に変換した後、DESを使用して暗号化します。

    DBMS_CRYPTOパッケージの暗号化および復号化ファンクションとプロシージャはRAWデータ型にのみ機能するため、このステップが必要となります。

  • SHA-1アルゴリズムを使用した160ビット・ハッシュの作成方法を示します。

  • MD5アルゴリズムを使用したキー依存の一方向ハッシュであるMACの計算方法を示します。(Oracle Databaseリリース20c以降では、MD5アルゴリズムは非推奨となっています)。

次に、DBMS_CRYPTO.SQLプロシージャを示します。

DECLARE
    input_string     VARCHAR2(16) := 'tigertigertigert';
    raw_input        RAW(128) :=
UTL_RAW.CAST_TO_RAW(CONVERT(input_string,'AL32UTF8','US7ASCII'));
    key_string       VARCHAR2(8)  := 'scottsco';
    raw_key          RAW(128) :=
UTL_RAW.CAST_TO_RAW(CONVERT(key_string,'AL32UTF8','US7ASCII'));
    encrypted_raw    RAW(2048);
    encrypted_string VARCHAR2(2048);
    decrypted_raw    RAW(2048);
    decrypted_string VARCHAR2(2048); 
-- Begin testing Encryption: 
BEGIN
    dbms_output.put_line('> Input String                     : ' || 
    CONVERT(UTL_RAW.CAST_TO_VARCHAR2(raw_input),'US7ASCII','AL32UTF8'));
    dbms_output.put_line('> ========= BEGIN TEST Encrypt =========');
    encrypted_raw := dbms_crypto.Encrypt(
        src => raw_input, 
        typ => DBMS_CRYPTO.DES_CBC_PKCS5, 
        key => raw_key);
        dbms_output.put_line('> Encrypted hex value              : ' || 
        rawtohex(UTL_RAW.CAST_TO_RAW(encrypted_raw)));
decrypted_raw := dbms_crypto.Decrypt(
        src => encrypted_raw, 
        typ => DBMS_CRYPTO.DES_CBC_PKCS5, 
        key => raw_key);
    decrypted_string := 
    CONVERT(UTL_RAW.CAST_TO_VARCHAR2(decrypted_raw),'US7ASCII','AL32UTF8');
dbms_output.put_line('> Decrypted string output          : ' || 
        decrypted_string);
if input_string = decrypted_string THEN
    dbms_output.put_line('> String DES Encyption and Decryption successful');
END if;
dbms_output.put_line('');
dbms_output.put_line('> ========= BEGIN TEST Hash =========');
    encrypted_raw := dbms_crypto.Hash(
        src => raw_input, 
        typ => DBMS_CRYPTO.HASH_SH1);
dbms_output.put_line('> Hash value of input string       : ' || 
        rawtohex(UTL_RAW.CAST_TO_RAW(encrypted_raw)));
dbms_output.put_line('> ========= BEGIN TEST Mac =========');
    encrypted_raw := dbms_crypto.Mac(
        src => raw_input, 
        typ => DBMS_CRYPTO.HMAC_MD5, 
        key => raw_key);
dbms_output.put_line('> Message Authentication Code      : ' || 
        rawtohex(UTL_RAW.CAST_TO_RAW(encrypted_raw)));
dbms_output.put_line('');
dbms_output.put_line('> End of DBMS_CRYPTO tests  ');
END;
/

AES 256ビット・データ暗号化および復号化プロシージャの例

PL/SQLブロックを使用して、事前定義された変数を暗号化または復号できます。

次の例では、事前定義の変数input_stringが、Cipher Block ChainingとPKCS #5パディングを使用するAES 256ビット・アルゴリズムを使用しています。

declare
   input_string       VARCHAR2 (200) := 'Secret Message';
   output_string      VARCHAR2 (200);
   encrypted_raw      RAW (2000);             -- stores encrypted binary text
   decrypted_raw      RAW (2000);             -- stores decrypted binary text
   num_key_bytes      NUMBER := 256/8;        -- key length 256 bits (32 bytes)
   key_bytes_raw      RAW (32);               -- stores 256-bit encryption key 
   encryption_type    PLS_INTEGER :=          -- total encryption type
                            DBMS_CRYPTO.ENCRYPT_AES256
                          + DBMS_CRYPTO.CHAIN_CBC
                          + DBMS_CRYPTO.PAD_PKCS5;
begin
   DBMS_OUTPUT.PUT_LINE ('Original string: ' || input_string);
   key_bytes_raw := DBMS_CRYPTO.RANDOMBYTES (num_key_bytes);
   encrypted_raw := DBMS_CRYPTO.ENCRYPT
      (
         src => UTL_I18N.STRING_TO_RAW (input_string, 'AL32UTF8'),
         typ => encryption_type,
         key => key_bytes_raw
      );
    -- The encrypted value in the encrypted_raw variable can be used here:
   decrypted_raw := DBMS_CRYPTO.DECRYPT
      (
         src => encrypted_raw,
         typ => encryption_type,
         key => key_bytes_raw
      );
   output_string := UTL_I18N.RAW_TO_CHAR (decrypted_raw, 'AL32UTF8');
   DBMS_OUTPUT.PUT_LINE ('Decrypted string: ' || output_string);
end;

BLOBデータの暗号化および復号化プロシージャの例

BLOBデータを暗号化できます。

次に、BLOBデータを暗号化および復号化するためのPL/SQLプログラム(blob_test.sql)のサンプルを示します。このサンプル・コードは次の操作を実行し、ステップごとに進捗状況(または問題)を出力します。

  • BLOB列の表を作成します。

  • RAWの値をその表に挿入します。

  • RAWデータを暗号化します。

  • 暗号化されたデータを復号化します。

blob_test.sqlプロシージャは次のとおりです。

-- 1. Create a table for BLOB column:
create table table_lob (id number, loc blob);

-- 2. Insert 3 empty lobs for src/enc/dec:
insert into table_lob values (1, EMPTY_BLOB());
insert into table_lob values (2, EMPTY_BLOB());
insert into table_lob values (3, EMPTY_BLOB());

set echo on
set serveroutput on

declare
    srcdata    RAW(1000);
    srcblob    BLOB;
    encrypblob BLOB;
    encrypraw  RAW(1000);
    encrawlen  BINARY_INTEGER;
    decrypblob BLOB;
    decrypraw  RAW(1000);
    decrawlen  BINARY_INTEGER;
    
    leng       INTEGER;

begin
    
    -- RAW input data 16 bytes
    srcdata := hextoraw('6D6D6D6D6D6D6D6D6D6D6D6D6D6D6D6D');
    
    dbms_output.put_line('---');
    dbms_output.put_line('input is ' || srcdata);
    dbms_output.put_line('---');
    
    -- select empty lob locators for src/enc/dec
    select loc into srcblob from table_lob where id = 1;
    select loc into encrypblob from table_lob where id = 2;
    select loc into decrypblob from table_lob where id = 3;
    
    dbms_output.put_line('Created Empty LOBS');
    dbms_output.put_line('---');
    
    leng := DBMS_LOB.GETLENGTH(srcblob);
    IF leng IS NULL THEN
        dbms_output.put_line('Source BLOB Len NULL ');
    ELSE
        dbms_output.put_line('Source BLOB Len ' || leng);
    END IF;
    
    leng := DBMS_LOB.GETLENGTH(encrypblob);
    IF leng IS NULL THEN
        dbms_output.put_line('Encrypt BLOB Len NULL ');
    ELSE
        dbms_output.put_line('Encrypt BLOB Len ' || leng);
    END IF;
    
    leng := DBMS_LOB.GETLENGTH(decrypblob);
    IF leng IS NULL THEN
        dbms_output.put_line('Decrypt  BLOB Len NULL ');
    ELSE
        dbms_output.put_line('Decrypt BLOB Len ' || leng);
    END IF;
    
    -- 3. Write source raw data into blob:
    DBMS_LOB.OPEN (srcblob, DBMS_LOB.lob_readwrite);
    DBMS_LOB.WRITEAPPEND (srcblob, 16, srcdata);
    DBMS_LOB.CLOSE (srcblob);
    
    dbms_output.put_line('Source raw data written to source blob');
    dbms_output.put_line('---');
    
    leng := DBMS_LOB.GETLENGTH(srcblob);
    IF leng IS NULL THEN
        dbms_output.put_line('source BLOB Len NULL ');
    ELSE
        dbms_output.put_line('Source BLOB Len ' || leng);
    END IF;
    
    /*
    * Procedure Encrypt
    * Arguments: srcblob -> Source BLOB
    *            encrypblob -> Output BLOB for encrypted data
    *            DBMS_CRYPTO.AES_CBC_PKCS5 -> Algo : AES
    *                                         Chaining : CBC
    *                                         Padding : PKCS5
    *            256 bit key for AES passed as RAW
    *                ->
    hextoraw('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F')
    *            IV (Initialization Vector) for AES algo passed as RAW
    *                -> hextoraw('00000000000000000000000000000000')
    */
    
    DBMS_CRYPTO.Encrypt(encrypblob,
                srcblob,
                DBMS_CRYPTO.AES_CBC_PKCS5,
                hextoraw ('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F'),
                hextoraw('00000000000000000000000000000000'));
    
    
    dbms_output.put_line('Encryption Done');
    dbms_output.put_line('---');
    
    leng := DBMS_LOB.GETLENGTH(encrypblob);
    IF leng IS NULL THEN
        dbms_output.put_line('Encrypt BLOB Len NULL');
    ELSE
        dbms_output.put_line('Encrypt BLOB Len ' || leng);
    END IF;
    
    -- 4. Read encrypblob to a raw:
    encrawlen := 999;
    
    DBMS_LOB.OPEN (encrypblob, DBMS_LOB.lob_readwrite);
    DBMS_LOB.READ (encrypblob, encrawlen, 1, encrypraw);
    DBMS_LOB.CLOSE (encrypblob);
    
    dbms_output.put_line('Read encrypt blob to a raw');
    dbms_output.put_line('---');
    
    dbms_output.put_line('Encrypted data is (256 bit key) ' || encrypraw);
    dbms_output.put_line('---');
    
    /*
    * Procedure Decrypt
    * Arguments: encrypblob -> Encrypted BLOB to decrypt
    *            decrypblob -> Output BLOB for decrypted data in RAW
    *            DBMS_CRYPTO.AES_CBC_PKCS5 -> Algo : AES
    *                                         Chaining : CBC
    *                                         Padding : PKCS5
    *            256 bit key for AES passed as RAW (same as used during Encrypt)
    *                ->
    hextoraw('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F')
    *            IV (Initialization Vector) for AES algo passed as RAW (same as
                 used during Encrypt)
    *                -> hextoraw('00000000000000000000000000000000')
    */
    
    DBMS_CRYPTO.Decrypt(decrypblob,
                encrypblob,
                DBMS_CRYPTO.AES_CBC_PKCS5,
                hextoraw
           ('000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F'),
                hextoraw('00000000000000000000000000000000'));
    
    leng := DBMS_LOB.GETLENGTH(decrypblob);
    IF leng IS NULL THEN
        dbms_output.put_line('Decrypt BLOB Len NULL');
    ELSE
        dbms_output.put_line('Decrypt BLOB Len ' || leng);
    END IF;
    
    -- Read decrypblob to a raw
    decrawlen := 999;
    
    DBMS_LOB.OPEN (decrypblob, DBMS_LOB.lob_readwrite);
    DBMS_LOB.READ (decrypblob, decrawlen, 1, decrypraw);
    DBMS_LOB.CLOSE (decrypblob);
    
    dbms_output.put_line('Decrypted data is (256 bit key) ' || decrypraw);
    dbms_output.put_line('---');
    
    DBMS_LOB.OPEN (srcblob, DBMS_LOB.lob_readwrite);
    DBMS_LOB.TRIM (srcblob, 0);
    DBMS_LOB.CLOSE (srcblob);
    
    DBMS_LOB.OPEN (encrypblob, DBMS_LOB.lob_readwrite);
    DBMS_LOB.TRIM (encrypblob, 0);
    DBMS_LOB.CLOSE (encrypblob);
    
    DBMS_LOB.OPEN (decrypblob, DBMS_LOB.lob_readwrite);
    DBMS_LOB.TRIM (decrypblob, 0);
    DBMS_LOB.CLOSE (decrypblob);
    
end;
/

truncate table table_lob;
drop table table_lob;

暗号化データのデータ・ディクショナリ・ビュー

Oracle Databaseには、暗号化されたデータに関する情報を検索できるデータ・ディクショナリ・ビューが用意されています。

表16-2に、これらのデータ・ディクショナリ・ビューを示します。

表16-2 暗号化データに関する情報を表示するデータ・ディクショナリ・ビュー

ビュー 説明

ALL_ENCRYPTED_COLUMNS

ユーザーがアクセスできるすべての表にあるすべての暗号化列の暗号化アルゴリズム情報が表示されます。

DBA_ENCRYPTED_COLUMNS

データベースにあるすべての暗号化列の暗号化アルゴリズム情報が表示されます。

USER_ENCRYPTED_COLUMNS

ユーザー・スキーマのすべての表にあるすべての暗号化列の暗号化アルゴリズム情報が表示されます。

V$ENCRYPTED_TABLESPACES

暗号化されている現在のプラガブル・データベース(PDB)表領域に関する情報が表示されます。

V$ENCRYPTION_WALLET

透過的データ暗号化のウォレットのステータスおよびウォレットの場所に関する情報が表示され、現在のPDBのみに適用されます。

V$RMAN_ENCRYPTION_ALGORITHMS

現在のPDBでサポートされている暗号化アルゴリズムが表示されます。

関連項目:

これらのビューの詳細は、Oracle Databaseリファレンスを参照してください。