I am trying to work out the correct process to encrypt and decrypt a file using the "PBEWithHmacSHA256AndAES_256" standard.
From what I understand from looking at this example code from Oracle.
I have gathered that a salt is needed, as well as an iteration count and the hash standard.
So I have my main method, passing into the encryption method:
- a user-defined password
new String(key).toCharArray()as a byte array (using this method for other encryption runs) - a secure random IV
initVectoras a byte array - the plain text file
inputFileas a String - the name of, to be created, ciphertext file
outputFileas a String
I have followed the code example to code up what I believe is correct for the encrypt method. And I am storing the salt and IV to be used for decryption by appending them both to the ciphertext.
private static void encrypt(byte[] key, byte[] initVector, String inputFile, String outputFile) //exceptions for throws... {
//Initalisation for encryption
Cipher cipher;
byte[] salt = new byte[16];
SecureRandom rand = new SecureRandom();
// Salt randomly generated with base64
rand.nextBytes(salt);
System.out.println("my salt should be" + Base64.getEncoder().encodeToString(salt));
salt = Base64.getEncoder().encode(salt);
// Iteration count
int count = 1000;
IvParameterSpec iv = new IvParameterSpec(initVector);
// Create PBE parameter set
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(Base64.getDecoder().decode(salt), count, iv);
// Convert pass into SecretKey object
PBEKeySpec pbeKeySpec = new PBEKeySpec(new String(key).toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256");
SecretKey pbeKey;
try {
pbeKey = keyFac.generateSecret(pbeKeySpec);
} catch (InvalidKeySpecException e) {
System.out.println("Sorry, the password specified cannot be used as a secret key");
System.out.println("Please check that your password uses valid characters");
return;
}
// Create PBE Cipher
cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_256");
// Initialize PBE Cipher with key and parameters
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
}
//File error checking and file handling (i.e. generating file paths)...
System.out.println("Secret key is " + Base64.getEncoder().encodeToString(key));
System.out.println("IV is " + Base64.getEncoder().encodeToString(initVector));
//Special file reading and writing with 'Cipher Stream'
try (InputStream fin = FileEncryptor.class.getResourceAsStream(loadFile.getName());
OutputStream fout = Files.newOutputStream(saveFile);
CipherOutputStream cipherOut = new CipherOutputStream(fout, cipher) {
}) {
final byte[] bytes = new byte[1024];
for(int length=fin.read(bytes); length!=-1; length = fin.read(bytes)){
fout.write(initVector);
fout.write(salt);
cipherOut.write(bytes, 0, length);
}
} catch (IOException e) {
System.out.println("Something went wrong with reading and writing these files!");
System.out.println("Please check you have the latest version of this program");
System.out.println("Contact your IT admin to make sure you have sufficient privileges");
}
System.out.println("SUCCESS! Encryption finished, saved at specified location");
}
Then I also have my main method, passing into the decryption method:
a user-defined password
String inputKEYas a string (also using this method for other dencryption runs)a String for
inputIV, has been passed in as null, since not used for PBE.the ciphertext file
inputFileas a Stringthe name of, to be created, revealplaintext file
outputFileas a Stringprivate static void decrypt(String inputKEY, String inputIV, String inputFile, String outputFile) { Cipher cipher = null;
//File error checking and file handling (i.e. generating file paths)... InputStream encryptedData = Files.newInputStream(loadFilePath); PBEKeySpec pbeKeySpec = new PBEKeySpec(inputKEY.toCharArray()); SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_256"); SecretKey pbeKey = null; try { pbeKey = keyFac.generateSecret(pbeKeySpec); } catch (InvalidKeySpecException e) { // TODO Auto-generated catch block e.printStackTrace(); } byte[] initVect = new byte[16]; encryptedData.read(initVect); IvParameterSpec iv = new IvParameterSpec(Base64.getDecoder().decode(initVect); byte[] salt = new byte[16]; encryptedData.read(salt); PBEParameterSpec pbeParamSpec = new PBEParameterSpec(Base64.getDecoder().decode(salt), 1000, iv); cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_256"); System.out.println("my salt should be" + Base64.getEncoder().encodeToString(Base64.getDecoder().decode(salt))); cipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec); try (CipherInputStream decryptStream = new CipherInputStream(encryptedData, cipher); OutputStream decryptedOut = Files.newOutputStream(saveFile)){ final byte[] bytes = new byte[1024]; for(int length=decryptStream.read(bytes); length!=-1; length = decryptStream.read(bytes)){ decryptedOut.write(bytes, 0, length); } } catch (IOException e) { //This is caught when decryption is run System.out.println("Something went wrong with reading and writing these files!"); System.out.println("Please check you have the latest version of this program"); System.out.println("Contact your IT admin to make sure you have sufficient privileges"); } System.out.println("SUCESS! Decryption finished, saved at specified location");}
I believe something is not right with my understanding of PBE, and thus the way I implemented it is probably wrong. Could anyone point out what seems to be wrong?