在Rails中使用AES密码块链接解密字符串

时间:2011-12-22 06:48:24

标签: ruby-on-rails ruby cryptography encryption

我不得不在Rails中实现一个我以前没有合作过或看过的支付网关(Westpac在澳大利亚的Payway,如果有人有兴趣的话)。

他们的文档并不坏,而且系统相当合乎逻辑,以至于到目前为止它已经非常轻松(支付集成的奇迹)。

如果出现问题,付款后直接向Westpac发送邮件并处理完付款,他们会使用大型加密参数重定向回我们的网站。这意味着我们要解密以获取实际参数。

这是Westpac的指导:

  

使用带有密码块链接的AES,使用PCKS-5对参数进行加密      填充。解密算法应该用16字节初始化,零填充      初始化向量,并应使用您的加密密钥(可在PayWay Net Shopping Cart设置的Security页面上找到)。

     

在解密之前,使用重定向传递的参数将如下所示:

  EncryptedParameters=QzFtdn0%2B66KJV5L8ihbr6ofdmrkEQwqMXI3ayF7UpVlRheR7r5fA6
  IqBszeKFoGSyR7c7J4YsXgaOergu5SWD%2FvL%2FzPSrZER9BS7mZGckriBrhYt%2FKMAbTSS8F
  XR72gWJZsul9aGyGbFripp7XxE9NQHVMWCko0NlpWe7oZ0RBIgNpIZ3JojAfX7b1j%2F5ACJ79S
  VeOIK80layBwCmIPOpB%2B%2BNI6krE0wekvkkLKF7CXilj5qITvmv%2FpMqwVDchv%2FUNMfCi
  4uUA4igHGhaZDQcV8U%2BcYRO8dv%2FnqVbAjkNwBqxqN3UPNFz0Tt76%2BP7H48PDpU23c61eM
  7mx%2FZh%2Few5Pd0WkiCwZVkSZoov97BWdnMIw5tOAiqHvAR3%2BnfmGsx

Westpac没有Rails演示,但他们确实有PHP。这是PHP演示:

function decrypt_parameters( $base64Key, $encryptedParametersText, $signatureText )
{
    $key = base64_decode( $base64Key );
    $iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
    $td = mcrypt_module_open('rijndael-128', '', 'cbc', '');

    // Decrypt the parameter text
    mcrypt_generic_init($td, $key, $iv);
    $parametersText = mdecrypt_generic($td, base64_decode( $encryptedParametersText ) );
    $parametersText = pkcs5_unpad( $parametersText );
    mcrypt_generic_deinit($td);
}

以下是我在Rails中尝试过的内容:

def Crypto.decrypt(encrypted_data, key, iv, cipher_type)
    aes = OpenSSL::Cipher::Cipher.new(cipher_type)
    aes.decrypt
    aes.key = key
    aes.iv = iv if iv != nil
    aes.update(encrypted_data) + aes.final  
end

iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
key = Base64.decode64("mysecretkey")
data = Base64.decode64("QzFtdn0%2B66KJV5L8ihbr6ofdmrkEQwqMXI3ayF7UpVlRheR7r5fA6
     IqBszeKFoGSyR7c7J4YsXgaOergu5SWD%2FvL%2FzPSrZER9BS7mZGckriBrhYt%2FKMAbTSS8F
     XR72gWJZsul9aGyGbFripp7XxE9NQHVMWCko0NlpWe7oZ0RBIgNpIZ3JojAfX7b1j%2F5ACJ79S
     VeOIK80layBwCmIPOpB%2B%2BNI6krE0wekvkkLKF7CXilj5qITvmv%2FpMqwVDchv%2FUNMfCi
     4uUA4igHGhaZDQcV8U%2BcYRO8dv%2FnqVbAjkNwBqxqN3UPNFz0Tt76%2BP7H48PDpU23c61eM
     7mx%2FZh%2Few5Pd0WkiCwZVkSZoov97BWdnMIw5tOAiqHvAR3%2BnfmGsx")

cleartext = Crypto.decrypt(data, key, iv, "AES-128-CBC")

我只是传入PHP中提到的相同初始化向量,但我不确定这对Rails是否正确。

无论如何,提供密钥并且易于进行Base64解码,加密参数也是如此。在一天结束时,我收到了这个错误:

cipher.rb:21:in `final': wrong final block length (OpenSSL::Cipher::CipherError)
from cipher.rb:21:in `decrypt'
from cipher.rb:29:in `<main>'

不可否认,我对这个Crypto的东西不太了解,但我还是靠墙而且没有时间(尽管有兴趣)了解更多信息。

1 个答案:

答案 0 :(得分:8)

问题是,输入数据另外是“URI转义”并且ruby的base64-decoder没有“关心”无效的base64-input(%没有base64-digit),所以没有错误被提出来了。

解决方案是使用URI.unescape

require 'uri'

data = Base64.decode64(
    URI.unescape("QzFtdn0%2B66 ... Iw5tOAiqHvAR3%2BnfmGsx"))

当然,如果输入数据是从GET / POST参数接收的,那么输入数据很可能已经被您的网络堆栈“转义” - 只是作为一个小心谨慎的注意事项(如果输入数据中出现百分号unescape,则双%可能会导致问题。