仕事がらみで必要に迫られたのでちょっと調査してみました。
Perlの Crypt::CBC と PHPの mcrypt_encrypt では多少の処理ロジックに差異があります。
その解決方法を探ってみましょう。
Perl Crypt::CBC で暗号化してみる
$ cat 1.pl
use Crypt::CBC;
use MIME::Base64;
my $key = 'be497e4272bae86d1c729e5c2a85fe65';
my $iv = '460e2f651ca61161';
my $text = 'hogehoge';
my $cipher = Crypt::CBC->new({
key => $key,
cipher => 'Crypt::Rijndael',
iv => $iv,
header => 'none',
});
my $crypted = $cipher->encrypt($text);
print encode_base64($crypted);
$
$ perl 1.pl
fazwxd6I4GS/UnKUsG7kYg==
$ cat 2.php
<?
$key = 'be497e4272bae86d1c729e5c2a85fe65';
$iv = '460e2f651ca61161';
$text = 'hogehoge';
$crypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
echo base64_encode($crypted)."\n";
?>
$
$ php 2.php
1bwpbx18QSv9TpHi5cZFXg==
これは、Crypt::CBC の内部処理では、mcrypt_encrypt では行われない処理が2つあるためです。
- 指定している暗号化モードのブロックサイズに暗号化対象のテキストをPKCS#5パディングする
- 指定している暗号化モードのキーサイズに暗号化キーをmd5ハッシュ化する
$ cat 1.pl
use Crypt::CBC;
use MIME::Base64;
my $key = 'be497e4272bae86d1c729e5c2a85fe65';
my $iv = '460e2f651ca61161';
my $text = 'hogehoge';
my $cipher = Crypt::CBC->new({
key => $key,
cipher => 'Crypt::Rijndael',
iv => $iv,
header => 'none',
});
print "keysize: ".$cipher->keysize()."\n";
print "blocksize: ".$cipher->blocksize()."\n";
$
$ perl 1.pl
keysize: 32
blocksize: 16
この1.と2.の処理をPHPでは自分で実装する必要があります。
1.テキストの パディング
function pkcs5_pad( $text, $blocksize ) {
$pad = $blocksize - ( strlen( $text ) % $blocksize );
return $text . str_repeat( chr( $pad ), $pad );
}
2.暗号化キーのハッシュ化
function key_hash( $key, $keysize )
{
$key = md5( $key, true);
while( strlen( $key ) < $keysize ) {
$key .= md5( $key, true);
}
return substr( $key, 0, $keysize);
}
で、これができあがったPHPの実装コードサンプルです。
$ cat 2.php
<?
$key = 'be497e4272bae86d1c729e5c2a85fe65';
$iv = '460e2f651ca61161';
$text = 'hogehoge';
$keysize = 32;
$blocksize = 16;
$padding_text = pkcs5_pad( $text, $blocksize );
$hashed_key = key_hash( $key, $keysize );
$crypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $hashed_key, $padding_text, MCRYPT_MODE_CBC, $iv);
echo base64_encode($crypted)."\n";
function pkcs5_pad( $text, $blocksize ) {
$pad = $blocksize - ( strlen( $text ) % $blocksize );
return $text . str_repeat( chr( $pad ), $pad );
}
function key_hash( $key, $keysize )
{
$key = md5( $key, true);
while( strlen( $key ) < $keysize ) {
$key .= md5( $key, true);
}
return substr( $key, 0, $keysize);
}
?>
$
$ php 2.php
fazwxd6I4GS/UnKUsG7kYg==
これで、Perlの Crypt::CBC と PHPの mcrypt_encrypt で暗号化・復号化のやりとが可能になります。
ちなみに、Perlの Crypt::CBC側で、literal_key => 1 の設定を追加すれば、PHPでは、2.の暗号化キーのハッシュ化の実装が不要になります。
$ cat 1.pl
use Crypt::CBC;
use MIME::Base64;
my $key = 'be497e4272bae86d1c729e5c2a85fe65';
my $iv = '460e2f651ca61161';
my $text = 'hogehoge';
my $cipher = Crypt::CBC->new({
key => $key,
cipher => 'Crypt::Rijndael',
iv => $iv,
header => 'none',
literal_key => 1,
});
my $crypted = $cipher->encrypt($text);
print encode_base64($crypted);
$
$ perl 1.pl
4yb1njYe2Ftxt2P+08tNzA==
$ cat 2.php
<?
$key = 'be497e4272bae86d1c729e5c2a85fe65';
$iv = '460e2f651ca61161';
$text = 'hogehoge';
$keysize = 32;
$blocksize = 16;
$padding_text = pkcs5_pad( $text, $blocksize );
// $hashed_key = key_hash( $key, $keysize );
$crypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $padding_text, MCRYPT_MODE_CBC, $iv);
echo base64_encode($crypted)."\n";
function pkcs5_pad( $text, $blocksize ) {
$pad = $blocksize - ( strlen( $text ) % $blocksize );
return $text . str_repeat( chr( $pad ), $pad );
}
function key_hash( $key, $keysize )
{
$key = md5( $key, true);
while( strlen( $key ) < $keysize ) {
$key .= md5( $key, true);
}
return substr( $key, 0, $keysize);
}
?>
$
$ php 2.php
4yb1njYe2Ftxt2P+08tNzA==
おしまい。