1. ホーム
  2. php

[解決済み] openssl_encryptにおける初期化ベクトルの使用について

2023-06-21 21:07:32

質問

私は この の質問を見て、自分でもやってみたくなりました。私はこのコード(から直接取られた)を実行したとき この答え ):

$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

そこで、私は ドキュメント を見てみましたが、「ドキュメントがない」のです。そこで、次のようなものを見つけました。 コメント を見つけましたが、初期化ベクターがどうあるべきか、それをどう使うべきかについては、まだ言及されていません。どなたか教えていただけませんか?

私はもっとググることができたと思いますが、Stackoverflow は多くの検索結果で最初に出てくるので、この質問はこの問題を抱えている他の誰かにとって有用であるかもしれないと思いました。

どのように解決するのですか?

IVとは一般に、暗号化されたテキストがユニークであることを保証する乱数のことです。

なぜそれが必要なのかを説明するために、「secret」という鍵で暗号化された人名のデータベースがあり、IVがない場合を想定してみましょう。

1 John dsfa9p8y098hasdf
2 Paul po43pokdfgpo3k4y
3 John dsfa9p8y098hasdf

もしJohn 1が自分の暗号文(dsfa9p8y098hasdf)を知っていて、他の暗号文にアクセスできれば、Johnという名前の他の人たちを簡単に見つけることができます。

さて、実際には、IV を必要とする暗号化モードでは、常に IV を使用します。IV を指定しない場合、IV は自動的に null バイトの束に設定されます。最初の例で、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つの「John」暗号文は異なるものになりました。それぞれのIVはユニークで、暗号化処理に影響を与え、最終結果もユニークになります。John 1は現在、ユーザー3の名前が何であるかわかりません。

復号化には、もちろんテキストが暗号化されたのと同じ 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