AES:如何为每个算法大小从密码生成密钥

3

有没有可能编写一个单独的方法,从密码中生成AES-128、AES-192和AES-256的有效密钥?

我在思考这样的实现:

    SecretKeyFactory f;
    try {
        f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    } catch (NoSuchAlgorithmException e) {
        throw new Exception("Key derivation algorithm not available.", e);
    }
    KeySpec ks = new PBEKeySpec(password.toCharArray());
    SecretKey s;
    try {
        s = f.generateSecret(ks);
    } catch (InvalidKeySpecException e) {
        throw new Exception("Key generation failed.", e);
    }
    Key k = new SecretKeySpec(s.getEncoded(),"AES");

我使用了类似的方法来生成AES-256加密的盐值密钥。然而,现在我需要仅通过密码(没有盐和迭代)生成密钥,并且我需要它们适用于AES-128、AES-192和AES-256。我的问题是,这段代码返回与每个AES-XXX大小兼容的密钥,还是我应该为每个大小编写不同的代码?
另外,是否有更好的(从安全或简单性方面考虑)方法从密码生成密钥?
更新:最终我进行了一些测试,结果发现这个构造函数:
KeySpec ks = new PBEKeySpec(password.toCharArray());

这个块总是抛出一个InvalidKeySpecException异常:

try {
    s = f.generateSecret(ks);
} catch (InvalidKeySpecException e) {
    throw new Exception("Key generation failed.", e);
}

所以我只能使用另一个构造函数,该函数需要一个盐作为参数:

KeySpec ks = new PBEKeySpec(password.toCharArray(), "somepredefinedsalt".getBytes(), numIters, keySizeInBits);

由于我没有盐值,所以我考虑硬编码一个预定义的盐值。现在我不知道哪个选项更安全,是编写一个预定义的盐值并使用PBKDF2呢,还是使用截断哈希。


一种加盐、长度加长的哈希算法非常强大。在生成256位后,您可以将结果截断为所需的任何长度。 - user684934
如果我使用256位哈希的一部分来获取128位或192位的密钥,那么两个不同的密码可能会生成相同的截断密钥。 - Mister Smith
2
每个比特都很难预测,因此预测和碰撞只是最高的128位、最低的128位或每个其他比特一样困难(每个比特)。这就是为什么它是密码哈希的一个理想属性。如果你考虑到从攻击者的角度来看,它们实际上是随机的,那么一个随机集合的子集仍然是随机的,并且与另一个更小、不同生成的随机数字集合一样好。 - user684934
1
如果两个不同的密码可以生成相同的截断密钥,那么这种情况非常罕见。如果您关心这样的概率,为什么不假设您的对手可以通过随机尝试128位数字来找到128位密钥呢?;) - curiousguy
@curiousguy 一个安全的哈希函数,例如SHA-256,需要2^256时间来进行暴力破解。(现在可能更接近于2^254,我听说有一种攻击可以将复杂度降低2位。)然而,如果您准备了彩虹表(理论上可能),则可以在恒定时间内破解散列密码。因此,您为每个密码构造一个唯一的盐,并以明文形式存储它。根本不需要传输它。 - user684934
显示剩余12条评论
2个回答

4
如果可以的话,请不要这样做。 用户选择的密码通常具有非常差的熵
如果“密码”不是用户选择的,而是由密码学强的RNG生成的,请使用密码或密码的哈希值。在这种情况下,您不需要PBKDF2。
PBKDF2实际上是最后的解决方案。
请还阅读有关加密和密码学的教训和误解

我必须从用户选择的任意长度的密码中派生一个密钥。我有两个选项:截断256位哈希或应用具有预定义盐的PBKDF2(用户不输入盐,因此它必须是应用程序代码中的常量)。我对第二个选项更有信心。 - Mister Smith
我必须包含盐,因为没有其他方法可以使用给定的密钥长度创建新的PBEKeyspec实例。 - Mister Smith
什么鬼?PBKDF2在其操作中使用哈希。我不知道为什么它是“最后的手段”,当简单哈希不是的时候:S 你可能需要阅读一下它的定义。 - Ivo
抱歉,我误解了。你所称之为密码的东西,在我看来只是一个密钥。 - Ivo
@Ivo 我的意思是使用密码生成密钥是最后的解决方案,因为密码通常熵值较低,将其用作密钥会暴露密码并遭受离线攻击。 - curiousguy

0

将256位长度的密钥截断为所需大小。密钥应该是随机的,或者使用诸如PBKDF2之类的安全方法生成。如果不确定,请在截断之前进行更长/均匀随机分布的哈希处理。

您还可以看到PBEKeySpec允许您可选地指定密钥长度。


请阅读下面我的答案,以了解我现在的疑惑是什么。 - Mister Smith
请描述PBKDF2如何“安全”。您是否认为它之所以“安全”是因为它运行缓慢? - curiousguy
@curiousguy,我使用这个词来描述程序员从密码中派生密钥的许多自定义非安全方式。 - Ivo
@Ivo PBKDF2并不是什么神奇的东西,它只是一个数学函数。如果你从一个低熵密码中推导出一个加密密钥,那么你的密钥将具有低熵。这是无法避免的。 - curiousguy

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