I'm working on a server and client program. Data will be exchanged between the server and client. This data will be encrypted.
The server will always generate the salt and the IV. The client will receive the salt and IV and use it to encrypt / decrypt the data that it will send / recieve.
The only problem is that when I try to encrypt data with my client, I get java.lang.NullPointerException - I dont know why.
Here is my code:
Main:
public static void main(String[] args) throws Exception {
String password = "weak_password";
String message = "TOP SECRET DATA.";
byte[] cipherText;
byte[] iv;
byte[] salt;
String decrypted;
AESCipher server = new AESCipher(password);
salt = server.getSalt();
iv = server.getIV();
AESCipher client = new AESCipher(password, salt, iv);
System.out.println("Original data: " + message);
cipherText = server.encrypt(message.getBytes());
System.out.println("Cipher text from server: " + new String(cipherText));
decrypted = new String(client.decrypt(cipherText));
System.out.println("Data decrypted by client: " + decrypted);
cipherText = client.encrypt(message.getBytes());
System.out.println("Cipher text from client: " + new String(cipherText));
decrypted = new String(server.decrypt(cipherText));
System.out.println("Data decrypted by server: " + decrypted);
}
AES Cipher:
public class AESCipher {
private String password;
private byte[] iv;
private byte[] salt;
private final int passwordIterations = 78882;
private final int keySize = 128;
private SecretKeyFactory factory;
private PBEKeySpec spec;
private SecretKey secretKey;
private SecretKeySpec secret;
private Cipher encryptCipher;
private Cipher decryptCipher;
/**
* Generates a secure random salt.
*/
public void generateSalt() {
byte[] randomBytes = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(randomBytes);
this.salt = randomBytes;
}
/**
* Generates an IV.
* @throws Exception
* If something went wrong with padding scheme or IV generation.
*/
public void generateIV() throws Exception {
AlgorithmParameters params;
encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, secret);
params = encryptCipher.getParameters();
iv = params.getParameterSpec(IvParameterSpec.class).getIV();
}
/**
* Generates the key from the password.
* @throws Exception
* If something went wrong with the key generation.
*/
private void generateKey() throws Exception {
factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
spec = new PBEKeySpec(this.password.toCharArray(), this.salt,
this.passwordIterations, this.keySize);
secretKey = factory.generateSecret(spec);
secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
}
/**
* Gets the salt so that it can be sent to the client.
* @return
* The salt.
*/
public byte[] getSalt() {
return this.salt;
}
/**
* Gets the IV so that it can be sent to the client.
* @return
*/
public byte[] getIV() {
return this.iv;
}
/**
* Encrypts data.
* @param plainText
* The data to encrypt.
* @return
* Encrypted data.
* @throws Exception
* If something went wrong with the encryption.
*/
public byte[] encrypt(byte[] plainText) throws Exception {
byte[] encrypted;
encrypted = encryptCipher.doFinal(plainText);
return encrypted;
}
/**
* Decrypts data.
* @param cipherText
* The data to decrypt.
* @return
* Decrypted data.
* @throws Exception
* If something went wrong with the decryption.
*/
public byte[] decrypt(byte[] cipherText) throws Exception {
byte[] decrypted;
decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
decrypted = decryptCipher.doFinal(cipherText);
return decrypted;
}
/**
* Class initializer for server encryption.
* @param password
* The password that will be used for the key.
* @throws Exception
* If something went wrong with the key generation.
*/
public AESCipher(String password) throws Exception {
this.password = password;
generateSalt();
generateKey();
generateIV();
}
/**
* Class initializer for client encryption.
* @param password
* The password that will be used for the key.
* @param salt
* The salt that was received from the server.
* @param iv
* The IV that was received from the client.
* @throws Exception
* If something went wrong with the key generation.
*/
public AESCipher(String password, byte[] salt, byte[] iv) throws Exception {
this.password = password;
this.salt = salt;
this.iv = iv;
generateKey();
}
}
Sample output:
Original data: TOP SECRET DATA.
Cipher text from server: v~vTȟzPIiGHE
Exception in thread "main" java.lang.NullPointerException
at confusion.encryption.AESCipher.encrypt(AESCipher.java:93)
at central.control.system.CentralControlSystem.main(CentralControlSystem.java:29)
Java Result: 1