确定性地生成加密安全密钥和IVEC

时间:2010-11-29 12:16:32

标签: c++ hash cryptography secret-key crypto++

背景

我正在设计一个系统,该系统可以为静态Web内容的用户开发动态身份验证方案。其动机是预先生成大量复杂的生成但敏感的Web内容,然后通过基于cookie(嵌入可逆加密信息)的身份验证进行静态服务,由Web服务器强制执行。使用AEAD模式加密原语。

问题

我需要生成一段时间有效的IVEC和密钥,比如一周(当前有效对)。并且过去的IVEC /密钥也有效期为2周(历史上有效),并且使用历史有效秘密加密的任何数据将仅使用当前有效的IVEC / KEY重新加密。

我需要的是一个确定性的CSPRNG,即随机数和密码短语的种子,它可以以索引方式产生64位或128位数字块。如果我使用一周以来 - “1970年1月1日”作为我假设的CSPRNG的索引元素之一,我应该能够构建一个随着时间的推移自动更改密钥的系统。

我正在考虑的方法

现在我没有在cryptopp中看到这样的功能,或者我现在已经足够了解术语,并且由于cryptopp是最先进的加密库,我没有信心我会找到另一个。所以,如果我找不到实现,我应该自己动手。是否会从连接数据中生成静态字符串结构然后对其进行散列(如下所示)?

RIPEMD160(RandomPreGeneratedFixedNonce:密码短语:UInt64SinceEpoch:128BitBlockIndexNumber);

注意:块编号将被分配并具有常规结构,因此例如对于128位摘要,块0的前64位将用于ivec,而所有元素1用于128位键。

这是一种合理的方法( - 。,加密安全)?

- 编辑:发表接受评论

经过一番反思后,我决定将我最初认为的密码短语和nonce / salt合并为一个16字节(加密的强)密钥,并使用PKCS#5中概述的技术来导出多个基于时间的密钥键。不需要盐,因为不使用密码短语。

2 个答案:

答案 0 :(得分:4)

有趣的问题。

首先,您的初始向量不一定是加密强随机数,但 每个消息应该是唯一的。 IV实际上只是一种盐值,可确保使用相同密钥加密的类似消息在加密后看起来类似。您可以使用任何快速伪随机生成器生成IV,然后将其与加密数据一起发送(最好是加密的)。

当然,钥匙应该尽可能强大。

我提议散列包含现时,密码和有效性数据的文本字符串似乎非常合理 - 它与使用密码短语生成密钥的其他系统所做的大致相符。你应该多次哈希 - 而不仅仅是一次 - 使密钥生成计算成本昂贵(对于任何试图暴力破解密钥的人而言,这将是一个更大的问题)。

您可能还想查看PKCS#5中设置的密钥生成方案(例如,在http://www.faqs.org/rfcs/rfc2898.html),该密钥生成方案在cryptopp中作为PasswordBasedKeyDerivationFunction实现。这种机制已经被广泛使用并且已知是合理安全的(注意PKCS#5建议将密码短语数据散列至少1000次)。您可以将有效期和索引数据附加到密码短语,并使用PasswordBasedKeyDerivationFunction。

您没有说明您建议使用哪种加密算法来加密数据,但我建议您应该选择广泛使用且已知安全的内容......特别是我建议您使用AES。我还建议使用一个SHA摘要函数(可能作为PasswordBasedKeyDerivationFunction的输入)。 SHA-2是最新的,但SHA-1足以用于密钥生成。

您也没有说明您要生成的密钥长度,但您应该知道密钥中的熵数量取决于您使用的密码长度,除非密码短语为非常长,远远小于理想要求的密钥长度。

这个方案中最薄弱的环节是密码本身,这总是会限制你可以达到的安全级别。只要您对数据进行加盐(就像您正在做的那样)并使密钥生成变得昂贵以减缓暴力攻击,您应该没问题。

答案 1 :(得分:1)

  

我需要的是一个确定性的CSPRNG,即随机数和密码短语的种子,它可以以索引方式产生64位或128位数字块。如果我用了几个星期 - " jan 1 1970"作为我假设的CSPRNG的索引元素之一,我应该能够构建一个随着时间的推移自动更改密钥的系统。

嗯,我认为部分解决方案是使用非基于时间的生成器。这样,如果双方都以相同的种子开始,那么他们都产生相同的随机流。自1970年第1周和第34周以来,你可以对你的周期进行分层。最重要的逻辑。

为此,您可以使用OFB_mode<T>::Encryption。它可以用作生成器,因为OFB模式使用AdditiveCipherTemplate<T>,它派生自RandomNumberGenerator

事实上,Crpyto ++使用test.cpp中的生成器,以便在出现问题时可以重现结果。以下是{1 {}的使用方法。它也适用于OFB_mode<T>::Encryption

CTR_Mode<T>::Encryption

SecByteBlock seed(32 + 16); OS_GenerateRandomBlock(false, seed, seed.size()); for(unsigned int i = 0; i < 10; i++) { OFB_Mode<AES>::Encryption prng; prng.SetKeyWithIV(seed, 32, seed + 32, 16); SecByteBlock t(16); prng.GenerateBlock(t, t.size()); string s; HexEncoder hex(new StringSink(s)); hex.Put(t, t.size()); hex.MessageEnd(); cout << "Random: " << s << endl; } 的调用从OS_GenerateRandomBlock获取字节,然后将其用作模拟共享种子。程序的每次运行都会有所不同。在程序的每次运行中,它的打印类似于以下内容:

/dev/{u|s}random

还有另一个可用的生成器,但它不是Crypto ++库的一部分。它名为$ ./cryptopp-test.exe Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD Random: DF3D3F8E8A21C39C0871B375013AA2CD ,基于AES-256。它只是一个头文件实现,您可以在RandomNumberGenerator下的Crypto ++ wiki中找到它。

另请参阅Crypto ++ wiki上AES_RNG类的主题Reproducibility

相关问题