Mcrypt が使えなくて困った

すでに数年前の話なのですが、Laravel の古いバージョンで実装したけれどそのまま放置気味だった Web アプリケーションを改修しようとしたところ、暗号化・復号でトラブルがあったというログです。

過去、 PHP では暗号化・復号ライブラリとして Mcrypt を使用しており、 Laravel でもこのライブラリに依存した実装がありました。 稼働実績のあるその Web アプリケーションでは Mcrypt で暗号化したデータがデータベースに大量保存されています。

この Mcrypt は⻑期間メンテナンスいなかったため、 PHP 7.2 で削除されました。 Mcrypt に変わるものが OpenSSL ですが、 McryptOpenSSL は単純に置き換えができなく、泣きつかれた感じです。

結論としては、互換性があるので OK です。

暗号化結果の⽐較

Mcrypt で暗号化

リプレイス前に動作していたものと同等のコードです。

1// 暗号化するデータ
2$plaintext = 'dummy_text';
3// シークレットキー
4$key = 'dummy_secret_key';
5
6$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $plaintext, MCRYPT_MODE_ECB);
7$ciphertext_base64 = base64_encode($ciphertext);
8
9echo $ciphertext_base64; // dD2hL+qY2lG60wM7vQW0fQ==

OpenSSL で暗号化

リプレイス後のコードです。

 1// 暗号化するデータ
 2$plaintext = 'dummy_text';
 3// シークレットキー
 4$key = 'dummy_secret_key';
 5// 同等の暗号メソッド
 6$cipher = "aes-128-ecb";
 7
 8$ciphertext = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA);
 9$ciphertext_base64 = base64_encode($ciphertext);
10
11echo $ciphertext_base64; // srIFQhnoDAIgRJOefeES4Q==

暗号化メソッドは同等にしていますが、暗号化で得られる文字列の結果が違っています。

復号する

しかし、すでに述べている通り、結果は違いますが復号は可能です。

Mcrypt で復号する

mcrypt_encrypt() で暗号化したものは、対応する mcrypt_decrypt() なら当然復号できます。

1// 暗号化済み文字列
2$ciphertext_base64 = 'dD2hL+qY2lG60wM7vQW0fQ==';
3// シークレットキー
4$key = 'dummy_secret_key';
5
6$ciphertext_dec = base64_decode($ciphertext_base64);
7$plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $ciphertext_dec, MCRYPT_MODE_ECB);
8
9echo $plaintext_dec; // dummy_text

復号できることが確認できました。

なお、 OpenSSL で暗号化したものを、上のコードで復号もできます。 ただし OPENSSL_ZERO_PADDING をオプション指定しないと失敗します。

OpenSSL で復号する

では Mcrypt で暗号化したものを OpenSSL で復号します。

 1// 暗号化済み文字列
 2$ciphertext_base64 = 'dD2hL+qY2lG60wM7vQW0fQ==';
 3// シークレットキー
 4$key = 'dummy_secret_key';
 5// 同等の暗号メソッド
 6$cipher = "aes-128-ecb";
 7
 8$ciphertext_dec = base64_decode($ciphertext_base64);
 9$plaintext_dec = openssl_decrypt($ciphertext_dec, $cipher, $key, OPENSSL_RAW_DATA);
10
11echo $plaintext_dec; // dummy_text

おお、復号できました。
OK ですね。

最初⼀瞬⾎の気が引いたのですが、互換性があって問題なくやり取りできるよ、ということのログでした。