RPG、DB2 for i、Web での AES 暗号化に関するQ&A
こんにちは FHG:
暗号化は使ったことがないのですが、IBM i 7.1 システムで暗号化を使うように、新しいマネージャーから求められています。(例えば、我々の Web サイト・メンバーのパスワードを保管しています。) 自分の RPG プログラムで、 ENCRYPT_AES および DECRYPT_CHAR SQL 関数を使っています。ところが、AES 暗号化に関して、PHP プログラマーが、初期設定ベクトルを生成して、説明のため後で保存する方法について尋ねています。正しく指南くださいませんか?最後に、我々のマネージャーは、RPG ソース・コードで暗号化キーが非暗号化テキストになっている点を好ましく思っていません。その点、どう考えますか?
--匿名希望
親愛なる読者様へ
暗号化を真剣にとらえ、DB2 for i で提供される便利な関数を使って AES を使用したデータを暗号化したり、復号したりすると聞いて嬉しく思います。また、PHP の同僚が初期設定ベクトルの生成について質問していますが、これは単なる用語の違いであることがわかります。少し説明します。
しかし、最初に AES (Advanced Encryption Standard 別名「Rijndael」) についてあまり知らない人向けに、このトピックのウィキペディア・ページを見せたいと思います。
DB2 for i で AES 暗号化を使う場合、単に暗号化するテキスト・データまたはバイナリー・データ (Web サイトのパスワード、社会保障番号、クレジットカード番号など) と暗号化に使うパスワードだけで、高度な知識は必要ありません。以下のように簡単です。
ENCRYPT_AES(暗号化する文字列、暗号化パスワード)
関数はバイナリー・データを戻します。この例では、ユーザー「Joe Cool」のパスワード (UserPassword) は、 AES 暗号化で暗号化されており、暗号化パスワード値があります。EncryptionPassword
ENCRYPT_AES 関数で戻される難解な表現は、 VARBINARY、VARCHAR FOR BIT DATA、または BLOB のいずれかになります。暗号化データのデータ型により異なります。戻されたデータの長さは、暗号化中のデータの長さとパスワード長により異なります。
データは、 DECRYPT_CHAR 関数を使って元の文字形式に復号できます (暗号化パスワードがわかっている場合)。この例では、 DECRYPT_CHAR 関数は、最初にデータを暗号化したときに使用した同じ暗号化パスワードを使用して、暗号化された Web サイトのパスワードを復号しています。
当然、ユーザー名とパスワードには、リテラルではなく、変数にするのが普通です。また、絶対必要でない限り、暗号化データを復号することは一般的にはありません。私なら、こうしたコードを作成するときは、保存されたパスワードを復号して、ユーザーの入力内容と比較するよりも、ユーザーの入力内容を暗号化して、それを保存された暗号化値と比較します。
パスワードは、データ保護という点で、暗号化プロセスの重要な部分です。パスワードが必要ない場合、データの復号のためハッカーがしなければならないことは、どの暗号化アルゴリズムでデータが暗号化されているか見極めることです。しかし、パスワードを暗号化プロセスの開始点として使う場合、2 つの異なるシステムが (AES など) 同じアルゴリズムを使って同じデータを暗号化できますが、異なる暗号化パスワードを使うと暗号化の結果も異なります。
また、文字データではなくバイナリーを暗号化している場合、DECRYPT_CHAR ではなく DECRYPT_BINARY 関数を使います。
記録のため、パスワードをどうしても保存しなければならない理由がない限り、しばしば暗号化パスワードではなくパスワードのハッシュを保存することをお勧めします。理由は、データが盗まれた場合、ハッカーは盗んだパスワードで復号する場合があるためです。
初期設定ベクトル (IV) の質問についてはどうでしょうか?IV は DB2 暗号化パスワードの類似語です。IV は、データが暗号化され、また復号に必要な場合にプロセスを始めるための種です。
IV の生成は、暗号化パスワードの生成と似ています。これをするかどうかはあなた次第です。すべての暗号化データが DB2 に含まれており、あらゆるアプリケーションが DB2 関数を介して復号データにアクセスする必要がある場合、パスワードを 1 つ使うことができます。しかし、暗号化データに複数のパスワードを使いたい場合があります。例えば、多くの顧客の暗号化データを保存する場合、各顧客が自分独自に生成した暗号化パスワードを持つようにしたいでしょう。複数のIV (つまり、複数のパスワード) を生成する場合、IV と保護に使ったデータの相互参照を維持しなければならない点が問題になります。
生成された IV のある AES 暗号化を使って RPG プログラムの例を見てみると、IBM は、qc3crtax API を使って AES 暗号化を実行する、純粋な RPG の例を公開しました。暗号化された顧客にはそれぞれ、自分の初期設定ベクトルが与えられます (同じコードの変数 QC3IV を参照してください。IV は API Qc3GenPRN で生成されます)。サンプル・コードはここにあります。
例からわかるように、DB2 for i 関数ははるかに簡単に使うことができます。
PHP の同僚が、DB2 for i 関数を使った RPG プログラムを使って、すべての暗号化を処理するのは素晴らしいです。しかし、PHPアプリケーションの暗号化パスワードにアクセスできる場合、開発者は、 PHP ライブラリーを使って AES 暗号化を実行することができます。ENCRYPT_AES 関数への入力が UTF-8 (CCSID 1208) として提供され、出力が UTF-8 である限り、PHP 暗号化は、 DB2 for i 暗号化と互換性があります。そうでない場合は、RPG プログラムは EBCDIC パスワードを使って、 EBCDIC データを暗号化することになります。これにより PHP と互換性がなくなります。幸い、DB2 は文字パラメーターを CCSID 1208 としてタグ付けすることで、EBCDIC/UTF8 変換を自動処理できます。
PHP 開発者がローカルに暗号化をコーディングできるという利点により、アプリケーションがデータベース・サーバーを呼び出すことがなくなり、また暗号化されていないトラフィックが、ネットワーク間を移動しなくなります。欠点は、 PHP 開発者 (またはアプリケーション自体) が暗号化データのパスワードにアクセスしなければならないことです。
ソース・コード内にある非暗号化パスワードの問題については、自分を守るためにもう少し努力が必要でしょう。過去に私は、データ域またはデータ・テーブルを使ってパスワードを保存したことがあります。この場合、ハッカーとしては、求めているものを得るにはもう少し手順を踏む必要があるだけでしょうが、ポイントは、その方がソース・コードを眺めているより難しいということです。願わくば、IBM i/DB2 オブジェクト・セキュリティーの余分な障害物により、ハッカーがパスワードを取得できないことを祈ります。
そうやってパスワードを保存する場合、全ビットに対して単純な排他的論理和 (XOR) のような何らかのエンコードにより、パスワードをバイナリー・フィールドとして保存することができます。パスワードの取得は、テキストを読み取ったり、データベースからバイナリー値を抽出したりするほど簡単ではありません。途中で入れることができるあらゆる頭痛の種は、あなたのデータを狙っている人への抑止力となります。
最後に、DB2 暗号化関数の使用には多くの意味合いがあります。SQL リファレンス・ガイドにある暗号化関数とステートメントをじっくりお読みください。開発者はパスワードのヒントを指定したり、SET ENCRYPTION PASSWORD ステートメントでデフォルト・パスワードを設定したりできます。