-1

我在客户端安装了 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 版本的情况下

4

1 回答 1

0

此问题有多种可能的原因:

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

  2. 您没有在系统的任一侧指定分组密码操作模式或填充方案——我建议使用AEAD模式,如GCM,EAXCCM(CTR + CBC-MAC) 与您只需调用.NoPaddingCBC/PKCS5PaddingCTR/NoPaddingAES/ECB/PKCS5PaddingCipher.getInstance("AES")

  3. 您没有解释如何在持久化密文然后对其进行反序列化以进行解密之前对其进行编码。如果没有像十六进制或 Base64 这样的安全编码方案,您可能(阅读:最终会)遇到使用原始二进制值的编码问题。

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

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

AES/ECB/PKCS5PaddingJava 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
}
于 2017-01-07T02:36:07.457 回答