代码之家  ›  专栏  ›  技术社区  ›  Hassan Syed

确定地生成密码安全密钥和IVEC

  •  12
  • Hassan Syed  · 技术社区  · 14 年前

    背景

    我正在设计一个系统,它可以为静态Web内容的用户开发动态认证方案。其动机是预先生成大量复杂而敏感的Web内容,然后静态地为其提供基于cookie(嵌入可逆加密信息)的身份验证,由Web服务器单独实施。使用AEAD模式加密原语。

    问题

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

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

    我正在考虑的方法

    现在我在cryptopp中看不到这样的功能,或者我现在对这个术语已经足够了解了,而且由于cryptopp是目前最先进的加密库,我没有信心找到另一个。所以,如果我在那里找不到实现,我应该自己开始。从具体化的数据中生成静态字符串结构,然后对其进行散列(如下所示)会有什么效果吗?

    ripemd160(randompregendfixednonce:passphrase:uint64 sinepoch:128位块索引号);

    注:块号将被分配并具有规则结构,因此,例如对于128位摘要,块0的前64位将用于IVEC,元素1的所有部分将用于128位密钥。

    这是一种可靠的方法吗(即密码安全)?

    --编辑:发布接受评论--

    经过一些思考,我决定将我最初认为的密码短语和nonce/salt合并到一个16字节(密码学强)密钥中,并使用pkcs 5中概述的技术来派生多个基于时间的密钥。不需要盐,因为没有使用密码。

    2 回复  |  直到 9 年前
        1
  •  4
  •   dajames    14 年前

    有趣的问题。

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

    当然,钥匙应该尽可能结实。

    在我看来,您对包含nonce、密码短语和有效性数据的文本字符串进行哈希处理的建议是非常合理的——这与使用密码短语生成密钥的其他系统所做的操作大致一致。为了使密钥生成的计算成本更高(对于任何试图强行使用密钥的人来说,这将是一个比对您更大的问题),您应该多次(而不仅仅是一次)散列。

    您可能还需要查看pkcs 5中规定的密钥生成方案(例如 http://www.faqs.org/rfcs/rfc2898.html )它在Cryptopp中实现为密码基密钥派生函数。这种机制已经被广泛使用,并被认为是合理的安全机制(请注意,pkcs 5建议对密码短语数据进行至少1000次哈希处理)。您只需将您的有效期和索引数据附加到密码短语中,并按原样使用PasswordBasedKeyDerivationFunction。

    你没有说你打算用什么加密算法来加密数据,但我建议你应该选择一些广泛使用并且已知是安全的…尤其是我建议你使用AES。我还建议使用sha摘要函数之一(可能作为passwordbasedKeyDerivationFunction的输入)。sha-2是当前的,但sha-1足以用于密钥生成。

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

    这个方案中最薄弱的环节就是密码本身,这总是会限制您可以实现的安全级别。只要您盐渍您的数据(如您所做的),使密钥生成成本高昂,以减缓暴力攻击,您应该是好的。

        2
  •  1
  •   jww avp    9 年前

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

    嗯,我 认为 部分解决方案是使用非基于时间的生成器。这样,如果双方从相同的种子开始,那么它们都会产生相同的随机流。你可以把你的“1970年第1周以来的几周”逻辑放在上面。

    要做到这一点,你需要 OFB_mode<T>::Encryption . 它可以用作发电机,因为B模式使用 AdditiveCipherTemplate<T> ,源自 RandomNumberGenerator .

    实际上,crpyto++在 test.cpp 所以如果有什么失败的话,结果可以被复制。以下是您将如何使用 OFB_模式:加密 . 它也适用于 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
    

    有另一个生成器也可以这样做,但它不是Crypto++库的一部分。它叫 AES_RNG ,基于AES-256。它是一个只包含头部的实现,您可以在crypto++wiki的 RandomNumberGenerator .

    另请参见主题 Reproducibility 对于 随机数发生器 在crypto++wiki上初始化。