Skip to Main Content

Java Security

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Encryption working but decryption giving error "pad block corrupted"

843811May 11 2009 — edited May 2 2010
I have to decrypt an image in java which is encrypted in .NET using Rijndael Algorithm. I am using AES algorithm to decrypt on java.

Encryption code in .NET:
public void EncryptFile(string inFile, string outFile, string password)
        {
            using (FileStream fin = File.OpenRead(inFile),
                      fout = File.OpenWrite(outFile))
            {
                long lSize = fin.Length; 
                int size = (int)lSize;  
                byte[] bytes = new byte[BUFFER_SIZE]; 
                int read = -1; 

                byte[] IV = GenerateRandomBytes(16);
                byte[] salt = GenerateRandomBytes(16);

                // create the crypting object
                SymmetricAlgorithm sma = CreateRijndael(password, salt);
                sma.IV = IV;

                // write the IV and salt to the beginning of the file
                fout.Write(IV, 0, IV.Length);
                fout.Write(salt, 0, salt.Length);

                // create the hashing and crypto streams
                HashAlgorithm hasher = SHA256.Create();
                using (CryptoStream cout = new CryptoStream(fout, sma.CreateEncryptor(), CryptoStreamMode.Write),
                          chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write))
                {
                    // write the size of the file to the output file
                    BinaryWriter bw = new BinaryWriter(cout);
                    bw.Write(lSize);

                    // write the file cryptor tag to the file
                    bw.Write(FC_TAG);

                    // read and the write the bytes to the crypto stream in BUFFER_SIZEd chunks
                    while ((read = fin.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        cout.Write(bytes, 0, read);
                        chash.Write(bytes, 0, read);
                        //value += read;
                    }
                    chash.Flush();
                    chash.Close();

                    // read the hash
                    byte[] hash = hasher.Hash;

                    // write the hash to the end of the file
                    cout.Write(hash, 0, hash.Length);

                    cout.Flush();
                    cout.Close();
                }
            }
        }

// Creates a Rijndael SymmetricAlgorithm for use in EncryptFile and DecryptFile
        private SymmetricAlgorithm CreateRijndael(string password, byte[] salt)
        {
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, salt, "SHA256", 1000);

            SymmetricAlgorithm sma = Rijndael.Create();
            sma.KeySize = 256;
            sma.Key = pdb.GetBytes(32);
            sma.Padding = PaddingMode.PKCS7;
            return sma;
        }


        private byte[] GenerateRandomBytes(int count)
        {
            byte[] bytes = new byte[count];
            rand.GetBytes(bytes);
            return bytes;
        }
Decryption code in java:
public static void decryptImageUsingRijndaelAlgorithm(){
		try{
			byte[] iv = new byte[]
          		{
          		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
          		};

      		AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			//Security.addProvider(new com.sun.crypto.provider.SunJCE());
			SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");  
		    byte[] salt = new byte[16];  
		    rand.nextBytes(salt);  
		    PBEKeySpec password = new PBEKeySpec("Bbbbb1234".toCharArray(), salt, 1000, 128);  
		    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");  
		    PBEKey pkey = (PBEKey) factory.generateSecret(password);  
		    SecretKey key = new SecretKeySpec(pkey.getEncoded(), "AES");			
		    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
		    //Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
		    System.out.println("Cipher provider: " + cipher.getProvider());

		    //AES Decryption
		    File encryptedImage = new File("c:/EncryptDecrypt/AESencrypted.jpg");
			byte[] encryptedImageBytes = new byte[(int)encryptedImage.length()];
			DataInputStream dis = new DataInputStream(new FileInputStream(encryptedImage));
			dis.readFully(encryptedImageBytes);
		    //cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
			cipher.init(Cipher.DECRYPT_MODE, key);
		    byte[] decrypted = cipher.doFinal(encryptedImageBytes);		    
		    FileOutputStream desrOut = new FileOutputStream("c:/EncryptDecrypt/AESDecryptedJAVA.jpg");		    
		    desrOut.write(decrypted);
		    dis.close();					
			desrOut.close();
		} 
		catch(Exception e){
			e.printStackTrace();
		}
	}
When its decrypting, the cipher.doFinal(encryptedImageBytes) is giving the following exception

javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(DashoA12275)

I also tried with PKCS5 and PKCS7 padding. And also used BouncyCastleProvide and SunJCE provider.

Any help will be appreciated.

Thanks.

Comments

843811
As you have it, this can't possibly work. To start with, the decryption key has a random component so how can it have the same value as is used to encrypt the data.

I have experience at doing this sort of encryption and decryption. I found that the most important thing is to make sure one understands exactly what process is being used in generating the keys from the password and to make sure the key, iv, block mode and padding are the same on both sides before even thinking about decryption.
843811
I removed the random component from the code. But still I am getting the same error.

