我正在尝试将PHP库移植到ruby,并且crypto / decrypt函数没有给出相同的结果:
我正在尝试转换此方法:
function encrypt_3DES($message, $key){
$l = ceil(strlen($message) / 8) * 8;
$padded_message = $message . str_repeat("\0", $l - strlen($message));
$iv = "\0\0\0\0\0\0\0\0";
return substr(openssl_encrypt($padded_message, 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, $iv), 0, $l);
}
对此:
def encrypt_3DES(message, key)
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC')
cipher.encrypt
cipher.key = key
cipher.iv = "\0" * 8
output = cipher.update(message) + cipher.final
output
end
这给了我一些问题:
原始密钥长24个字节,而ruby引发异常
Base64.decode64('sq7HjrUOBfKmC576ILgskD5srU870gJ7')
ArgumentError (key must be 16 bytes)
使用ruby接受的相同消息和密钥,php输出会有所不同
message1
1234567890123456
uJxPvodsbLs=
K8v3K/w4pS7R2DHXr0UHbQ==
我在做什么错了?
我正在使用PHP 7.3.11和ruby 2.6.5p114
des-ede-cbc
(在Ruby中使用)与Tripple-des的变体稍有不同,与PHP中使用的des-ede3-cbc
略有不同。对于des-ede-cbc
,您将在两个加密阶段使用相同的密钥(这说明了为什么只需要两个密钥,即2 * 8 = 16字节),而对于des-ede3-cbc
,您将使用三个密钥,因此3 * 8 = 24字节。
如果使用正确的算法,则会从OpenSSL获得相同的输出(但请参见下文)。
function encrypt_3DES($message, $key){
$l = ceil(strlen($message) / 8) * 8;
$padded_message = $message . str_repeat("\0", $l - strlen($message));
$iv = "\0\0\0\0\0\0\0\0";
return substr(openssl_encrypt($padded_message, 'des-ede3-cbc', $key, OPENSSL_RAW_DATA, $iv), 0, $l);
}
echo base64_encode(encrypt_3DES('message1', base64_decode('sq7HjrUOBfKmC576ILgskD5srU870gJ7')));
# => "OO4olPtGedE="
def encrypt_3DES(message, key)
cipher = OpenSSL::Cipher.new('des-ede3-cbc')
cipher.encrypt
cipher.key = key
cipher.iv = "\0" * 8
output = cipher.update(message)
output
end
Base64.encode64 encrypt_3DES('message1', Base64.decode64('sq7HjrUOBfKmC576ILgskD5srU870gJ7'))
# => "OO4olPtGedE6qq1lHRAtgQ==\n"
您可以看到两个实例中的前缀相同。唯一的区别是,在您的PHP实现中,您没有生成(重新删除)最终的块,但是最终的块实际上是解密数据所必需的。通过从PHP版本中删除substr
逻辑,在两种情况下,您都应该获得正确的加密数据。
话虽如此,请考虑3DES是一种非常过时且(对于大多数当前应用而言)不安全的算法。如果您打算在任何玩具应用程序之外使用此代码(即:如果您打算将其与此附带的生产代码一起使用,则应使用更现代的算法。一个很好,安全且维护良好的选项是使用libsodium的密码箱。) 7.2,这是PHP本身提供的,较早的版本可以使用PECL软件包。some documentation上有关于如何使用它的信息。
在Ruby中,您可以使用rbnacl宝石,它在底层也使用libsodium并具有相同的功能。