log

日記です

pythonとphpで相互に暗号化/復号化を行う

pythonで `Simple-AES-Cipher` を使って暗号化された文字列を復号化する。

`Simple-AES-Cipher` を使った場合デフォルトの暗号化方式はaes-256-cbcで、initialization vectorにランダムの文字列が使われる。
返り値はinitialization vector + 暗号化された文字列のbase64となる。

phpでは以下の手順をふみ、復号化する。

  • base64デコード
  • initialization vectorと暗号化を分ける。
  • openssl_decryptにそれぞれのパラメーターを渡す

以下テストコード。

'12345678901234567890123456789012' を共通で使用するkeyとする。

python で "php man" を暗号化

from simple_aes_cipher import AESCipher

cipher = AESCipher('12345678901234567890123456789012')
cipher.encrypt('php man')
# 0DbgJCpQDDvH8vNs1teJWaSk3U7mGsEdnA/mfg3r0bw=

php で "php man" に復号化

<?php
$key = "12345678901234567890123456789012";

$encrypted_by_python = '0DbgJCpQDDvH8vNs1teJWaSk3U7mGsEdnA/mfg3r0bw=';

$decoded = base64_decode($encrypted_by_python);
$iv = substr($decoded, 0, 16);
$encrypted = substr($decoded, 16);

$encrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $key, true, $iv);
// php man

無事OK。

vi(initialization vector)ってなんだ

initialization vectorはECBモードの脆弱さをなくすために作られたらしい。

CBC暗号モードの初期値は、敵から見えてもかまわないことになっていますが、毎回違う値を利用することが推奨されています。

ふーむ。

ブロック暗号モード(block cipher mode)

CBCモードでは、前の平文ブロックを暗号化した結果を次の平文に XOR 演算によって重ね合わせ、その結果に対して暗号化処理を行います。

なるほど。ECBモードに存在した、

  • 同じ鍵で暗号化したデータは同じ暗号文になるため、元の平文データを推測しやすい。仮にphp manの暗号文がxxx だった場合、xxxという暗号文はphp manという事がわかってしまう。
  • 改ざん検知機能がない

っていうのを改善しているわけだ。改ざん検知機能は不産物感あるな。