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

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

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

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

このパッケージを使用することで、格納されているデータを暗号化および復号化できます。DBMS_CRYPTOのファンクションとプロシージャは、ネットワーク通信を実行するPL/SQLプログラムで使用できます。このパッケージは、Advanced Encryption Standard(AES)の暗号化アルゴリズムなど、業界標準の暗号化とハッシュ処理のアルゴリズムをサポートしています。AESは、米国標準技術局(National Institute of Standards and Technology: NIST)により、Data Encryption Standard (DES)にかわるアルゴリズムとして承認されています。

ほとんどの場合、データの暗号化にはTDEを使用する必要があります。保存データを暗号化する場合には、TDEを使用する必要があります。

DBMS_CRYPTO PL/SQLパッケージを使用した手動によるデータの暗号化には、いくつかのユースケースがあります。

  • 手動による暗号化では、データの収集時にデータを暗号化し、このデータ暗号化状態をデータベース内の他のすべてのレイヤーで維持できます。
  • 手動による暗号化は、データベース外部の別のソースで暗号化済の情報を取得する場合に役立ちます。DBMS_CRYPTOでは、データを復号化して、そのデータを暗号化されていない形式で表示するための暗号化キーを使用できます。
  • 手動による暗号化は、パスワードをハッシュして、機密性の高いデータを保護し、データ署名を使用する必要があるシナリオにも役立ちます。

手動によるデータの暗号化のデメリットは次のとおりです。

  • 索引が無意味になることや、パフォーマンスの問題が発生する可能性があります。
  • 各行を復号化することで、パフォーマンスのオーバーヘッドが発生する可能性があります。

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

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

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

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

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

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

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

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

19.2.2 原則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を使用して調整することもできます。

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

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

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

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

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

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

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

19.3 データ暗号化の課題

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

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

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

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

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

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

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

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

19.3.2 生成された暗号化キー

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

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

ノート:

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

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

19.3.3 転送された暗号化キー

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

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

19.3.4 暗号化キーの格納

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

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

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

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

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

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

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

