Thanks for your suggestions. Here is the working code:
package com.example.passwordsafe.data;
import com.example.passwordsafe.core.usecases.EncryptionModuleInterface;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
public class AESEncryption implements EncryptionModuleInterface {
private static final int ITERATION_COUNT = 1000000;
private static final int KEY_LENGTH = 256;
private static final String PBKDF_ALGORITHM = "PBKDF2WithHmacSHA1";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final String ALGORITHM = "AES";
@Override
public String encryptPassword(String password, String masterpassword) {
byte[] finalCiphertext;
SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
KeySpec spec = new PBEKeySpec(masterpassword.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_ALGORITHM);
byte[] key = factory.generateSecret(spec).getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] inputBytes = password.getBytes();
byte[] encValue = cipher.doFinal(inputBytes);
finalCiphertext = new byte[encValue.length+2*16];
System.arraycopy(ivBytes, 0, finalCiphertext, 0, 16);
System.arraycopy(salt, 0, finalCiphertext, 16, 16);
System.arraycopy(encValue, 0, finalCiphertext, 32, encValue.length);
} catch (NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException |
InvalidKeySpecException | NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException(e);
}
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString(finalCiphertext);
}
@Override
public String decryptPassword(String password, String masterpassword) {
byte[] ivBytes = new byte[16];
byte[] salt = new byte[16];
byte[] encValue;
Base64.Decoder decoder = Base64.getDecoder();
byte[] readEncryptedBytesWithIvAndSaltPrefix = decoder.decode(password);
byte[] inputBytes = new byte[readEncryptedBytesWithIvAndSaltPrefix.length - 32];
System.arraycopy(readEncryptedBytesWithIvAndSaltPrefix, 0, ivBytes, 0, 16);
System.arraycopy(readEncryptedBytesWithIvAndSaltPrefix, 16, salt, 0, 16);
System.arraycopy(readEncryptedBytesWithIvAndSaltPrefix, 32, inputBytes, 0, readEncryptedBytesWithIvAndSaltPrefix.length - 32);
KeySpec spec = new PBEKeySpec(masterpassword.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH);
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_ALGORITHM);
byte[] key = factory.generateSecret(spec).getEncoded();
SecretKeySpec keySpec = new SecretKeySpec(key, ALGORITHM);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
encValue = cipher.doFinal(inputBytes);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException |
BadPaddingException | InvalidKeySpecException | InvalidAlgorithmParameterException e) {
throw new RuntimeException(e);
}
return new String(encValue);
}
}