【问题标题】:AES: how to generate key from password for every algorithm sizeAES:如何为每种算法大小从密码生成密钥
【发布时间】:2011-11-20 00:49:38
【问题描述】:

是否可以编写一个方法从 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 位后,您可以将结果截断为所需的任何长度。
  • @bdares 如果我使用 256 位哈希的一部分来获得 128 位或 192 位的密钥,那么两个不同的密码可能会生成相同的截断密钥。
  • 那,唉,太真实了。不幸的是,无限数量的密码可以使用散列函数生成相同的密钥。你只需要安慰一下,故意这样做真的很难。
  • 每个位都很难预测,因此仅预测和碰撞前 128 位、低 128 位或其他所有位同样困难(每位)。这就是为什么它是加密哈希的理想属性。如果您认为从攻击者的角度来看它们实际上是随机的,那么随机数字集的子集仍然是随机的,并且与另一个更小、不同生成的随机数字集一样好。
  • @MisterSmith "那么两个不同的密码可能会生成相同的截断密钥" 这不太可能。如果你关心这样的几率,为什么不假设你的对手可以通过随机尝试 128 位数字来找到 128 位密钥呢? ;)

标签: java encryption aes


【解决方案1】:

如果可以,不要这样做。用户选择的密码通常具有非常差的熵

如果“密码”不是用户选择的,而是由密码学强 RNG 生成的,请使用密码或密码的哈希值。在这种情况下,您不需要 PBKDF2。

PBKDF2 确实是最后的解决方案。

另请阅读Lessons learned and misconceptions regarding encryption and cryptology

【讨论】:

  • 我必须从用户选择的任意长度密码中派生出一个密钥。我有两个选择:截断 256 位哈希,或使用预定义的盐应用 PBKDF2(用户不键入盐,因此它必须是应用程序代码中的常量)。我对第二个选项感觉更好。
  • 我必须包含盐,因为没有其他方法可以创建具有给定密钥长度的新 PBEKeyspec 实例。
  • 什么鬼? PBKDF2 在其操作中使用哈希。我不知道为什么当简单的散列不是时它是“最后的手段”:S 你可能想阅读它的定义。
  • 对不起,我误解了。你在那里叫密码,我只是叫钥匙。
  • @Ivo 我的意思是使用密码来制作密钥是最后的解决方案,因为密码通常具有较差的熵,并且使用密码作为密钥会使密码受到离线攻击。跨度>
【解决方案2】:

将 256 位长度的密钥截断为所需的大小。密钥应该是随机的,或者使用安全方法(例如 PBKDF2)生成。如果有疑问,请在截断之前散列以获得更多长度/均匀随机分布。

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

【讨论】:

  • 请阅读下面我的回答,了解我现在的疑问。
  • 请描述 PBKDF2 如何“安全”。你认为它“安全”是因为它很慢吗?
  • @curiousguy,我将其用于程序员想出的许多自定义非安全方式从密码中获取密钥。
  • @Ivo PBKDF2 没有魔法,它是数学函数。如果您从低熵密码中推断出加密密钥,那么您的密钥将具有低熵。没有办法解决这个问题。
猜你喜欢
  • 2018-05-31
  • 1970-01-01
  • 2017-12-26
  • 2015-03-13
  • 2014-06-15
  • 1970-01-01
  • 2012-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多