php - 为什么用 PHP 加密的东西与用 Ruby 加密的相同字符串不匹配?

标签 php ruby openssl mcrypt

这是我的要求:

我需要使用 AES 加密(包括随机 iv)在 PHP 中加密一个字符串,对其进行 Base64 编码,然后对其进行 URL 编码,以便它可以作为 URL 参数传递。

我试图在 PHP 和 Ruby 中获得相同的结果,但我无法让它工作。

这是我的 PHP 代码:

function encryptData($data,$iv){
    $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
    $iv_size = mcrypt_enc_get_iv_size($cipher);
    if (mcrypt_generic_init($cipher, 'g6zys8dlvvut6b1omxc5w15gnfad3jhb', $iv) != -1){
        $cipherText = mcrypt_generic($cipher,$data );
        mcrypt_generic_deinit($cipher);
        return $cipherText;
    }
    else {
        return false;
    }
}
$data = 'Mary had a little lamb';
$iv = '96b88a5f0b9efb43';
$crypted_base64 = base64_encode(encryptData($data, $iv));

这是我的 Ruby 代码:

module AESCrypt
  def AESCrypt.encrypt(data, key, iv)
    aes = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
    aes.encrypt
    aes.key = key
    aes.iv = iv
    aes.update(data) + aes.final      
  end
end

plaintext = "Mary had a little lamb"
iv = "96b88a5f0b9efb43"
@crypted = AESCrypt::encrypt(plaintext, "g6zys8dlvvut6b1omxc5w15gnfad3jhb", iv)
@crypted_base64 = Base64.encode64(@crypted)
@crypted_base64_url = CGI.escape(@crypted_base64)

令人恼火的是,两个代码示例都产生了相似但不完全相同的散列。例如上面的代码生成(base64编码,不是URL编码):

PHP:/aRCGgLBMOOAarjjtfTW2Qg2OtbPDLhx3KmgfgMzDJU=

ruby :/aRCGgLBMOOAarjjtfTW2XIZhZ9VjBx8PdozxSL8IE0=

任何人都可以解释我在这里做错了什么吗?此外,对我来说(因为我是一个 Ruby 人,通常不是 PHP)更容易修复 Ruby 代码而不是 PHP 代码。因此,如果您想在 Ruby 中提供一个可以与 PHP 完美搭配的解决方案,我将不胜感激。

哦,而且,在生产中,iv 确实是随机的,但对于这个例子,我将它设置为永久相同,以便可以比较输出。

编辑:

感谢 Eugen Rieck 的回答,我找到了解决方案。 Ruby 会填充 block ,但 PHP 不会,您必须手动完成。将 PHP 代码更改为以下内容,您将获得上述 Ruby 代码可以轻松破译的加密字符串:

$iv = '96b88a5f0b9efb43';
$data = 'Mary had a little lamb';

function encryptData($data,$iv){
    $key = 'g6zys8dlvvut6b1omxc5w15gnfad3jhb';
    $padded_data = pkcs5_pad($data);
    $cryptogram = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $padded_data, MCRYPT_MODE_CBC, $iv);
    return $cryptogram;
}

function pkcs5_pad ($text, $blocksize){
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

最佳答案

事实证明,这很简单:填充是罪魁祸首。

AES 是一种 block 密码,因此它适用于固定大小的 block 。这意味着,最后一个 block 将始终被填充,而且,你知道,标准的好处在于,有很多可供选择。 PHP 使用零填充,您必须查看 AESCrypt 以找出 Ruby 使用的是什么。

同样的问题存在于各种 JS AES 库和 PHP 中。我们最终总是自己做填充,因为这让我多次陷入血红色的愤怒之中。

当然,这解释了为什么第一部分(携带信息)相同,而第二部分(携带填充)不同。

关于php - 为什么用 PHP 加密的东西与用 Ruby 加密的相同字符串不匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9186541/

相关文章:

php - Mysql 存储过程

c - 生成 RSA 并保存在 ASN.1/DER 中时出现段错误?

android - 在android中为cCURL添加ssl证书有错误

c - 在 GCC 中链接 libssl 和 libcrypto

php - 通过 AJAX 模板化动态加载内容的最佳方法?

php - 执行对用户 readonlyuser 拒绝的命令

php - 未捕获的 soapfault 异常

ruby-on-rails - 同一模型的 Rails 多态关联和 has_many

ruby-on-rails - 在 Rails 中处理多个文件上传的最佳插件是什么?

ruby - 使用 win32ole excel 对象的运行方法的意外行为