Modified code on .NET:
public void EncryptFile(string inFile, string outFile, string password)
        {
            using (FileStream fin = File.OpenRead(inFile),
                      fout = File.OpenWrite(outFile))
            {
                long lSize = fin.Length; 
                int size = (int)lSize;  
                byte[] bytes = new byte[BUFFER_SIZE]; 
                int read = -1;

                byte[] IV = new byte[16]; 
                byte[] salt = new byte[16];

                // create the crypting object
                SymmetricAlgorithm sma = CreateRijndael(password, salt);
                sma.IV = IV;

                // write the IV and salt to the beginning of the file
                fout.Write(IV, 0, IV.Length);
                fout.Write(salt, 0, salt.Length);

                // create the hashing and crypto streams
                HashAlgorithm hasher = SHA256.Create();
                using (CryptoStream cout = new CryptoStream(fout, sma.CreateEncryptor(), CryptoStreamMode.Write),
                          chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write))
                {
                    // write the size of the file to the output file
                    BinaryWriter bw = new BinaryWriter(cout);
                    bw.Write(lSize);

                    // write the file cryptor tag to the file
                    bw.Write(FC_TAG);

                    // read and the write the bytes to the crypto stream in BUFFER_SIZEd chunks
                    while ((read = fin.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        cout.Write(bytes, 0, read);
                        chash.Write(bytes, 0, read);
                        //value += read;
                    }
                    chash.Flush();
                    chash.Close();

                    // read the hash
                    byte[] hash = hasher.Hash;

                    // write the hash to the end of the file
                    cout.Write(hash, 0, hash.Length);

                    cout.Flush();
                    cout.Close();
                }
            }
        }

       // Creates a Rijndael SymmetricAlgorithm for use in EncryptFile and DecryptFile
        private SymmetricAlgorithm CreateRijndael(string password, byte[] salt)
        {
            PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, salt, "SHA256", 1000);

            SymmetricAlgorithm sma = Rijndael.Create();
            sma.KeySize = 128;
            sma.Padding = PaddingMode.PKCS7;
            return sma;
        }
Decryption Code on JAVA:
public static void decryptImageUsingRijndaelAlgorithm(){
		try{
			byte[] iv = new byte[]
          		{
          		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
          		};

      		AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			//Security.addProvider(new com.sun.crypto.provider.SunJCE());			
		    byte[] salt = new byte[16];  
		    PBEKeySpec password = new PBEKeySpec("Bbbbb1234".toCharArray(), salt, 1000, 128); 
		    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");  
		    PBEKey pkey = (PBEKey) factory.generateSecret(password);  
		    SecretKey key = new SecretKeySpec(pkey.getEncoded(), "AES");	
		    
		    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
		    //Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
		    System.out.println("Cipher provider: " + cipher.getProvider());		

		    //AES Decryption		    
		    //File encryptedImage = new File("c:/EncryptDecrypt/EncryptDecrypt/encryptedImageNET.jpg");
	        File encryptedImage = new File("c:/EncryptDecrypt/encryptedImageNET.jpg");
			byte[] encryptedImageBytes = new byte[(int)encryptedImage.length()];
			DataInputStream dis = new DataInputStream(new FileInputStream(encryptedImage));
			dis.readFully(encryptedImageBytes);
		    //cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
			cipher.init(Cipher.DECRYPT_MODE, key);
		    byte[] decrypted = cipher.doFinal(encryptedImageBytes);		    
		    //FileOutputStream desrOut = new FileOutputStream("c:/EncryptDecrypt/EncryptDecrypt/AESDecryptedJAVA.jpg");	
		    FileOutputStream desrOut = new FileOutputStream("c:/EncryptDecrypt/decryptedImageJAVA.jpg");
		    desrOut.write(decrypted);
		    dis.close();					
			desrOut.close();
		} 
		catch(Exception e){
			e.printStackTrace();
		}
	}
	
843811
1) Your PasswordDeriveBytes is using sha256. In Java you create a SecretkeyFactory is using sha1.
2) On encryption you write the IV and salt unencrypted to the output but you never read them in the Java.
3) On encryption you write the hash of the data to the output at the end. On decryption you never process this hash and you don't compute the hash of the decrypted date and to a comparison with the encrypted value.
4) On encryption you specify an IV which means you are using one of the feedback block modes. In Java you are using ECB mode where an IV is not required. I seem to remember that the default in C# is CBC so the Java should at least use the same block mode.

There is almost certainly more wrong than just these 4 items but please please stop trying to run and start walking. You first need to make sure you have like-for-like between the C# and Java in terms of key bytes, block mode, padding, key generation algorithm, iteration count etc etc etc.
843811
Hi -

Did you get an answer for your question. In fact we are in the same boad as we have to decrypt a string that is encrypted in .net using Rijndael.

We have to use Rijndael in java to decrypt the same.

Please help if you have alrady solved your issue.

Thanks,
Venkat
EJP
Did you get an answer for your question.
Yes
In fact we are in the same boad
Boat?
as we have to decrypt a string that is encrypted in .net using Rijndael.
If you mean a java.lang.String, that's your first mistake. Use a byte[]. String is not a container for binary data.
1 - 5
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on May 30 2010
Added on May 11 2009
5 comments
5,368 views