Ruby:使用私钥/公钥进行文件加密/解密

25

我正在寻找一个符合以下要求的文件加密/解密算法:

  • 算法必须可靠
  • 对于相当大的文件,算法应该具有较快的速度
  • 私钥可以通过某些参数(例如密码)生成
  • 生成的私钥必须与公钥兼容(公钥仅生成一次并存储在数据库中)

是否有建议算法的Ruby实现?

4个回答

38

请注意:正如emboss在评论中提到的那样,这个答案并不适合实际系统。首先,文件加密不应使用此方法(例如,该库提供了AES)。其次,此答案也未解决任何其他会影响您设计解决方案的更广泛问题。

原始来源还详细介绍了更多细节

Ruby可以使用openssl来完成此操作:

#!/usr/bin/env ruby

# ENCRYPT

require 'openssl'
require 'base64'

public_key_file = 'public.pem';
string = 'Hello World!';

public_key = OpenSSL::PKey::RSA.new(File.read(public_key_file))
encrypted_string = Base64.encode64(public_key.public_encrypt(string))

并进行解密:

#!/usr/bin/env ruby

# DECRYPT

require 'openssl'
require 'base64'

private_key_file = 'private.pem';
password = 'boost facile'

encrypted_string = %Q{
...
}

private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file),password)
string = private_key.private_decrypt(Base64.decode64(encrypted_string))

来自这里


2
其实我不是 Ruby 程序员,但那些库非常好用。我想知道在 Python 中相应的库会有多难... - brice
3
希望补充一下,文件应该使用AES-256等加密算法进行加密,但其密钥应该使用RSA进行传送。 - tiktak
4
抱歉,但这是非常糟糕的建议。原帖提到了文件加密/解密,而您不应该使用RSA进行此操作。 - emboss
@emboss:看看tiktak之前的评论。你说得完全正确——在想要回答问题时,我没有真正停下来考虑更广泛的问题。我会尝试修改我的帖子来展示这一点。 - brice
@Brice:太好了!没有什么损害,只是不想让人们误解 :) - emboss
当读取.cer文件时,我得到了OpenSSL :: PKey :: RSA公钥实例,但我无法像cipher.key = KEY这样将其设置为aes密钥,其中KEY是OpenSSL :: PKey :: RSA实例。这样做的方式正确吗?http://stackoverflow.com/q/40760184/4477305 - CodecPM

12
很抱歉,您在这里混淆了两个概念,身份验证/授权和机密性,试图在一个步骤中涵盖两个方面,这是行不通的。您永远不应该使用非对称算法加密“真实数据”。a)它们对于这个过程来说太慢了,b)如果做得不对,会严重削弱您解决方案的安全性。
一个好的经验法则是,您应该最终只使用私有的非对称密钥加密对称算法使用的密钥,这种对称算法速度要快得多。但在几乎所有情况下,您甚至都不应该这样做,因为在90%的情况下,您实际上想要的是TLS(SSL),我曾在这里尝试解释过为什么。
在您的情况下,我假设要求如下:
- 存储在数据库中的数据必须保持机密性:一般公众不应该能够读取它(甚至访问它) - 选择的少数人(可能只有一个人)应该能够访问和阅读那些数据
第一个目标通常通过使用对称加密来实现。第二个目标虽然相关,但是实现方式完全不同。您希望访问文件的用户得到身份验证(即建立身份),并且最重要的是您还希望他们获得授权(即检查已建立的身份是否有权执行他们打算执行的操作)。这就是非对称加密可能进入舞台的地方,但不一定需要。由于您的问题标记为Rails,我假设我们正在谈论一个Rails应用程序。您通常已经有一些手段在那里对用户进行身份验证和授权(很可能涉及上述TLS),您可以简单地重用它们以建立用于实际文件加密/解密的对称密钥。如果您想完全避免非对称加密,则基于密码的加密适合此目的。如果您还希望确保已经保密的数据的完整性,那么事情将变得更加复杂,也就是说,您希望向经过身份验证和授权的用户提供某种保证,即他们最终访问的内容在此期间没有被修改。
开发这个解决方案并不是一项简单的任务,它很大程度上取决于您的具体需求,因此没有适用于所有人的“黄金方法”。我建议您进行一些研究,更清楚地了解您想要实现什么以及如何实现,然后尝试获取有关您仍感到不确定/不舒服的主题的额外建议。

1
谢谢回答!我用以下方式传输和存储数据解决了这个问题:1)生成对称加密密钥(sym-key)2)使用sym-key加密文件3)使用公共非对称密钥加密sym-key 4)发送文件和加密的sym-key 5)使用用户的秘密令牌解密用户私有加密的非对称密钥6)使用私有非对称密钥解密接收到的sym-key 7)使用解密后的sym-key解密文件。我认为这很正常。 - tiktak
2
这是正确的方向!但它仍然容易受到重放攻击的威胁。你能不能使用TLS代替发送由非对称密钥包装的密钥呢?我发现在几乎所有从A到B传输数据的情况下,你应该使用TLS而不是非对称加密 - TLS可以保护你免受可能会破坏自定义协议的事物的影响。 - emboss

2

对称加密绝对快速,并支持流式传输非常大的文件。

SymmetricEncryption::Writer.open('my_file.enc') do |file|
  file.write "Hello World\n"
  file.write "Keep this secret"
end

对称加密是为组织内部的数据和大文件加密而设计的。

如果需要与其他组织共享文件,则最好选择PGP。对于使用PGP流式传输非常大的文件,请考虑: IOStreams

IOStreams.writer('hello.pgp', recipient: 'receiver@example.org') do |writer|
  writer.write('Hello World')
  writer.write('and some more')
end

请查看文件 iostreams/lib/io_streams/pgp.rb 以获取更多 PGP 示例。它还支持直接从 Ruby 进行 PGP 密钥管理。

0
我制作了一个宝石来帮助这个问题。它叫做cryptosystem。只需配置您的私钥路径和密码以及您的公钥路径,它就会完成其他工作。
加密就像这样简单:
rsa = Cryptosystem::RSA.new
rsa.encrypt('secret') # => "JxpuhTpEqRtMLmaSfaq/X6XONkBnMe..."

解密:

encrypted_value = rsa.encrypt('secret') # => "Y8DWJc2/+7TIxdLEolV99XI2sclHuK..."
rsa.decrypt(encrypted_value) # => "secret"

你可以在 GitHub 或者 RubyGems 上查看。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接