質問: '1234567890123456'; var_dump(openssl_encrypt('1486601281','AES-256-CBC','aaatest',0,$iv)); var_dump(unpack("H*", openssl_encrypt('1486601281','AES-256-CBC','aaatest',0,$iv))); 結果 string(24) "V3zbf8fVlSc32J/+76vpNg==" array(1) { [1]=> string(48) "56337a62663866566c536333324a2f2b373676704e673d3d" } ```
回答: 質問者さんの提示したコードでは暗号方式に`AES-256-CBC`が指定されていますから、暗号化のたびにランダムな初期化ベクタ (IV) を指定しなければなりません。ですから、平文が一意であっても暗号文は一意になりません。 以下、説明です。 * 初期化ベクタ (IV) やソルトを使わない暗号方式では、平文と暗号文が一対一に対応します。ブロック暗号では、ECBモードの場合はIVを使いません。 しかし、**このような暗号方式はもはや用いるべきではありません**。 * 初期化ベクタ (IV) やナンス (nonce) を使う暗号方式は、IVやナンスを暗号化の度に変えるという正しい運用をするかぎり、同じ平文が同じ暗号文になることはほぼありません。ブロック暗号では、ECB以外のモードではIVを用いる (CBC、CFB、OFB等) かナンスを用いる (CTR等) かです。 そして、**IVやナンスに固定した値を用いるべきではありません**。 IVを使わない暗号方式を使うことも、IVを固定して使うことも、するべきでない理由は同じです。そのようなものは、現在では十分な強度のある暗号方式とみなされていないからです。 「でも、IVを固定すれば一意になるんでしょう。ならそういう使いかたをしたっていいじゃないか」と思うかもしれません。しかし、暗号方式の設計で想定されている以外の運用をすれば、暗号化の強度は全く保証できなくなります。**暗号化しているつもりで安心していると、すべて誰かに解読されてしまっているかもしれない**のです。これほど危険なことはありません。 参考文献 * 結城浩『暗号技術入門 第3版』SBクリエイティブ, 2015. 第4章「ブロック暗号のモード」. ところで、質問者さんのやりたいことが何なのか、いまひとつわかりません。 一意な文字列を作りたいのであれば、規則的に変化するもの (連番など) でいいはずです。規則性のない文字列にしたいのであれば、乱数を使うしかありません。両立は無理です。 また、やりたいことがわからないので憶測ですが、文字列を予測困難にする――次に生成される文字列を隠す――必要があるのかどうかも、再考すべきなのかもしれません。