I have just discovered the PBE method to generate a "salty" key in order to encrypt an object (here, a string).
I do not know much how all this works, but the lessons I had made me want to go a little further and therefore to create my own salege and everything that follows without leaving java "everything to do".
So I developed methods that are used to encrypt and decrypt a message, and everything seems to work very well ... But in fact, it works weirdly, because the message I find at the end is present, but present with extra characters!
I find it hard to understand how this is done.
Could you enlighten me on this question?
The code of my class below:
package fr.doranco.cryptage.pbe;
import fr.doranco.utils.Utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
*
* @author Boule
*/
public abstract class CryptagePBE {
private static final int KEY_SIZE = 128;
private static final String KEY_ALGO = "AES";
private static final String ALGOTRANSFORM = "AES/CBC/PKCS5Padding";
private static final String KDF = "PBKDF2WithHmacSHA1";
private static final int ITERATION = 1000;
private static final Random RANDOM = new SecureRandom();
private CryptagePBE() {
}
public static final byte[] encrypter(Object objetACrypter, SecretKey clePBE) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, IOException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance(ALGOTRANSFORM);
cipher.init(Cipher.ENCRYPT_MODE, clePBE,new IvParameterSpec(new byte[16]));
byte[] objetBytes = Utils.convertToBytes(objetACrypter);
byte[] cipherBytes = cipher.doFinal(objetBytes);
return cipherBytes;
}
public static final byte[] decrypter(byte[] stringCrypte, SecretKey cle, String encodage) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance(ALGOTRANSFORM);
cipher.init(Cipher.DECRYPT_MODE, cle, new IvParameterSpec(new byte[16]));
//Ne pas oublier de caster le retour afin de récupérer l'objet désiré !
return cipher.doFinal(stringCrypte);
}
public static final SecretKey generatePBEKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKey clePBE = null;
char[] passwordTochar = password.toCharArray();
PBEKeySpec pbeKeySpec = new PBEKeySpec(passwordTochar, CryptagePBE.getNextSalt(), ITERATION, KEY_SIZE);
//On vide le tableau de charactère du mot de passe.
password = "";
for (int j = 0; j < passwordTochar.length; j++) {
passwordTochar[j] = 0;
}
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KDF);
SecretKey keyPBE = keyFactory.generateSecret(pbeKeySpec);
clePBE = new SecretKeySpec(keyPBE.getEncoded(), KEY_ALGO);
return clePBE;
}
public static byte[] getNextSalt() {
byte[] salt = new byte[16];
RANDOM.nextBytes(salt);
return salt;
}
public static final byte[] convertKeyToBytes(SecretKey key) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos)) {
out.writeObject(key);
return bos.toByteArray();
}
}
public static final SecretKey convertKeyFromBytes(byte[] keyData) throws IOException, ClassNotFoundException {
try (ByteArrayInputStream bis = new ByteArrayInputStream(keyData);
ObjectInput in = new ObjectInputStream(bis)) {
return (SecretKey) in.readObject();
}
}
}
Here my main
public class Main {
public static void main(String[] args) {
try {
SecretKey clePBE = CryptagePBE.generatePBEKey("coucou");
String messageA = "Hi people";
System.err.println("Original message : "+ messageA+" //Message in bytes array : "+Utils.convertToBytes(messageA));
byte[] messageCrypte2 = CryptagePBE.encrypter(messageA, clePBE);
System.err.println("Crypted message : "+messageCrypte2);
byte[] messageDecrypte = CryptagePBE.decrypter(messageCrypte2, clePBE, "UTF8");
System.err.println("Decrypted message : "+messageDecrypte);
} catch (Exception ex) {
System.err.println("Une erreur est survenue dans le main : " + ex);
}
}
public Main() {
}
}
And this is what I have in my output console :
Original message : Hi people //Message in bytes array : [B@704921a5
Crypted message : [B@31f924f5
Decrypted message : [B@5579bb86 //This will return "Hi people" but with a changed bytes array.
I wonder if it's a problem due to the encoding ?
Thank you !
Edit
Thx to @andreas who gave me the reason. The method to compare the both messages is to compare with Arrays.toString(myArray). With this method we can see the same array of bytes, not a different for both.
Here the full explaination of this : What's the simplest way to print a Java array?