0
votes

I am trying to decrypt the encrypted data with two different service providers.

Encryption Algorithm I used is: AES/CTR/PKCS5PADDING (AES Counter Mode with PKCS5Padding)

While doing encryption from other end, they used SunJCE as service provider using Python.

I am trying decrypt the encrypted data (from python) using Bouncy Castle as Provider in Java.

I used the same Key and IV which is used for encrypt.

From my side (while decryption) and from other side (while encryption) have limitation. We both can't change the service providers.

Java's default provider is SunJCE, Since I am using customized JVM version, that does not contain SunJCE libraries. I am able to decrypt the same encrypted data successfully if I configure SunJCE as a provider (Tried with full version of Java in different machine). So I feel, there is no other problem with this code.

Please anyone help to decrypt the SunJCE's encrypted data using Bouncy Castle provider.

Here is the code snippet I used.

java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
IvParameterSpec iv = new IvParameterSpec(initVector);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING", "BC");
// I tried with below line as well. No luck
//Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING", new org.bouncycastle.jce.provider.BouncyCastleProvider());
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] textToDecryptInByte = Base64.toBytes(encrypted);
byte[] decrypted = cipher.doFinal(textToDecryptInByte);
return new String(decrypted);

initVector and key is a byte[] type.

The exception I got while decrypt:

javax.crypto.BadPaddingException: pad block corrupted at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal (Unknown Source, bco=19) at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal (Unknown Source, bco=43) at javax.crypto.Cipher.doFinal (Unknown Source, bco=48)

1
...they used SunJCE as service provider using Python. That doesn't really make sense. "SunJCE" is one of the Sun/Oracle providers for Java cryptography. It has nothing to do with python.President James K. Polk
...Java's default provider is SunJCE.... Well, that's mostly right but it is more complicated that that, mainly due to historical reasons. For example RSA, ECDSA, and DSA keypair generations are each in different providers and not in SunJCE.President James K. Polk
And finally, you haven't provided even a hint of what's not working and you haven't provided the encryption code. Both are critical.President James K. Polk
How was it encrypted? Code please.user207421
@JamesReinstateMonicaPolk, I have edited my question with exception I got. FYI, Solution from Michael Fehr works exactly what I want. Thanks much.Mohamed Farook

1 Answers

3
votes

There is a problem in JCE since many years that AES in mode CTR is working with NOPADDING regardless what you give as parameter. You can find an old thread dated 2007 where the problem is described and two solutions are given - generally use NOPADDING (best choice) or add your own padding on encryption side and strip it of on decryption side.

Here is the link to the thread (see answer of David Hook-4 Nov 25, 2007; 1:06am): http://bouncy-castle.1462172.n4.nabble.com/SunJCE-versus-BouncyCastle-using-AES-CTR-PKCS5Padding-td1465907.html This is the answer: You should use NoPadding though, unless you actually want the padding - as Peter has indicated for most intents and purposes it is completely unnecessary, and NoPadding is what the Sun JCE is producing, regardless of what you request.

Here is a full working sample program that demonstrates the "wrong" padding - on encryption side I'm using PKCS5Padding in JCE while using NOPADDING on decryption part in BC. You change the decryption to JCE by changing AesCtrNoPaddingDecryptBC to AesCtrNoPaddingDecrypt.

