-1

I java 8 installed on client side where I am encrypting my data file using the below technique

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

And now i am decrypting on server side where i have Java 7 installed as per the code below.

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

Doing so give me below error

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]

Same code works fine when i have same java version (1.7) installed on both side. How can we fix this so that without changing the java version either of the side

Chunkyy Garg
  • 107
  • 1
  • 5
  • Possible duplicate of [Java 7 -> Java 8: AES Causes exception: "BadPaddingException: Given final block not properly padded" in conjunction with BufferedReader & ZipStreams](http://stackoverflow.com/questions/27124931/java-7-java-8-aes-causes-exception-badpaddingexception-given-final-block) – Robby Cornelissen Dec 08 '16 at 09:58
  • 1
    Post your I/O code. – user207421 Jan 07 '17 at 03:18

1 Answers1

0

There are a number of possible causes for this issue:

  1. You don't specify how you are getting/generating the key. If your JREs differ in their possession/absence of the JCE Unlimited Strength Jurisdiction Policies, one will support 256-bit AES encryption and the other will only support 128-bit. If you are generating a key based on the available key lengths, this could be causing the keys not to match. Meanwhile, both of your Java 7 environments may have the same level policies installed.

  2. You are not specifying the block cipher mode of operation or padding scheme on either side of the system -- I recommend an AEAD mode like GCM, EAX, or CCM (CTR + CBC-MAC) in conjunction with NoPadding, but even CBC/PKCS5Padding or CTR/NoPadding are better than the default AES/ECB/PKCS5Padding that you will get just by invoking Cipher.getInstance("AES").

  3. You don't explain how you are encoding the cipher text before persisting it and then deserializing it for decryption. Without a safe encoding scheme like hexadecimal or Base64, you may (read: eventually will) encounter encoding issues working with raw binary values.

  4. Once you change from ECB to another mode of operation, you will need to provide the initialization vector (IV) for both encryption and decryption, and transmit the IV alongside the cipher text. The IV does not need to be encrypted in any way, but it must be unique and non-predictable for each message encrypted with the same key. As it is always the block size of the cipher (fixed at 16 bytes/128 bits for AES), simply prepend the cipher text with the IV value and then split it for decryption.

  5. AES (and all symmetric cryptography) uses the same key for encryption and decryption -- there are no public and private keys involved. It could just be a naming issue, but the fact that you are trying to decrypt with publicKey may indicate the wrong key being used. You should verify that both the encryption and decryption keys are byte-identical (same length (16, 24, or 32 bytes) and equal). ECB "decryption" will always "succeed" if the cipher text is an exact multiple of the block size (16 bytes). Then the padding is verified. If you attempt to decrypt a message with the wrong key, you will often (255/256 times) get a padding error. The other case is that the last byte decrypts to 0x01, which is a valid padding value for PKCS #5/#7, so it won't detect a padding error.

Demonstration that AES/ECB/PKCS5Padding is the default on 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
}
Andy
  • 13,916
  • 1
  • 36
  • 78