我想在ruby应用程序中加密一些数据,然后在nodejs应用程序中对其进行解码。我一直试图让这个工作,现在我只是尝试加密两种语言中的同一条数据,以获得相同的结果,但我似乎无法做到。
//js
var crypto = require('crypto');
var key = crypto.createHash('sha1').update('key').digest('hex');
console.log(key); // a62f2225bf70bfaccbc7f1ef2a397836717377de
var encrypted = "";
var cipher = crypto.createCipher('bf-cbc', key);
encrypted += cipher.update('text');
encrypted += cipher.final('hex');
console.log(encrypted); //outputs 4eafd5542875bd3c
所以看起来我从编码中得到一个十六进制字符串。
#ruby
require 'openssl'
require 'digest/sha1'
c = OpenSSL::Cipher::Cipher.new("bf-cbc")
c.encrypt
# your pass is what is used to encrypt/decrypt
c.key = key = Digest::SHA1.hexdigest("key")
p key # a62f2225bf70bfaccbc7f1ef2a397836717377de
e = c.update("text")
e << c.final
p e # 皋?;??
是否存在某些我遗漏的编码问题。我尝试使用base64解码e,但这并没有产生与节点应用相同的结果。有什么指针吗?
更新:所以这和朋友一样近,我可以得到:https://gist.github.com/a880ea13d3b65a21a99d。 Sheesh,我只是想在ruby中加密一些东西并在节点中解密它。
UPDATE2:好的,这个问题中的代码让我有很多方法:https://github.com/joyent/node/issues/1395
答案 0 :(得分:4)
有几个微妙的事情使这个失败。最重要的一个 - 您没有在代码中指定IV,因此将为您生成随机值。您会注意到,您甚至无法以相同的编程语言解密您的密文。
因此,您需要为两个实现提供明确的IV。但在我向您展示代码之前,请先提出一些建议:
密钥生成:
Blowfish在64位块上运行,其密钥大小各不相同,但OpenSSL(目前同时支持Ruby和node.js的密码实现)默认使用128位,即16字节。
所以你的密钥违反了两个原则 - 第一个:它太长了。它是SHA-1哈希的十六进制表示,它是20个字节* 2 = 40个字节而不是16个。大多数情况下这很好,因为实现会适当地截断值,但这应该 not not 依赖。
第二个错误,更严重的是,你使用十六进制表示而不是原始字节:大安全问题!十六进制字符根本不是随机的,因此实际上您将输入的熵减少到一半长度(因为底层字节是随机的)。
生成随机密钥的安全方法是使用OpenSSL :: Random
key = OpenSSL::Random.random_bytes(cipher_key_len)
第三个错误是将密钥保存在源代码中。这是个坏主意。您应该做的最少的事情是将其存储在文件系统的其他位置,严格限制访问。另见my answer另一个问题。密钥应该存储在带外,并且只在应用程序中动态加载。
<强>密码强>:
河豚变老了。从某种意义上来说它仍然被认为是不间断的,因为强制它是打破它的唯一方法。但对于资源丰富的攻击者而言,2 ^ 64的搜索空间并非遥不可及。所以你应该继续使用AES。
<强>填充强>:
OpenSSL打击垫默认使用PKCS5Padding(也称为PKCS7Padding)。 Ruby从中获利,我的赌注是node.js也使用了这个 - 所以你应该对此保持安全。
现在来到工作解决方案。我们需要生成一个IV,Blowfish要求它是64位--8个字节。您将需要rbytes来获取节点中的安全随机数。 IV可以在你的来源中进行硬编码(它是公共信息,没有安全影响) - 但它必须在双方都是相同的。您应该预生成一个值并将其用于node.js和Ruby。
/*node.js*/
var rbytes = require('rbytes');
var iv = rbytes.randomBytes(8);
/*see advice above - this should be out-of-band*/
var key = rbytes.randomBytes(16);
var encrypted = "";
var cipher = crypto.createCipheriv('bf-cbc', key, iv);
encrypted += cipher.update('text');
encrypted += cipher.final('hex');
现在Ruby部分:
require 'openssl'
c = OpenSSL::Cipher::Cipher.new("bf-cbc")
c.encrypt
# should be out-of-band again
c.key = OpenSSL::Random.random_bytes(16)
# may be public but has to be the same for Ruby and node
iv = OpenSSL::Random.random_bytes(8)
c.iv = iv
e = c.update("text")
e << c.final
puts e.unpack('H*')[0]
答案 1 :(得分:0)
您的密文将是一些随机的字节。这些字节可以表示为十六进制,Base64或其他方式。看起来您的ruby代码正在输出原始字节。我建议您将这些原始字节转换为十六进制以进行比较。
查看您的代码,您还应该从Blowfish(“bf”)更改为AES。 Blowfish的块大小为64位,现已过时。
你最好明确指定填充,PKCS7是常见的
答案 2 :(得分:0)
行。我要感谢大家帮助我。基本上这个帖子在这里回答了我的问题:https://github.com/joyent/node/issues/1395。我将继续发布这两个程序,以防其他任何人必须通过这个程序。请记住,这不是硬核安全的意思,这是ruby加密数据和节点解密它的垫脚石。您将不得不采取更多措施来确保采取更高的安全措施。
代码位于此要点:https://gist.github.com/799d6021890f34734470
这些是在ruby 1.9.2p290和节点0.4.10
上运行的