确定性地生成密码固定的密钥和IVEC的密钥
-
29-09-2019 - |
题
背景
我正在设计一个系统,该系统可以为静态Web内容的用户开发动态身份验证方案。动机是预先生成大量的复杂到生成,但敏感的网络包含,然后静态地将其与基于cookie的(嵌入可逆的加密信息嵌入)身份验证,由Web服务器执行。使用AEAD模式加密原始。
问题
我需要生成有效期有效的IVEC和键,例如一周(当前播种机对)。而且,过去的IVEC/键也有效说2周(历史上是valid),并且任何与历史上有效秘密加密的数据都只会与当前的valid ivec/key重新加密。
我需要的是一个确定性的csprng,它的播种是一个随机数和密码,并且可以以索引的方式64位或128位数字块产生。如果我使用数周的“ 1970年1月1日”作为我假设的CSPRNG的索引元素之一,我应该能够构建一个随着时间的流逝而自动更改键的系统。
我正在考虑的方法
现在,我在CryptoPP中没有看到这样的功能,或者现在我确实非常了解术语,并且由于CryptoPP是那里最先进的加密库,我没有信心,我会找到另一个。因此,如果我找不到那里的实现,我应该自己滚动。会从排气数据中生成静态字符串结构,然后哈希(如下所示)可以解决问题吗?
RIPEMD160(RandompRegeneratedFixedNonce:密码:UINT64SINCEEPOCH:128BITBLOCKINDEXNUMBER);
注意:将分配数字并具有常规结构,因此,对于128位消化方案,块0的前64位将用于IVEC,而元素1则用于128位键。
这是一种合理的方法(-.ie,密码范围内安全)吗?
- 编辑:发布接受评论 -
经过一定的反思,我决定将最初认为的密码/盐和nonce/盐合并为16字节(密码词强)键,并使用PKCS#5中概述的技术来衍生多个基于时间的键。不需要盐,因为没有使用密码。
解决方案
有趣的问题。
首先,您的初始向量不必是密码强的随机数量,但是它们 应该 是独特的人均。 IV实际上只是一种盐值,可确保使用相同密钥加密的类似消息不要 看 一旦被加密后类似。您可以使用任何快速的伪随机生成器来生成IV,然后将其与加密数据一起发送(最好是加密的)。
当然,钥匙应该尽可能强大。
在我看来,您可以放大包含nonce,密码和有效性数据的文本字符串的建议,这在我看来是非常合理的 - 它与其他系统使用密码来生成密钥的其他系统所做的事情大致相符。您应该增加多次(不只是一次)来使关键一代计算昂贵(对于试图违反钥匙的任何人来说,这将是一个更大的问题)。
您可能还想查看PKCS#5中规定的关键生成方案(例如 http://www.faqs.org/rfcs/rfc2898.html)在cryptopp中作为密码baseedekeyderivationFunction实现。该机制已经被广泛使用,已知是合理的安全性(请注意,PKCS#5建议至少将密码数据放置至少1000次)。您只需将您的有效期附加和索引数据索引到密码,并使用PasswordBaseadeKeyDerivationFunction在其上。
您没有说您建议使用什么加密算法来加密数据,但我建议您应该选择广泛使用并已知安全的东西……特别是我建议您使用AES。我还建议使用SHA Digest功能之一(也许是密码BasedBased KeyperivationFunction的输入)。 SHA-2是最新的,但是SHA-1足以用于关键生成目的。
您也不说要生成什么关键长度,但是您应该意识到,钥匙中的熵量取决于您使用的密码长度,除非密码是 非常 长期将比理想的键长要少得多。
该方案中最薄弱的链接是密码本身,这总是会限制您可以实现的安全级别。只要您加盐(就像您正在这样做一样),并使关键产生昂贵,以减慢蛮力攻击,就可以了。
其他提示
我需要的是一个确定性的csprng,它的播种是一个随机数和密码,并且可以以索引的方式64位或128位数字块产生。如果我使用数周的“ 1970年1月1日”作为我假设的CSPRNG的索引元素之一,我应该能够构建一个随着时间的流逝而自动更改键的系统。
好吧,我 思考 解决方案的一部分是使用非时代的生成器。这样,如果双方都以相同的种子开头,那么它们都会产生相同的随机流。您可以将“自1970年第1周以来的几周”分层。
为此,您将使用 OFB_mode<T>::Encryption
. 。它可以用作发电机,因为OFB模式使用 AdditiveCipherTemplate<T>
, ,源自 RandomNumberGenerator
.
实际上,crpyto ++在 test.cpp
因此,如果某事失败,则可以再现结果。这是您的使用方式 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
然后将其用作模拟的共享种子。程序的每次运行都会有所不同。在程序的每次运行中,它的打印类似于以下内容:
$ ./cryptopp-test.exe
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
Random: DF3D3F8E8A21C39C0871B375013AA2CD
还有另一个可用的发电机,但它不是加密++库的一部分。它叫 AES_RNG
, ,及其基于AES-256。它仅是标题的实现,您可以在Crypto ++ Wiki下找到它 Randomnumbergenerator.
另请参阅主题 可重复性 为了 RandomNumberGenerator
加密++ Wiki上的课。