/*
* Herkunft/Origin: http://javacrypto.bplaced.net/
* Programmierer/Programmer: Michael Fehr
* Copyright/Copyright: frei verwendbares Programm (Public Domain)
* Copyright: This is free and unencumbered software released into the public domain.
* Lizenttext/Licence: <http://unlicense.org>
* getestet mit/tested with: Java Runtime Environment 8 Update 191 x64
* Datum/Date (dd.mm.jjjj): 19.11.2019 
* Funktion: verschlüsselt einen string im aes ctr modus pkcs5padding mit jce
*           entschlüsselt einen string im aes ctr modus nopadding mit bc
* Function: encrypts a string using aes ctr modus with pkcs5padding using JCE
*           decrypts a string using aes ctr modus nopadding using BC
*
* Hinweis: die JCE arbeitet immer im NOPADDING-Modus, egal was alternativ angegeben ist ! 
* Notice: JCE works always in NOPADDING mode and not in PKCS5PADDING even if named !
* Link: http://bouncy-castle.1462172.n4.nabble.com/SunJCE-versus-BouncyCastle-using-AES-CTR-PKCS5Padding-td1465907.html
* 
* Sicherheitshinweis/Security notice
* Die Programmroutinen dienen nur der Darstellung und haben keinen Anspruch auf eine 
* korrekte Funktion, insbesondere mit Blick auf die Sicherheit ! 
* Prüfen Sie die Sicherheit bevor das Programm in der echten Welt eingesetzt wird.
* The program routines just show the function but please be aware of the security part - 
* check yourself before using in the real world !
*/

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class AesCtrNoPaddingRandomString {

    public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException,
            InvalidAlgorithmParameterException, NoSuchProviderException {
        System.out.println("AES mode CTR PKCS5PADDING or NOPADDING ?");

        Security.addProvider(new BouncyCastleProvider());

        String plaintextString = "HelloWorld12345"; // hier 15 zeichen
        String decryptedtextString = ""; // enthält später den entschlüsselten text
        final byte[] keyByte = "12345678901234567890123456789012".getBytes("UTF-8"); // 32 byte
        // random iv, 16 bytes long
        final byte[] initvectorByte = new byte[16];
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(initvectorByte);

        byte[] plaintextByte = plaintextString.getBytes("UTF-8");
        byte[] ciphertextByte = null;
        byte[] decryptedtextByte = null;

        // encryption
        ciphertextByte = AesCtrPkcs5PaddingEncrypt(plaintextByte, keyByte, initvectorByte);
        // decryption with bouncy castle
        decryptedtextByte = AesCtrNoPaddingDecryptBC(ciphertextByte, keyByte, initvectorByte);
        // decrypted text
        decryptedtextString = new String(decryptedtextByte, "UTF-8");
        // output
        System.out.println("");
        System.out.println("keyByte (hex)          :" + printHexBinary(keyByte));
        System.out.println("initvectorByte (hex)   :" + printHexBinary(initvectorByte));
        System.out.println("plaintextString        :" + plaintextString);
        System.out.println("plaintextByte (hex)    :" + printHexBinary(plaintextByte));
        System.out.println("= = = Encryption AES/CTR/PKCS5PADDING JCE = = =");
        System.out.println("ciphertextByte (hex)   :" + printHexBinary(ciphertextByte));
        System.out.println("= = = Decryption AES/CTR/NOPADDING BC = = =");
        System.out.println("decryptedtextByte (hex):" + printHexBinary(decryptedtextByte));
        System.out.println("decryptedtextString    :" + decryptedtextString);
    }

    public static byte[] AesCtrPkcs5PaddingEncrypt(byte[] plaintextByte, byte[] keyByte, byte[] initvectorByte)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] ciphertextByte = null;
        SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
        IvParameterSpec ivKeySpec = new IvParameterSpec(initvectorByte);
        Cipher aesCipherEnc = Cipher.getInstance("AES/CTR/PKCS5PADDING");
        aesCipherEnc.init(Cipher.ENCRYPT_MODE, keySpec, ivKeySpec);
        ciphertextByte = aesCipherEnc.doFinal(plaintextByte);
        return ciphertextByte;
    }

    public static byte[] AesCtrNoPaddingDecryptBC(byte[] ciphertextByte, byte[] keyByte, byte[] initvectorByte)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
            NoSuchProviderException {
        byte[] decryptedtextByte = null;
        SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
        IvParameterSpec ivKeySpec = new IvParameterSpec(initvectorByte);
        Cipher aesCipherDec = Cipher.getInstance("AES/CTR/NOPADDING", "BC");
        aesCipherDec.init(Cipher.DECRYPT_MODE, keySpec, ivKeySpec);
        decryptedtextByte = aesCipherDec.doFinal(ciphertextByte);
        return decryptedtextByte;
    }

    public static byte[] AesCtrNoPaddingDecrypt(byte[] ciphertextByte, byte[] keyByte, byte[] initvectorByte)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] decryptedtextByte = null;
        SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
        IvParameterSpec ivKeySpec = new IvParameterSpec(initvectorByte);
        Cipher aesCipherDec = Cipher.getInstance("AES/CTR/NOPADDING");
        aesCipherDec.init(Cipher.DECRYPT_MODE, keySpec, ivKeySpec);
        decryptedtextByte = aesCipherDec.doFinal(ciphertextByte);
        return decryptedtextByte;
    }

    public static String printHexBinary(byte[] bytes) {
        final char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }
}

That's the console output:

AES mode CTR PKCS5PADDING or NOPADDING ?

keyByte (hex)          :3132333435363738393031323334353637383930313233343536373839303132
initvectorByte (hex)   :FA61736967A9DE5E86F7ED8F345E0C4D
plaintextString        :HelloWorld12345
plaintextByte (hex)    :48656C6C6F576F726C643132333435
= = = Encryption AES/CTR/PKCS5PADDING JCE = = =
ciphertextByte (hex)   :5385A8F0BEC7FAC14FCC7AA2B04D9B
= = = Decryption AES/CTR/NOPADDING BC = = =
decryptedtextByte (hex):48656C6C6F576F726C643132333435
decryptedtextString    :HelloWorld12345