背景信息:
我正计划制造一个文件主机,使用它可以加密和上传文件。为了保护数据免遭任何形式的黑客攻击,我不想知道用于文件的加密密钥($ K $),因此用户将必须非对称地加密$ K $并将其发送出去。进行这种双重加密的原因是,您仍然可以通过使用这些用户的公用密钥对$ K $进行加密来与其他帐户共享(个人!)文件。

我的问题是:用户可以在无需服务器保存/知道私钥且无需记住250个十六进制字符的密码的情况下获得公钥和私钥?

问题:
有办法吗?也可以像PBKDF-2那样从密码派生密钥对来进行对称加密吗?
也建议以更简单的方式重新安排密码步骤。也可以使用PBKDF应用的密码对私钥进行加密,然后将其存储在服务器上,但是我想使事情保持“简单”。 ;)

注意:目前,我不在乎它是否需要RSA,ECC或晦涩的加密方案。

评论

如果可用,并且您可以选择自己的协议,则椭圆曲线将有意义。正如Ilmari Karonen指出的那样,RSA繁琐,因为它在解密数据时效率很低,而在创建密钥时则效率极低。如果采用ECC方式,请尝试使用“命名曲线”。如果您选择使用RSA,最好听一下埃里克森的建议。

欢迎使用密码学堆栈交换。您的问题已迁移到这里,因为它在Stack Overflow上是不合主题的,在这里是不合主题的。请注册您的帐户以便发表评论并接受答案。

#1 楼

您可能希望得到的最好的结果如下:


您将密码派生到具有诸如PBKDF2之类的密钥派生功能的“足够大”(例如128位)秘密密钥$ K $中。有一些细节需要注意(请参阅下文)。
您将密钥$ K $用作伪随机数生成器的种子。 PRNG是确定性的(相同的种子表示相同的输出序列)并产生随机位。
要对任何要使用的非对称算法,在密钥对生成算法中使用PRNG。对于基于离散对数的算法(例如DSA,ElGamal,Diffie-Hellman及其椭圆曲线变体),此步骤既便宜又简单,但前提是必须事先知道组参数(例如,将其硬编码在您需要的所有相关软件中)正在使用由NIST定义的标准P-256椭圆曲线进行ECDSA / ECDH)。对于RSA,这便宜且简单,因为密钥生成过程需要生成随机整数,直到达到质数为止。仍然可行。

由于此过程是确定性的(对于给定的源密码),因此您每次需要私钥时都可以再次运行它。


现在,密码的麻烦在于它们来自相对较小且不一致的空间,即“适合普通用户的事物”。他们容易受到详尽搜索的攻击,对于密码,传统上称为字典攻击。有三种通用的方法来解决该问题:



不要让攻击者了解任何允许他验证密码猜测的数据。在通常将密码哈希存储在服务器中以进行用户身份验证的情况下,这意味着您不希望攻击者能够读取数据库。这就是大约15年前类似Unix的系统切换到影子密码的原因。您仍然希望存储哈希密码,并使用其他两种保护措施,因为在现实世界中确实会发生非法的只读访问。
使用可配置的慢速密钥派生功能。这使字典攻击成比例地变慢-但由于相同的因素,正常使用也变慢。这就是为什么PBKDF2或bcrypt之类的KDF包含迭代计数的原因。您希望将计数增加到用户仍然可以承受的最高值。
使用盐来防止攻击并行性。并行是指以不到攻击成本N倍的N倍(不一定要同时)攻击N个密码(预计算表是一种并行性)。盐是公开数据,是KDF的变体。这相当于说有很多不同的KDF,盐表示您使用的是哪种。

在您的情况下,您没有第一道保护:从本质上讲,生成的公钥是,公开,因此可以用于离线字典攻击。攻击者只需尝试可能的密码,直到找到相同的公共密钥。这是您要实现的目标的内在要求。

第三种保护(盐)也可能很困难。盐不必是秘密的,但仍必须具有一定程度的完整性。无论将盐存储在哪里,都必须合理地保证要重新计算其私钥的用户使用的盐正确(否则,他将计算错误的私钥)。根据使用情况,拥有这样的存储空间可能并不容易。一种解决方案是将用户名用作“ salt”(大概,用户将能够记住自己的名字)。有时,用户名并不理想,原因是:


