使用 ruby​​ 加密数据,使用 Node 解密

发布于 2024-12-01 07:23:21 字数 1253 浏览 2 评论 0原文

我想在 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 # 皋?;??

我是否缺少某种编码问题。我尝试对 e 进行 Base64 解码,但没有产生与节点应用程序相同的结果。有什么指点吗?

更新:所以这就像朋友一样亲密,我可以获得: https://gist.github.com/a880ea13d3b65a21a99d< /a>.天啊,我只想在 ruby​​ 中加密一些东西并在节点中解密它。

UPDATE2:好吧,这个问题中的代码让我明白了很多: https://github .com/joyent/node/issues/1395

I want to encrypt some data in a ruby app and then decode it in a nodejs app. I have been trying to get this to work and now I am just trying to encrypt the same piece of data in both languages to get the same result but I can't seem to do it.

//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

So it looks like I get a hexadecimal string from the encoding.

#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 # 皋?;??

Is there some sort of encoding issue that I am missing. I tried to base64 decode e but that didn't produce the same result as the node app. Any pointers?

UPDATE: So this is as close as a friend and I can get: https://gist.github.com/a880ea13d3b65a21a99d. Sheesh, I just want to encrypt something in ruby and decrypt it in node.

UPDATE2: Alright, the code in this issue gets me a lot of the way there: https://github.com/joyent/node/issues/1395

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花之痕靓丽 2024-12-08 07:23:21

有几个微妙的因素导致了这次失败。最重要的是 - 您没有在代码中指定 IV,因此将为您生成一个随机值。您会注意到,您甚至无法通过这种方式在相同的编程语言中解密您的密文。

因此,您需要为这两种实现提供显式的 IV。但在我向您展示代码之前,有一些建议:

密钥生成

Blowfish 在 64 位块上运行,其密钥大小各不相同,但 OpenSSL(目前支持 Ruby 和 Node.js 的密码实现)使用默认为128位,即16字节。

所以你的密钥违反了两个原则 - 第一个:它太长了。它是 SHA-1 哈希值的十六进制表示形式,为 20 字节 * 2 = 40 字节,而不是 16。大多数时候这很好,因为实现会适当截断值,但这是您不应该做的事情 取决于。

第二个错误更严重,是您使用十六进制表示而不是原始字节:严重的安全问题!十六进制字符根本不是随机的,因此实际上您将输入的熵减少到长度的一半(因为底层字节是随机的)。

生成随机密钥的安全方法是使用 OpenSSL::Random

key = OpenSSL::Random.random_bytes(cipher_key_len)

第三个错误是将密钥硬编码在源中。这是一个坏主意。您至少应该做的是将其存储在文件系统的其他位置,访问受到严格限制。另请参阅我对另一个问题的回答。密钥应存储在带外,并且仅在应用程序内动态加载。

密码

河豚变老了。它仍然被认为是未破坏的,因为暴力破解它是破坏它的唯一方法。但 2^64 的搜索空间对于足智多谋的攻击者来说并非遥不可及。所以你确实应该转向 AES。

Padding

默认情况下,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]

There are several subtle things that make this fail. The most important one - you are not specifying an IV in your code, so a random value will be generated for you. You would notice that you couldn't even decrypt your ciphertext within the same programming language this way.

So you need to provide an explicit IV to both implementations. But before I show you the code, some advice:

Key generation:

Blowfish operates on 64 bit blocks, its key size varies, but OpenSSL (which currently powers both Ruby's and node.js' cipher implementation) uses 128 bit by default, that is 16 bytes.

So your key violates two principles - the first: it's simply too long. It's the hex representation of a SHA-1 hash, which is 20 bytes * 2 = 40 bytes instead of 16. Most of the time this is fine, because the implementation truncates the values appropriately, but that is something you should not depend on.

The second mistake, much more severe, is that you use the hex representation instead of the raw bytes: big security issue! Hex characters are not random at all, so in effect you reduce the entropy of your input to half the length (because the underlying bytes were random).

A secure way to generate random keys is using OpenSSL::Random

key = OpenSSL::Random.random_bytes(cipher_key_len)

A third mistake is to keep your key hard-coded in the sources. It's a bad idea. The least you should do is to store it elsewhere on the file system, where access is tightly restricted. See also my answer to another question. The key should be stored out-of-band and only loaded dynamically within the application.

Cipher:

Blowfish grows old. It's still considered unbroken in the sense that brute-forcing it is the only way to break it. But a search space of 2^64 is not out of reach for resourceful attackers. So you should indeed move on to AES.

Padding:

OpenSSL pads using PKCS5Padding (also known as PKCS7Padding) by default. Ruby profits from this and my bet is node.js utilizes this, too - so you should be safe on this.

Now to the working solution. We need to generate an IV, Blowfish requires it to be 64 bit - 8 bytes. You will need rbytes to get secure random numbers in node. The IV may be hardcoded in your sources (it's public information, no security impact) - but it must be the same on both sides. You should pregenerate a value and use it for both node.js and 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');

Now the Ruby part:

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]
把人绕傻吧 2024-12-08 07:23:21

您的密文将是一些看起来随机的字节。这些字节可以表示为十六进制、Base64 或其他方式。看起来您的 ruby​​ 代码正在输出原始字节。我建议您将这些原始字节转换为十六进制以进行比较。

查看您的代码,您还应该从 Blowfish (“bf”) 更改为 AES。 Blowfish 具有 64 位块大小,现已过时。

您最好明确指定填充,PKCS7 很常见

Your cyphertext will be some random looking bytes. Those bytes can be expressed as hex, Base64 or in other ways. It looks as if your ruby code is outputting the raw bytes. I suggest that you convert those raw bytes to hex to make your comparison.

Looking at your code, you should also change from Blowfish ("bf") to AES. Blowfish has a 64-bit block size and is now obsolete.

You would do well to explicitly specify padding, PKCS7 is common

会发光的星星闪亮亮i 2024-12-08 07:23:21

好的。我要感谢大家帮助我。基本上这个线程在这里回答了我的问题: https://github.com/joyent/node/issues/1395 。我将继续发布这两个程序,以防其他人必须经历这个繁琐的过程。请记住,这并不意味着硬核安全,这是 ruby​​ 加密数据和节点解密数据的垫脚石。您将必须采取更多步骤来确保采取更高的安全措施。

代码位于以下要点: https://gist.github.com/799d6021890f34734470

这些运行于ruby 1.9.2p290 和节点 0.4.10

OK. I want to thank everyone for helping me out. Basically this thread here answers my question: https://github.com/joyent/node/issues/1395. I am going to go ahead and post the two programs in case anyone else has to go through this rigamarole. Keep in mind this isn't mean to be hardcore secure, this is a stepping stone for ruby encrypting data and node decrypting it. You will have to take more steps to make sure higher security measures are taken.

The code is located at this gist: https://gist.github.com/799d6021890f34734470

These were run on ruby 1.9.2p290 and node 0.4.10

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文