为什么用PHP加密的内容与使用Ruby加密的相同字符串不匹配

为什么用PHP加密的内容与使用Ruby加密的相同字符串不匹配

本文介绍了为什么用PHP加密的内容与使用Ruby加密的相同字符串不匹配?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的要求:

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

I need to encrypt a string in PHP using AES encryption (including a random iv), Base64 encode it, then URL-encode it so that it can be passed as a URL parameter.

我正在尝试在PHP和Ruby中获得相同的结果,但是我无法使其正常工作.

I am trying to get the same result in both PHP and Ruby, but I can't make it work.

这是我的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代码:

Here is my Ruby code:

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编码):

The infuriating thing is that both code samples produce similar but not identical hashes. For example, the above code generates (base64 encoded, not URL encoded):

PHP: /aRCGgLBMOOAarjjtfTW2Qg2OtbPDLhx3KmgfgMzDJU=

PHP: /aRCGgLBMOOAarjjtfTW2Qg2OtbPDLhx3KmgfgMzDJU=

Ruby: /aRCGgLBMOOAarjjtfTW2XIZhZ9VjBx8PdozxSL8IE0=

Ruby: /aRCGgLBMOOAarjjtfTW2XIZhZ9VjBx8PdozxSL8IE0=

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

Can anyone explain what I'm doing wrong here? Also, it is easier for me (since I am a Ruby guy, not PHP usually) to fix the Ruby code rather than the PHP code. So if you wanted to provide a solution in Ruby that would pair well with PHP, I would be most appreciative.

哦,而且在生产中,iv确实是随机的,但是对于本示例,我将其设置为永久相同,以便可以比较输出.

Oh, and also, in production the iv really will be random, but for this example I set it to be permanently the same so that output could be compared.

多亏Eugen Rieck的回答,我才找到了解决方案. Ruby填补了这些障碍,而PHP则没有,您必须手动进行.将PHP代码更改为以下代码,您将获得上述Ruby代码可以轻松解密的加密字符串:

Thanks to Eugen Rieck's answer, I arrived at a solution. Ruby pads the blocks, but PHP does not, and you have to do it manually. Change the PHP code to the following, and you get encrypted strings that the above Ruby code can decipher easily:

$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);
}

推荐答案

结果很简单:填充是罪魁祸首.

Turns out, this is quite easy: The padding is the culprit.

AES是一种块密码,因此它适用于固定大小的块.这意味着,最后的代码段将一直被填充,并且,关于标准的好处是,有很多可供选择. PHP使用零填充,您必须查看AESCrypt才能找到Ruby的用途.

AES is a block cipher, so it works on fixed-size blocks. This means, that the last block will allways be padded, and , you know, the good thing about standards is, that there are so many to chose from. PHP uses zero padding, you will have to look into AESCrypt to find out what Ruby uses.

各种JS AES库和PHP都存在相同的问题.我们最终还是做了自己的填充,因为这使我有些时候陷入了血红色的愤怒之中.

The same problem exists with the various JS AES libraries and PHP. We ended up in allways doing our own padding, as this has driven me into blood-red fury quite some times.

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

Ofcourse this explains, why the first part (carrying the info) is identical, while the second part (carrying the padding) is different.

这篇关于为什么用PHP加密的内容与使用Ruby加密的相同字符串不匹配?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 15:26