簡単な例として、従業員データを含む表(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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

DBMS_CRYPTOパッケージを使用すると、格納されたデータを手動で暗号化および復号化できるようになります。

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

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などの複数のパディング・オプションと、Galois/Counter Mode (GCM)などの4つのブロック暗号連鎖モードから選択できます。パディングは8バイトの倍数で実行する必要があります。

ノート:

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

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

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

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

    この非推奨の結果、非推奨のアルゴリズムの使用が指定されているかどうかを確認するために、ネットワーク暗号化構成を確認することをお薦めします。いずれかが見つかった場合は、AESなどの最新の暗号の使用に切り替えます。詳細は、「ネイティブ・ネットワーク暗号化のセキュリティの向上」を参照してください。

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

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

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

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

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

ブロック暗号連鎖モード

CBC、CCM、CFB、ECB、GCM、OFB

暗号化アルゴリズム

AES、DES (非推奨)、3DES (非推奨)、PBE_MD5DES (非推奨)、3DES_2KEY (非推奨)

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

SHA-1 (非推奨)、SHA-2、HASH_SH256、HASH_SH384、HASH_SH512

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

RAWNUMBERBINARY_INTEGER

データベース型

RAWCLOBBLOB

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

HMAC_MD5、HMAC_SH1、HMAC_SH256、HMAC_SH384、HMAC_SH512

パディング形式

PKCS5、複数ゼロ

表19-2に、サポートされているSHAハッシュ関数を示します。これらの関数の多くはRSA環境で使用できます。

表19-2 SHAハッシュ・アルゴリズム

ハッシュ・アルゴリズム 説明
SIGN_SHA1_RSA

RSAを使用するSHAハッシュ関数

SIGN_SHA1_RSA_X931

RSAおよびX931パディングを使用するSHAハッシュ関数

SIGN_SHA224_ECDSA

楕円曲線デジタル署名アルゴリズムを使用するSHA 224ビット・ハッシュ関数

SIGN_SHA224_RSA

RSAを使用するSHA 224ビット・ハッシュ関数

SIGN_SHA256_ECDSA

楕円曲線デジタル署名アルゴリズムを使用するSHA 256ビット・ハッシュ関数

SIGN_SHA256_RSA

RSAを使用するSHA 256ビット・ハッシュ関数

SIGN_SHA256_RSA_X931

RSAおよびX931パディングを使用するSHA 256ビット・ハッシュ関数

SIGN_SHA384_ECDSA

楕円曲線デジタル署名アルゴリズムを使用するSHA 384ビット・ハッシュ関数

SIGN_SHA384_RSA

RSAを使用するSHA 384ビット・ハッシュ関数

SIGN_SHA384_RSA_X931

RSAおよびX931パディングを使用するSHA 384ビット・ハッシュ関数

SIGN_SHA512_ECDSA

楕円曲線デジタル署名アルゴリズムを使用するSHA 512ビット・ハッシュ関数

SIGN_SHA512_RSA

RSAを使用するSHA 384ビット・ハッシュ関数

SIGN_SHA512_RSA_X931

RSAおよびX931パディングを使用するSHA 384ビット・ハッシュ関数

表19-3に、サポートされる暗号化および復号化アルゴリズムを示します。

表19-3 暗号化および復号化アルゴリズム

アルゴリズム 説明
PKENCRYPT_RSA_PKCS1_OAEP (非推奨)

PKCS1およびOAEPパディングを使用するRSA公開キー暗号システム

PKENCRYPT_RSA_PKCS1_OAEP_SHA2

SHA2とともにPKCS1およびOAEPパディングを使用するRSA公開キー暗号システム

表19-4に、サポートされているその他のアルゴリズムを示します。

表19-4 その他のアルゴリズム

アルゴリズム 説明
KEY_TYPE_RSA

RSAキーのタイプ

SIGN_ECDSA

楕円曲線デジタル署名アルゴリズム

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

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

ノート:

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

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

19.5 DBMS_CRYPTOパッケージを使用した非対称キー操作

DBMS_CRYPTOパッケージには、暗号化、復号化、署名および検証のための非対称キー操作を実行できる4つのファンクションが用意されています。

非対称キー操作(公開キー暗号化とも呼ばれる)では、公開キーと秘密キーを使用してメッセージを暗号化および復号化し、不正アクセスから保護します。

非対称キー操作ファンクションは次のとおりです。

  • PKDECRYPTは、キー・アルゴリズムおよび暗号化アルゴリズムで支援される秘密キーを使用してRAWデータを復号化します。
  • PKENCRYPTは、キー・アルゴリズムおよび暗号化アルゴリズムで支援される公開キーを使用してRAWデータを暗号化します。
  • SIGNは、キー・アルゴリズムおよび署名アルゴリズムで支援された秘密キーを使用してRAWデータに署名します。
  • VERIFYは、署名、キー・アルゴリズムおよび署名アルゴリズムで支援される公開キーを使用してRAWデータを検証します。

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

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

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

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

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

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

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

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

  • MD5アルゴリズムを使用したキー依存の一方向ハッシュであるMACの計算方法を示します。(Oracle Databaseリリース21c以降では、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(16)  := 'scottscoscottsco';
    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.AES_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.AES_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;
/

19.6.2 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;

19.6.3 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;

19.6.4 例: 数値文字列の暗号化または復号化

DBMS_CRYPTO PL/SQLパッケージを使用して、数値文字列を手動で暗号化または復号化する関数を作成できます。

次の手順では、関数を作成して使用し、数値文字列を暗号化および復号化する方法を示します。また、変換された数値文字列を表に挿入して、関数の動作をテストする例も示します。
  1. 数値文字列を暗号化する関数を作成します。
    次の関数f_encrypt_numberの例は、入力値number_in、戻り値をRAWタイプとして使用し、DES_CBC_PKCS5を暗号化アルゴリズムとして使用します。
    CREATE OR REPLACE FUNCTION f_encrypt_number(number_in IN NUMBER) 
     RETURN RAW IS
      number_in_raw RAW(128):=UTL_I18N.STRING_TO_RAW(number_in,'AL32UTF8');
      key_number number(32):=32432432343243279898;
      key_raw RAW(128):=UTL_RAW.cast_from_number(key_number);
      encrypted_raw RAW(128);
    BEGIN
      encrypted_raw:=DBMS_CRYPTO.ENCRYPT(src=>number_in_raw,typ=>DBMS_CRYPTO.DES_CBC_PKCS5,key=>key_raw);  
      RETURN encrypted_raw;
    END;
    /
  2. 関数f_encrypt_numberを実行して、数値文字列2を暗号化します。
    SELECT f_encrypt_number('2') FROM DUAL;

    この例では、84A8B8D7D8925582になります。

    F_ENCRYPT_NUMBER('2')
    --------------------------------------------------------------------------------
    84A8B8D7D8925582
  3. 数値文字列を復号化する関数を作成します。
    次の関数f_decrypt_numberの例では、暗号化されたRAW値encrypted_rawを復号化できます。入力はencrypted_rawです。復号化アルゴリズムとしてDES_CBC_PKCS5を使用します
    CREATE OR REPLACE FUNCTION f_decrypt_number (encrypted_raw IN RAW)
     RETURN NUMBER IS
      decrypted_raw raw(48);
      key_number number(32):=32432432343243279898;
      key_raw RAW(128):=UTL_RAW.cast_from_number(key_number);
    BEGIN
      decrypted_raw := DBMS_CRYPTO.DECRYPT
          (
             src => encrypted_raw,
             typ => DBMS_CRYPTO.DES_CBC_PKCS5,
             key => key_raw
          );
    RETURN   UTL_I18N.RAW_TO_CHAR (decrypted_raw, 'AL32UTF8');
    END;
    /
  4. f_decrypt_number関数を実行して84A8B8D7D8925582を復号化します。
    :
    SELECT f_decrypt_number('84A8B8D7D8925582') FROM DUAL;

    結果は次のとおりです 2:

    
    F_DECRYPT_NUMBER('84A8B8D7D8925582')
    ------------------------------------
                                       2
  5. 暗号化された番号文字列をテストします。
    このテストでは、f_encrypt_numberを実行して番号2を暗号化します。(結果は84A8B8D7D8925582になります)。次に、表test_dbms_cryptoに(f_encrypt_number('2')username)を挿入します。表に挿入された84A8B8D7D8925582 usernameを確認できます。f_encrypt_numberを実行してID 84A8B8D7D8925582を復号化すると、結果は2になります。
    1. 暗号化された番号文字列をtest_dbms_crypto表に挿入します。
      INSERT INTO test_dbms_crypto VALUES (f_encrypt_number('2'),'username');
      1 row created.
      COMMIT;
      Commit complete.
    2. test_dbms_crypto表から選択します。
      SELECT * FROM test_dbms_crypto;

      次の出力が表示されます。

      ID                             NAME
      --------------------------     --------------------
      84A8B8D7D8925582               username
    3. test_dbms_crypto表から選択します。
      SELECT f_decrypt_number(id), NAME FROM test_dbms_crypto ;

      次の出力が表示されます。

      F_DECRYPT_NUMBER(ID) NAME
      -------------------- --------------------
                         2 username