【问题标题】:BadPaddingException: Given final block not properly padded due to different java versionBadPaddingException:由于 Java 版本不同,给定最终块未正确填充
【发布时间】:2017-04-23 12:27:21
【问题描述】:

我在客户端安装了 java 8,我正在使用以下技术加密我的数据文件

    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    outputStream = new CipherOutputStream(new FileOutputStream(encryptedFile), cipher);

现在我正在按照下面的代码在我安装了 Java 7 的服务器端解密。

Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
inputStream = new CipherInputStream(new FileInputStream(encryptedFile), cipher);
outputStream = new FileOutputStream(decryptedFileName);

这样做给我下面的错误

Caused by: java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115) [jce.jar:1.7.0_71]
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:233) [jce.jar:1.7.0_71]
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:209) [jce.jar:1.7.0_71]

当我在两边都安装了相同的 java 版本 (1.7) 时,相同的代码可以正常工作。 我们如何解决这个问题,以便在不更改任何一方的 java 版本的情况下

【问题讨论】:

标签: java encryption aes badpaddingexception


【解决方案1】:

这个问题有很多可能的原因:

  1. 您没有指定获取/生成密钥的方式。如果您的 JRE 在拥有/缺少 JCE Unlimited Strength Jurisdiction Policies 方面有所不同,则一个将支持 256 位 AES 加密,而另一个将仅支持 128 位。如果您根据可用的密钥长度生成密钥,这可能会导致密钥不匹配。同时,您的两个 Java 7 环境可能都安装了相同级别的策略。

  2. 1234563与NoPadding 结合使用,但即使CBC/PKCS5PaddingCTR/NoPadding 也比通过调用Cipher.getInstance("AES") 获得的默认AES/ECB/PKCS5Padding 更好。
  3. 在持久化密文然后反序列化以进行解密之前,您没有解释如何对密文进行编码。如果没有像十六进制或 Base64 这样的安全编码方案,您可能(阅读:最终会)遇到使用原始二进制值的编码问题。

  4. 一旦您从ECB 更改为另一种操作模式,您将需要为加密和解密提供初始化向量 (IV),并将 IV 与密文一起传输。 IV 不需要以任何方式加密,但对于使用相同密钥加密的每条消息,它必须是唯一且不可预测的。由于它始终是密码的块大小(对于 AES,固定为 16 字节/128 位),只需在密文前面加上 IV 值,然后将其拆分以进行解密。

  5. AES(以及所有对称加密)使用相同的密钥进行加密和解密——不涉及 publicprivate 密钥。这可能只是一个命名问题,但您尝试使用 publicKey 解密的事实可能表明使用了错误的密钥。您应该验证加密密钥和解密密钥是否字节相同(长度相同(16、24 或 32 字节)且相等)。 ECB 如果密文是块大小(16 字节)的精确倍数,“解密”将始终“成功”。然后验证填充。如果您尝试使用错误的密钥解密消息,您通常会(255/256 次)收到填充错误。另一种情况是最后一个字节解密为0x01,这是PKCS #5/#7 的有效填充值,因此它不会检测到填充错误。

证明AES/ECB/PKCS5Padding 是 Java 8 (1.8.0_101) 上的默认值:

@Test
public void testCipherGetInstanceShouldDefaultToECB() throws Exception {
    // Arrange
    final String PLAINTEXT = "This is a plaintext message."
    final SecretKey key = new SecretKeySpec(Hex.decodeHex("0123456789ABCDEFFEDCBA9876543210" as char[]), "AES")

    Cipher unspecified = Cipher.getInstance("AES")
    final Cipher EXPECTED_CIPHER = Cipher.getInstance("AES/ECB/PKCS5Padding")

    unspecified.init(Cipher.ENCRYPT_MODE, key)
    EXPECTED_CIPHER.init(Cipher.DECRYPT_MODE, key)

    // Act
    byte[] cipherBytes = unspecified.doFinal(PLAINTEXT.getBytes(StandardCharsets.UTF_8))
    logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)}")

    // Assert
    byte[] recoveredBytes = EXPECTED_CIPHER.doFinal(cipherBytes)
    String recovered = new String(recoveredBytes, StandardCharsets.UTF_8)
    assert recovered == PLAINTEXT
}

【讨论】:

    猜你喜欢
    • 2015-07-01
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多