在两个不同服务器上安装的两个用户(使用相同的软件)可能具有相同的名称;用户更改密码,但不更改名称;

这破坏了盐试图达到的“唯一性”特性。尽管如此,盐的用户名要比没有盐好得多(更好的是,将用户的电子邮件地址用作salt:用户记住自己的地址,并且电子邮件地址本质上在全球范围内是唯一的)。如果您根本不使用任何盐,那么在同一系统上的两个不同的用户,恰巧选择了相同的密码,将最终得到相同的密钥对,只需列出公共密钥即可立即显示它。 >

注:从密码派生私钥意味着用户更改密码时,他也会更改其私钥。很有可能这是一个问题。这就是为什么您偏爱间接系统的原因之一,在该系统中,一个完全普通的密钥对存储在某个位置,并使用密码派生的密钥对称加密。因此,更改密码后,只需使用旧密码解密密钥,然后使用新密码再次加密。但这需要一个可用的存储区域。该模型由例如GnuPG直接支持。

评论


$ \ begingroup $
“对于RSA来说,这便宜又简单,因为密钥生成过程需要生成随机整数,直到达到质数为止。这仍然是可行的。”特别感谢您澄清这一点;我担心不可能轻易地从随机数中得出质数。添加用户的邮件地址也是一个不错的主意。 (就像在SMF中生成的盐一样,它对于每个用户都应该是唯一的)
$ \ endgroup $
–忽悠
2012年1月15日12:06



$ \ begingroup $
tan PBKDF2或bcrypt会是一个更好的选择。
$ \ endgroup $
–fgrieu♦
2012年7月7日在11:46

$ \ begingroup $
如果我希望派生的RSA密钥例如为4096位长,则PRNG的种子应长多少个字节?
$ \ endgroup $
– Stil
17年6月17日在18:01

#2 楼

一种常见的方法是使用从密码短语派生的对称密钥对私钥进行加密。这将与所选密码短语一样安全。我建议坚持使用这种方法。它的常规性使其比尚未得到充分研究的解决方案“更简单”。

评论


$ \ begingroup $
我想我会采用这种方法。就像Thomas和Ilmari所说的那样,可以为RSA派生一个密钥对(这对我来说是最容易部署的),但是,因为只有用户需要知道他的密码才能解密文件的私钥(以及任何个人信息)。并加密新的私钥,使用带有简单KDF的AES(同样也是我最容易部署的安全)同样安全。
$ \ endgroup $
–忽悠
2012年1月15日12:16

#3 楼

是的,您也可以使用PBKDF派生用于非对称加密的密钥。这对于使用ElGamal,IES或椭圆曲线变体之类的加密方案最为方便,其中私钥只是从给定间隔中选择的随机数。从原则上讲,您也可以对RSA进行同样的操作,但是密钥生成过程比较麻烦。

(RSA密钥生成可以看作是一个随机比特流和输出的过程,具有概率随着时间的流逝,RSA密钥对逐渐接近1,要确定基于密码的RSA密钥,您需要指定密钥生成算法本身的每个细节,以使对算法的更改不能更改输出,然后使用从密码短语作为随机输入派生的伪随机比特流。)

您可能还想看看crypto.SE上的这个最新问题,它涉及一个类似的问题(重新推导非对称加密在运行时从存储的随机值中删除键)。

#4 楼

如果您想研究根据密码生成非对称密钥对,这是一个示例方案,其中还包括有关其用法的一些讨论(完整披露:我参与定义关联的标准)。使用这样的“分散身份”提供了很多机会。

主要的权衡是尽管用户不需要记住“ 250个字符的十六进制密码”,而典型的用户是“半随机8位”。字符密码”不会删除它。密码必须足够长且足够随机,以使由密码数据生成的非对称密钥的关联密钥空间足够大,可以承受暴力攻击,例如攻击。设置为az,AZ,0-9的〜16个完全随机字符的范围内。

但是,学习一个“真正复杂的”密码的用户受益的是,相同的密钥对可以与多种服务一起使用,并且可以通过对密钥生成输入数据进行轻微的非随机变化来轻松生成不同的密钥(身份)。这里是从密码生成密钥的python示例(关联的库是开源的,因此您可以尝试一下并从源代码中查找密钥生成代码。

评论


$ \ begingroup $
链接断开
$ \ endgroup $
– Ohad Cohen
16 Dec 20'在11:04