【问题标题】:Cipher.doFinal() not throwing exception when invalid key used使用无效密钥时,Cipher.doFinal() 不会引发异常
【发布时间】:2016-03-22 01:55:38
【问题描述】:

我有一些解密代码期望 Cipher.doFinal() 在使用不正确的密钥/iv 时抛出异常。这似乎没有发生。嗯,确实会发生,但并非总是如此。

我的加密使用当前时间的“秒”作为 Random() 类的种子。然后它使用 16 个(伪)随机值,以 256 为模,生成一个 16 字节的密钥。它使用此密钥进行加密。它对 IV 使用相同的字节数组。我正在按如下方式初始化密码:

Cipher.getInstance("AES/CBC/ISO10126Padding");

解密使用相同的逻辑循环遍历所有可能的 60 秒值 (0 - 59) 以生成密钥和 IV。对于每个密钥和 IV,它都会尝试解密加密的值。我通常会抛出一些 BadPaddingException,但大多数时候它会在不正确的“第二个”值上成功。正如预期的那样,我得到了垃圾返回。我期待 doFinal() 在使用错误的键/iv 时总是抛出异常。有什么理由不这样做吗?

举个例子:

如果我加密时当前秒为 45,它将使用该值生成密钥/iv。当我尝试解密时,我坐在一个从 0 到 59 的 for 循环中,尝试每个值,直到 doFinal() 成功(例如,不抛出异常)。我通常会看到一些 BadPaddingException,但循环将在 45 之前结束,并且我会返回垃圾。

我确实找到了这个:

Java AES decryption detect incorrect key

这似乎是相关的,虽然我没有使用密码流。

【问题讨论】:

  • 根据我的计算,只有 6% 的错误键应该使用 ISO10126Padding 产生垃圾。其他 94% 应该导致 BadPaddingException。是你看到的还是你的结果不同?

标签: java encryption


【解决方案1】:

解密本身无法检测到不正确的密钥,结果只是垃圾。这是一个常见的误解,它将加密与身份验证混为一谈。

这就是为什么使用婴儿床来暴力破解加密,所以人们可以从不正确的加密中分辨出正确与否,请参阅Bletchley Park 如何破解德国加密并需要婴儿床。婴儿床是确定解密可能正确/不正确的某种方式。

有时,如果使用填充,填充会出错,并且一些(但所有)实现会返回错误。这实际上是一种安全违规,它通过填充泄漏信息。这是婴儿床的一种形式。

如果您想验证加密,您需要提供一些其他方法,例如添加数据的哈希值以进行验证。

【讨论】:

  • 可能还值得一提的是,这是一种极其不安全的密钥生成方法
  • pvg:我认为这种加密方式存在问题,但如果有人无权访问代码,因此无法重新设计,你是说他们会更轻松比其他 128 位密钥解密?如果有,为什么?
  • 真正可怕的是密钥生成,Random():“如果使用相同的种子创建两个Random实例,并且方法调用的相同序列是为每一个,它们将生成并返回相同的数字序列”。种子是秒,也就是 60 个种子值。相反,只需从 SecureRandom 等加密安全随机数生成器中获取 16 个字节。
  • 安全加密很难。容易犯一些会降低或消除安全性的小错误。建议:如果您想要安全的实施,请让密码领域专家(又名“卑鄙的 SME”)来帮助和审查设计。
  • zaph:我指望 Random() 将为同一个种子生成相同的(伪)随机数集。这允许解密逻辑生成与加密生成的密钥匹配的密钥。
猜你喜欢
  • 1970-01-01
  • 2011-09-27
  • 2019-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 2013-02-15
相关资源
最近更新 更多