如何使Ruby的AES-256-CBC和PHP MCRYPT_RIJNDAEL_128配合默契
题
我生成要发送的数据从一个Ruby堆栈的PHP堆栈。我使用Ruby端和PHP的“的mcrypt”库OpenSSL的::密码库。当我加密使用“AES-256-CBC”(256位的块大小)的红宝石我需要使用在PHP MCRYPT_RIJNDAEL_128(128位块大小)进行解密。我怀疑Ruby代码被打破,因为cipher.iv_len为16;我相信它应为32:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
=> #<OpenSSL::Cipher::Cipher:0x3067c5c>
>> cipher.key_len
=> 16
>> cipher.iv_len
=> 16
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
=> #<OpenSSL::Cipher::Cipher:0x306de18>
>> cipher.key_len
=> 32
>> cipher.iv_len
=> 16
因此,这里是我的测试。在Ruby侧,第一I生成密钥和IV:
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
>> cipher.encrypt
>> iv = cipher.random_iv
>> iv64 = [iv].pack("m").strip
=> "vCkaypm5tPmtP3TF7aWrug=="
>> key = cipher.random_key
>> key64 = [key].pack("m").strip
=> "RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0="
然后,我使用这些密钥执行加密:
>> plain_data = "Hi, Don, this is a string."
>> cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
>> cipher.encrypt
>> cipher.key = Base64.decode64(key64)
>> cipher.iv = Base64.decode64(iv64)
>> encrypted_data = cipher.update(plain_data)
>> encrypted_data << cipher.final
>> crypt64 = [encrypted_data].pack("m").strip
=> "5gfC/kJcnAV2fJI0haxnLcdraIKWgtu54UoznVxf8K0="
这里的PHP解密:
$ruby_crypt = "5gfC/kJcnAV2fJI0haxnLcdraIKWgtu54UoznVxf8K0=";
$encrypted_data = base64_decode($ruby_crypt);
$key = base64_decode("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=");
$iv = base64_decode("vCkaypm5tPmtP3TF7aWrug==");
$result = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $encrypted_data, MCRYPT_MODE_CBC, $iv);
$unencrypt = rtrim($result, "\x00..\x1F");
print "\nUnencrypted token:\n'$unencrypt'\n";
RESULT:
Unencrypted token:
'Hi, Don, this is a string.'
我宁愿使用较长的块大小。显然我误解的API。帮助
解决方案
我不知道PHP,而是通过侧栏上的相关问题读书,我看到的转换红宝石AES256解密功能,PHP 。这包括参照此页面,指出在MCRYPT_RIJNDAEL_128
128指的加密块的大小,而不是密钥大小。你会发现,你已经Ruby和PHP之间传递的密钥长度是在两种情况下256位。换句话说,这似乎是预期的行为,并且您已经使用了较大的密钥。
#!/usr/bin/ruby
require 'base64'
puts((Base64.decode64("RIvFgoi9xZaHS/0Bp0J9WDRyND6Z7jrd3btiAfcQ8Y0=").length * 8).to_s)
HTH
其他提示
我写一个例子别人可能发现上述讨论的说明:
$猫publisher.rb
#!/usr/bin/env ruby
require 'openssl'
require 'base64'
key = '7fc4d85e2e4193b842bb0541de51a497'
cipher = OpenSSL::Cipher::Cipher.new('aes-128-cbc')
cipher.encrypt()
iv = cipher.random_iv
cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
cipher.encrypt()
cipher.key = key
cipher.iv = iv
crypt = cipher.update('This is my text')
crypt << cipher.final()
puts [Base64.encode64(crypt).strip(), Base64.encode64(iv).strip()].join('|')
$猫consumer.php
$key256 = '7fc4d85e2e4193b842bb0541de51a497';
$fd = fopen("php://stdin", "r");
$tokens = '';
while (!feof($fd))
$tokens .= fread($fd, 1024);
fclose($fd);
$tokens = explode('|', trim($tokens));
$crypt = $tokens[0];
$iv = $tokens[1];
$crypttext = base64_decode($crypt);
$iv = base64_decode($iv);
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key256, $crypttext, MCRYPT_MODE_CBC, $iv);
print $decrypted ."\n";
要测试它,从命令行尝试:
$红宝石publisher.rb | PHP consumer.php
这是我的文本
我因为PHP是使用密码小于8个字符有很多麻烦。在这种情况下,一个需要添加0,以使其与PHP兼容:
的mcrypt-加密手册页 “键
与该数据将被加密的密钥。如果它不是必需的密钥大小小,则填充为“\ 0”。这是最好不要使用ASCII字符串钥匙。 http://php.net/manual/en/function.mcrypt-encrypt.php 建议使用Mhash函数库来创建从字符串的密钥“。
require 'openssl'
cipher = OpenSSL::Cipher.new('DES-ECB')
cipher.encrypt
key = 'passwrd'[0...7].ljust(8, 0.chr) #Pad the key smaller than 8 chars
cipher.key = key
encrypted = cipher.update('33')
encrypted << cipher.final
dec = Base64.encode64(encrypted).strip()
让我告诉你一些代码。
PHP代码:
$privateKey = "1234567890123456"; # the size is 16.
$data = "hello";
$iv = "0123456789012345";
$result = mcrypt_encrypt(
MCRYPT_RIJNDAEL_128, $privateKey, $data, MCRYPT_MODE_CBC, $iv
)
$base64str = base64_encode($result);
$base64str = str_replace("+", "-", $base64str);
$base64str = str_replace("/","_", $base64str);
# => f-WffBXnf122NcVBUZ6Rlg==
Ruby代码:
require 'base64'
require 'openssl'
private_key = "1234567890123456"
data = "hello"
iv = "0123456789012345"
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
cipher.encrypt
cipher.padding = 0 # we must disable padding in ruby.
cipher.key = private_key
cipher.iv = iv
block_size = cipher.block_size
# Add padding by yourself.
data = data + "\0" * (block_size - data.bytesize % block_size)
result = cipher.update(data) + cipher.final
Base64.urlsafe_encode64(result)
# ==> f-WffBXnf122NcVBUZ6Rlg==
正如你可以看到我使用AES-128中红宝石因为private_key
的大小为16。
所以,你必须使用AES-256,如果你的private_key
的大小为32。
式:size_of_private_key
* 8