web-dev-qa-db-ja.com

openssl_encryptでの初期化ベクトルの使用

this の質問を見て、自分でやりたいと思った。このコードを実行したとき( this answer から直接取得):

$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";  // AES is used by the U.S. gov't to encrypt top secret documents.
$secretHash = "25c6c7ff35b9979b151f2136cd13b0ff";

//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, '1234567812345678');

//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);

//Result
echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";

ただし、警告が表示されます

openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended

そこで私は行って、 docs を見てみましたが、「ドキュメントはありません」。私はこれを見つけました コメント 、それでも初期化ベクトルがどうあるべきか、そしてそれをどのように使うべきかについての言及はありません。誰でも私を啓発できますか?

もう少しグーグルでやることができたのは知っていますが、Stackoverflowは非常に多くの検索結果で最初に表示されます。

68
Alfo

IVは通常、暗号化されたテキストが一意であることを保証する乱数です。

なぜそれが必要なのかを説明するために、キー「secret」で暗号化され、IVで暗号化されていない人々の名前のデータベースがあるとします。

1 John dsfa9p8y098hasdf
2 Paul po43pokdfgpo3k4y
3 John dsfa9p8y098hasdf

John 1が自分の暗号テキスト(dsfa9p8y098hasdf)を知っていて、他の暗号テキストにアクセスできる場合、Johnという名前の他の人を簡単に見つけることができます。

現在、実際には、IVを必要とする暗号化モードでは常に使用されます。 IVを指定しない場合、IVは一連のヌルバイトに自動的に設定されます。最初の例を想像してください。ただし、定数IV(00000000)を使用します。

1 John dsfa9p8y098hasdf 00000000
2 Paul po43pokdfgpo3k4y 00000000
3 John dsfa9p8y098hasdf 00000000

暗号テキストの繰り返しを防ぐために、同じ「秘密」キーとランダムIVを使用して名前を暗号化できます。

1 John sdf875n90mh28458 45gh3546
2 Paul fg9087n5b60987nf 56897ngq
3 John gjhn0m89456vnler 8907345f

ご覧のとおり、2つの「ジョン」暗号テキストが異なっています。各IVは一意であり、暗号化プロセスに影響を与え、最終結果も一意になります。ジョン1は、ユーザー3の名前が何であるかわかりません。

復号化には、もちろんテキストと同じIVを使用する必要があります。そのため、データベースに保存する必要があります。 IVはキーなしでは役に立たないので、暗号化されたテキストでIVを送信または保存することは関係ありません。

これは過度に単純化した例ですが、実際には、IVを使用しないと深刻なセキュリティ上の影響があります。


これで、コードはIV(1234567812345678)を設定しているように見えますが、復号化には使用していません。失敗することは確かです。

PHPのIV生成関数の一部を利用することもできます。私はこれがあなたのために働くはずだと思う:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_Rand);
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, 0, $iv);
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash, 0, $iv);

ストレージ/送信では、IVと暗号化テキストを次のように単純に連結できます。

$data = $iv.$encryptedMessage;

次に、取得時に、復号化のためにIVを引き出します。

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($data, 0, $iv_size);
$decryptedMessage = openssl_decrypt(substr($data, $iv_size), $encryptionMethod, $secretHash, 0, $iv);

詳細については、PHPのMcryptライブラリをご覧ください。それは非常に完全な機能を備えており、多くの例があります。その多くは、openssh暗号化の実装に役立ちます。 http://php.net/manual/en/function.mcrypt-encrypt.php

119
Joel Mellon