Newbie in java cryptography : BadPaddingException
Hi everyone,
I m just trying ton encrypt a specific part of a file. I made a test class (very bad I know I just want to test the encryption) but I'm not able to decrypt the buffer once encrypted, I get a pad block corrupted (BadPaddingException)
I'm using DES, but I would like to use AES instead, but Java Encryption is quiet new for me. I tryed DES with ECB or CBC and I still get these Exception while decrpyting.
I'll be happy if someone could help me.
Here is my dirty code :
import java.io.*;
import java.util.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
publicclass Essai2{
publicstaticvoid main(String []args){
Key key;
KeyGenerator keyGen;
Cipher encrypt, decrypt;
Security.addProvider(new BouncyCastleProvider());
try{
// File to crypt
File f =new File("test2.mp3");
byte[] buffer =newbyte[(int)f.length()];
DataInputStream in =new DataInputStream(new FileInputStream(f));
in.readFully(buffer);
in.close();
String s ="";
/*Retrieving the TAG
for(int i= buffer.length-128;i<buffer.length;i++){
s += (char)(buffer[i]);
}
System.out.println(s);
*/
keyGen = KeyGenerator.getInstance("DES","BC");
keyGen.init(new SecureRandom());
key = keyGen.generateKey();
byte[] iv ={ (byte) 0xc9, (byte) 0x36, (byte) 0x78, (byte) 0x99,
(byte) 0x52, (byte) 0x3e, (byte) 0xea, (byte) 0xf2};
IvParameterSpec ivp =new IvParameterSpec(iv);
encrypt = Cipher.getInstance("DES/CBC/PKCS5Padding","BC");
encrypt.init(Cipher.ENCRYPT_MODE, key; ivp);
byte[] buf_crypt = encryptPart(buffer, buffer.length-128, buffer.length-1, encrypt);
FileOutputStream envfos =new FileOutputStream("test_chiffre.mp3");
envfos.write(buf_crypt);
envfos.close();
decrypt = Cipher.getInstance("DES/CBC/PKCS5Padding","BC");
decrypt.init(Cipher.DECRYPT_MODE, key, ivp);
byte[] buf_decrypt = decryptPart(buf_crypt, buffer.length-128, buffer.length-1, decrypt);
envfos =new FileOutputStream("test_dechiffre.mp3");
envfos.write(buffer);
envfos.close();
}catch (Exception e){
e.printStackTrace();
}
}
publicstaticbyte[] encryptPart(byte[] buffer,int beg,int end, Cipher encrypter){
byte[] toencrypt =newbyte[(end - beg)+1];
byte[] encrypted =newbyte[(end - beg) +1];
//array copy
int j = beg;
for(int i=0; i>< (end -beg)+1 ; i++){
System.out.println("i = " + i +" j = " + j);
toencrypt[i] = buffer[j];
j++;
}
try{
encrypted = encrypter.doFinal(toencrypt);
}
catch(Exception e){e.getMessage(); e.printStackTrace();}
j=0;
for(int i=beg; i<= end; i++){
buffer[i] = encrypted[j];
j++;
}
return buffer;
}
publicstaticbyte[] decryptPart(byte[] buffer,int beg,int end, Cipher decrypter){
byte[] todecrypt =newbyte[(end - beg)+1];
byte[] decrypted =newbyte[(end - beg) +1];
//array copy
int j = beg;
for(int i=0; i< (end -beg)+1 ; i++){
System.out.println("i = " + i +" j = " + j);
todecrypt[i] = buffer[j];
j++;
}
try{
decrypted = decrypter.doFinal(todecrypt);
}
catch(Exception e){e.getMessage(); e.printStackTrace();}
j=0;
for(int i=beg; i<= end; i++){
buffer[i] = decrypted[j];
j++;
}
return buffer;
}
}
Message was edited by:
Maxime_V
[7487 byte] By [
Maxime_Va] at [2007-10-2 21:23:46]

This looks very wrong!
byte[] buf_decrypt = decryptPart(buf_crypt, buffer.length-128, buffer.length-1, decrypt);
You hve encrypted the last 128 bytes of an mp3 file to a byte array referenced by 'buf_crypt'. Since all the byte of 'buf_crypt' matter teh I would expect you to decrypt using
byte[] buf_decrypt = decryptPart(buf_crypt,0, buf_crypt.length, decrypt);
Also, in method encryptPart() the space allocated by
byte[] encrypted = new byte[(end - beg) +1];
is never used because it is replaced by the bytes generated by the cipher.doFinal() in
decrypted = decrypter.doFinal(todecrypt);
You seem to be suffering under two misconceptions. First, a Java misconception, that the cipher.doFinal() method copies bytes into an existing array when all it does is return an array of bytes. And second, an encryption misconception, that the number of encrypted bytes is the same as the number of plane text bytes. Using PKCS5Padding this is never the case.
> And second, an encryption misconception, that the
> number of encrypted bytes is the same as the number
> of plane text bytes. Using PKCS5Padding this is never
> the case.
Thank you for your explanation :) I knew I made stupid mistakes, but I'm learning actually. So what I would like to know now, is how to get the same number of encrypted bytes, as the number of plane text bytes ? What kind of Padding should I use ? My future goal is to encrypt some part of MP3 frames, so if I can find a way to just encrypt some parts of a buffer, it could help me a lot !
Thank you !
> > And second, an encryption misconception, that the
> > number of encrypted bytes is the same as the
> number
> > of plane text bytes. Using PKCS5Padding this is
> never
> > the case.
>
> Thank you for your explanation :) I knew I made
> stupid mistakes, but I'm learning actually. So what I
> would like to know now, is how to get the same number
> of encrypted bytes, as the number of plane text bytes
> ?
You could use a stream cipher such as RC4 but ...
> What kind of Padding should I use ?
since you are encrypting 128 bytes which is an exact multiple of the block length then you could use NoPadding.
> My future goal
> is to encrypt some part of MP3 frames, so if I can
> find a way to just encrypt some parts of a buffer,
>
I assume that you want to encrypt just the tags of an mp3 files. On earlier mp3 files these were indeed stored in the last 128 bytes of the file but this is not the case as of IDV3v2.3 so your code will only work on old mp3 files!
It is rare to find a need to encrypt just a small part of a file. Just out of interest what do you expect to gain by doing this.
Actually I'm trying to encrypt the TAG just to testing encryption, this is not my final goal. My final goal is to encrypt some par of each mp3 frame (38 frames per second ) in order to do a selective encryption of MP3 files (encrypt less thant 10% would be acceptable ). Selective encryption consums less ressources and it could be something efficient for small devices. That's why I'm actually trying to understand how works the encryption using Java, and after I will try to apply my knowledges to encrypt some parts of the MP3 frames. So it will not be 128 bits, and I don't think I will encrypt multiple of 16 or 32 bits :(
Thank you for your help !
Thanks for the explanation. I have spent some time looking at the MP3 specification thinking in terms of producing a better Java implementation than JLayer but I decided thet task would require more time than I am willing to give it. If you are going to add to the basic MP3 complexity by encrypting some part of the frame then I suspect you have a big project.
I wish you the very best of luck with this.
Sabre
So I changed some part and now I can encrypt and decrypt the Tag without problem, but I still have some questions :
- How could I chose a good IV for AES CBC mode ? Does the IV choice matter ?
- How could I get a key in a secure way ? If I try to get a key with : //key = keyGen.generateKey(); I get an Wrong KeySize Exception... So I have a blank key, but it works ;)
and last question : I'm using AES in CBC mode with No Padding, so I dont have problem to encrypt 128 bytes, but if I take a random number; it doesn't work. So I should encrypt a number of byte which is a multiple of 16 (because 16*8 = 128 ) ? I really want to use AES in CBC mode, so I think I could slipt the data I want to encrypt in buffer of a good size. I want that the encrypted content has the same size as the decrypted one !
So I copy here my code, but don't pay attention, I m just trying the encryption ;) When I ll have understand what I'm needing, I could begin to code something in a better way :)
import java.io.*;
import java.util.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class Essai2 {
public static void main(String []args){
Key key;
KeyGenerator keyGen;
Cipher encrypt, decrypt;
Security.addProvider(new BouncyCastleProvider());
try {
// Fichier ?chiffrer
File f = new File("test2.mp3");
byte[] buffer = new byte[(int)f.length()];
DataInputStream in = new DataInputStream(new FileInputStream(f));
in.readFully(buffer);
in.close();
String s = "";
/*Recuperation du TAG
for(int i= buffer.length-128;i<buffer.length;i++){
s += (char)(buffer[i]);
}
System.out.println(s);
*/
final byte[] passPhrase0 = new byte[16];
final SecretKey key0 = new SecretKeySpec(passPhrase0, "AES");
//keyGen = KeyGenerator.getInstance("AES","BC");
//keyGen.init(new SecureRandom());
//key = keyGen.generateKey();
byte[] iv = { (byte) 0xc9, (byte) 0x36, (byte) 0x78, (byte) 0x99,
(byte) 0x52, (byte) 0x3e, (byte) 0xea, (byte) 0xf2,
(byte) 0xc9, (byte) 0x36, (byte) 0x78, (byte) 0x99,
(byte) 0x52, (byte) 0x3e, (byte) 0xea, (byte) 0xf2 };
IvParameterSpec ivp = new IvParameterSpec(iv);
encrypt = Cipher.getInstance("AES/CBC/NoPadding","BC");
encrypt.init(Cipher.ENCRYPT_MODE, key0, ivp);
byte[] buf_crypt = encryptPart(buffer, buffer.length-128, buffer.length-1, encrypt);
FileOutputStream envfos = new FileOutputStream("test_chiffre.mp3");
envfos.write(buf_crypt);
envfos.close();
File f2 = new File("test_chiffre.mp3");
byte[] buffer2 = new byte[(int)f2.length()];
DataInputStream in2 = new DataInputStream(new FileInputStream(f2));
in2.readFully(buffer2);
in2.close();
decrypt = Cipher.getInstance("AES/CBC/NoPadding","BC");
decrypt.init(Cipher.DECRYPT_MODE, key0, ivp);
byte[] buf_decrypt = decryptPart(buffer2,buffer2.length-128,buffer2.length-1, decrypt);
envfos = new FileOutputStream("test_dechiffre.mp3");
envfos.write(buffer2);
envfos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] encryptPart(byte[] buffer, int beg, int end, Cipher encrypter){
byte[] toencrypt = new byte[(end - beg)+1];
byte[] encrypted;
//array copy
int j = beg;
for(int i=0; i>< (end -beg)+1 ; i++){
System.out.println("i = " + i + " j = " + j);
toencrypt[i] = buffer[j];
j++;
}
try{
encrypted = encrypter.doFinal(toencrypt);
System.out.println("nombre de bytes chifrees : " + encrypted.length);
j=beg;
for(int i=0; i<encrypted.length; i++){
buffer[j] = encrypted[i];
j++;
}
}
catch(Exception e){e.getMessage(); e.printStackTrace();}
return buffer;
}
public static byte[] decryptPart(byte[] buffer, int beg, int end, Cipher decrypter){
byte[] todecrypt = new byte[(end - beg)+1];
byte[] decrypted ;
//array copy
int j = beg;
for(int i=0; i>< (end -beg)+1 ; i++){
System.out.println("i = " + i + " j = " + j);
todecrypt[i] = buffer[j];
j++;
}
try{
decrypted = decrypter.doFinal(todecrypt);
System.out.println(" Size of decrypted : " + decrypted.length);
j=beg;
for(int i=0; i< decrypted.length; i++){
buffer[j] = decrypted[i];
j++;
}
}
catch(Exception e){e.getMessage(); e.printStackTrace();}
return buffer;
}
}
Thank you for your help !
> So I changed some part and now I can encrypt and
> decrypt the Tag without problem, but I still have
> some questions :
> - How could I chose a good IV for AES CBC mode ? Does
> the IV choice matter ?
I try to use a random IV. This does mean that I have to include the IV as part of the encrypted data so my encrypted length increases by a block length (in your case 16 bytes).
You could use a fixed IV but this then has some of the weaknesses of ECB mode.
> - How could I get a key in a secure way ? If I try
> to get a key with : //key = keyGen.generateKey(); I
> get an Wrong KeySize Exception... So I have a blank
> key, but it works ;)
Key management is very difficult. I don't know how you propose to use your encryption but if you are expecting to place the key with the client then any half competant hacker will be able to extract the key from your code. Since the key must be available to your program to decode the mp3 frame it must be available to a hacker.
You can use techniques to hide the key but this just makes it slightly more difficult for the hacker.
>
> and last question : I'm using AES in CBC mode with No
> Padding, so I dont have problem to encrypt 128 bytes,
> but if I take a random number; it doesn't work. So I
> should encrypt a number of byte which is a multiple
> of 16 (because 16*8 = 128 ) ? I really want to use
> AES in CBC mode, so I think I could slipt the data I
> want to encrypt in buffer of a good size. I want that
> the encrypted content has the same size as the
> decrypted one !
Not easy with CBC mode since you have to in some way include the IV in the encrypted data. I suspect that using the first 16 audio bytes of each frame of your audio data as the IV might solve the problem for you. Schneier shows that one can expose the IV without any loss of security and, since you only propose to encrypt 10% of the audio data, the random nature of audio might make the first 16 bytes a good IV.
I don't have time right now to look in detail at your code. I might try later.
