Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am trying to create a simple AES encryption/decryption module for use in a larger project, but I'm having trouble getting the AES methods to work. I've done a good amount of research, but I can't figure out what is going wrong within my code (I'm suspecting something simple that I'm missing).
Main:
public static byte[] genKey() {
// Create key generator
KeyGenerator keyGen;
try {
keyGen = KeyGenerator.getInstance("AES");
}
catch(GeneralSecurityException e) {
e.printStackTrace();
return null;
}
// Create random byte generator
SecureRandom r = new SecureRandom();
// Initialize key generator
keyGen.init(256, r);
SecretKey key = keyGen.generateKey();
return key.getEncoded();
}
public static void main(String[] args) throws GeneralSecurityException {
// write your code here
// Create AES handler
AES aes = new AES();
// Generate key
byte[] key = genKey();
// Set key for AES
aes.setKey(key);
Scanner in = new Scanner(System.in);
System.out.print("Please enter a phrase to encrypt: ");
String input = in.nextLine();
// Encrypt phrase
byte[][] encrypted = aes.encrypt(input);
// Decrypt phrase
String plaintext = aes.decrypt(encrypted[0], encrypted[1]);
// Print results
System.out.println("Ciphertext: " + encrypted[1]);
System.out.println("Plaintext: " + plaintext);
}
AES:
private Cipher cipher;
private SecretKey key;
public AES() {
// Create Cipher
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
public void setKey(byte[] key) {
this.key = new SecretKeySpec(key, "AES");
}
public byte[][] encrypt(String plaintext) throws GeneralSecurityException {
System.out.println("Using key : " + key.getEncoded() + " to encrypt");
byte[][] values = new byte[2][];
// Decode plaintext into bytes
byte[] decodedPlaintext = new byte[0];
try {
decodedPlaintext = plaintext.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// Generate an IV and set up the Cipher to encrypt
byte[] ivBytes = new byte[16];
SecureRandom rand = new SecureRandom();
rand.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
// Encrypt decoded plaintext
byte[] ciphertext = cipher.doFinal(decodedPlaintext);
values[0] = ivBytes;
values[1] = ciphertext;
return values;
}
public String decrypt(byte[] ivBytes, byte[] ciphertext) throws GeneralSecurityException {
System.out.println("Using key " + key.getEncoded() + " to decrypt");
// Set up cipher to decrypt
IvParameterSpec iv = new IvParameterSpec(ivBytes);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decodedPlaintext = cipher.doFinal(ciphertext);
// Encode plaintext
String plaintext = Base64.getEncoder().encodeToString(decodedPlaintext);
return plaintext;
}
Results:
Please enter a phrase to encrypt: test
Using key : [B#442d9b6e to encrypt
Using key [B#3d012ddd to decrypt
Ciphertext: [B#515f550a
Plaintext: dGVzdA==
I don't understand why my encryption/decryption seem to be using different keys when I only set the key once in the beginning. Am I creating a key wrong?
I've also tried:
byte[] key = new byte[32];
SecureRandom r = new SecureRandom();
r.nextBytes(key);
// Set key for AES
aes.setKey(key);
And run into the same issue.
If you trace this.key in AES class all the way through encode and decode using Arrays.toString(this.key.getEncoded()) it does look like it's using a persistent key.
this.key.getEncoded().toString()) returns a different representation each time but it seems like the actual byte array is the same.
I replaced
String plaintext = Base64.getEncoder().encodeToString(decodedPlaintext);
with
String plaintext = new String(decodedPlaintext, StandardCharsets.UTF_8);
and it seemed to work.
I am working on secure chat application. I have AES key for ecrypt/decrypt message and users have own public/private RS keys for encrypt/decrypt AES key. My code give me error like this:
> javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:383)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:294)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:363)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2164)
at org.fastchat.User.decryptAESKey(User.java:183)
at org.fastchat.User.readMessage(User.java:210)
at org.fastchat.WatchInbox.startWatch(WatchInbox.java:59)
at org.fastchat.WatchInbox.run(WatchInbox.java:32)
Error is in function for decrypting AES key with RSA private key. I found that problem could be with wrong key (keys stored in serialization, every user have once generated keys in profile object) or encode/decode problems. I decide to store encrypted AES key in some file and read that file for decrypt AES key. Is there some better way for store encypted AES key? Am I doing encode/decode in right way? Any help is welcome, I dont have any ideas now. My code is here and every part of proccess is in different function.
public SecretKey generateAESkey() throws NoSuchAlgorithmException {
System.out.println("Generating AES key...\n");
SecureRandom random = new SecureRandom();
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, random);
SecretKey aeSecretKey = keyGenerator.generateKey();
System.out.println("AES1 KEY " + new String(Base64.getEncoder().encodeToString(aeSecretKey.getEncoded())));
System.out.println("===========================\n");
return aeSecretKey;
// return keyGenerator.generateKey();
}
public byte[] encryptAESKey(SecretKey key, PublicKey pubKey) throws Exception {
System.out.println("Encrypt AES key...\n");
String aesKey = new String(Base64.getEncoder().encodeToString(key.getEncoded()));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] aesEnc = cipher.doFinal(aesKey.getBytes());
System.out.println("AES ENCRYPTED: " + aesEnc);
System.out.println("==========================\n");
return aesEnc;
// return cipher.doFinal(aesToEnc);
}
public byte[] encryptMessage(String message, SecretKey aeSecretKey) throws Exception {
System.out.println("Encrypt message...\n");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, aeSecretKey);
byte[] msgBytes = message.getBytes(); // This will be encrypted
byte[] msgEnc = cipher.doFinal(msgBytes);
System.out.println("=============================\n");
return msgEnc;
// return cipher.doFinal(msgBytes); //This will be in .txt file
}
public void checkerUpdate(User receiver) throws IOException {
BufferedWriter check = new BufferedWriter(new FileWriter(receiver.getCheck() + "/" + getUsername() + ".txt"));
Random random = new Random();
Integer num = random.nextInt(100);
check.write(num);
check.close();
}
public void sendMessage(String message, User receiver) throws Exception {
// First generate AES key
SecretKey aesSecretKey = generateAESkey(); // keysize = 128
// Encrypt message with AES key, will be in file
byte[] encMsg = encryptMessage(message, aesSecretKey);
// Encrypt AES key, put in file
byte[] aesEnc = encryptAESKey(aesSecretKey, receiver.getPub());
// Send message and key to receiver
FileOutputStream msgWrite = new FileOutputStream(receiver.getInbox() + "/" + getUsername() + ".msg", true);
FileOutputStream keyWrite = new FileOutputStream(receiver.getInbox() + "/" + getUsername() + ".kgn", true);
keyWrite.write(Base64.getEncoder().encode(aesEnc));
msgWrite.write(Base64.getEncoder().encode(encMsg));
keyWrite.close();
msgWrite.close();
// Add file to CHECKER, temp operations for WatchInbox service
checkerUpdate(receiver);
}
// FUNCTIONS FOR DECRYPTION
public byte[] decryptAESKey(byte[] aesEnc) throws Exception {
System.out.println("Decrypt AES key...\n");
byte[] aesEncString = Base64.getDecoder().decode(aesEnc);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, getPriv());
byte[] decAes = cipher.doFinal(aesEncString);
System.out.println("===========================\n");
return decAes;
// return cipher.doFinal(Base64.getDecoder().decode(aesEnc));
}
public String decryptMessage(byte[] msg, SecretKeySpec aeskey) throws Exception {
System.out.println("Decrypt message...\n");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, aeskey);
String msgDec = cipher.doFinal(Base64.getDecoder().decode(msg)).toString();
System.out.println("============================\n");
return msgDec;
// return cipher.doFinal(Base64.getDecoder().decode(msg)).toString();
}
public String readMessage(User sender) throws Exception {
// Read file in inbox
File msgtoRead = new File(getInbox() + "/" + sender.getUsername() + ".msg");
FileInputStream keytoRead = new FileInputStream(getInbox() + "/" + sender.getUsername() + ".kgn");
// Read 128bits from filetoRead. That is encrypted key.
byte[] aesEnc = new byte[128];
keytoRead.read(aesEnc);
// Decrypted aes key for decode
byte[] aesDec = decryptAESKey(aesEnc);
SecretKeySpec aesKey = new SecretKeySpec(aesDec, "AES/CBC/PKCS5Padding");
// Read message
byte[] message = Files.readAllBytes(msgtoRead.toPath());
keytoRead.close();
// Decrypt message with loaded AES key (aesKey), return this
return new String(decryptMessage(message, aesKey));
}
I'm new to cryptography and I'm attempting to create a simple AES encryption program and base64 enconding. The program seems to encrypt and decrypt my message string as it should but for some reason it shows me the exception java.lang.IllegalArgumentException: Illegal base64 character 20 in the decrypt method but maybe it has something to do with the encryption..
After searching for a while I couldn't find the reason for this. I would appreciate if someone could point out any mistakes in my code that could lead to this error!
public class AES_encryption {
private static SecretKey skey;
public static Cipher cipher;
public static void main(String[] args) throws Exception{
String init_vector = "RndInitVecforCBC";
String message = "Encrypt this?!()";
String ciphertext = null;
//Generate Key
skey = generateKey();
//Create IV necessary for CBC
IvParameterSpec iv = new IvParameterSpec(init_vector.getBytes());
//Set cipher to AES/CBC/
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try{
ciphertext = encrypt(skey, iv, message);
}
catch(Exception ex){
System.err.println("Exception caught at encrypt method!" + ex);
}
System.out.println("Original Message: " + message + "\nCipher Text: " + ciphertext);
try{
message = decrypt(skey, iv, message);
}
catch(Exception ex){
System.err.println("Exception caught at decrypt method! " + ex);
}
System.out.println("Original Decrypted Message: " + message);
}
private static SecretKey generateKey(){
try {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
skey = keygen.generateKey();
}
catch(NoSuchAlgorithmException ex){
System.err.println(ex);
}
return skey;
}
private static String encrypt(SecretKey skey, IvParameterSpec iv, String plaintext) throws Exception{
//Encodes plaintext into a sequence of bytes using the given charset
byte[] ptbytes = plaintext.getBytes(StandardCharsets.UTF_8);
//Init cipher for AES/CBC encryption
cipher.init(Cipher.ENCRYPT_MODE, skey, iv);
//Encryption of plaintext and enconding to Base64 String so it can be printed out
byte[] ctbytes = cipher.doFinal(ptbytes);
Base64.Encoder encoder64 = Base64.getEncoder();
String ciphertext = new String(encoder64.encode(ctbytes), "UTF-8");
return ciphertext;
}
private static String decrypt(SecretKey skey, IvParameterSpec iv, String ciphertext) throws Exception{
//Decoding ciphertext from Base64 to bytes[]
Base64.Decoder decoder64 = Base64.getDecoder();
byte[] ctbytes = decoder64.decode(ciphertext);
//Init cipher for AES/CBC decryption
cipher.init(Cipher.DECRYPT_MODE, skey, iv);
//Decryption of ciphertext
byte[] ptbytes = cipher.doFinal(ctbytes);
String plaintext = new String(ptbytes);
return plaintext;
}
}
The issue is because you decrypt the message not the encrypted message!
decrypt(skey, iv, message) should probably be decrypt(skey, iv, ciphertext)
I have been given an encrypted file along with a base64 symmetric key and base 64 IV and have been asked to decrypt it using Java. The encryption used on the data file was AES. However, when I run the encrypted file, symmetric key and IV into my code, I get the following error:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
Here is my code:
String encryptedData = "C:\\EncryptedDataFile.data";
FileInputStream fis = null;
File file = new File(encryptedData);
//Convert file into array of bytes
byte[] encryptedDataBytes = new byte[(int) file.length()];
try
{
// Read in array of bytes
fis = new FileInputStream(file);
fis.read(encryptedDataBytes);
fis.close();
}
catch (FileNotFoundException ex)
{
ex.printStackTrace();
}
catch (IOException ex)
{
ex.printStackTrace();
}
// AES Key
byte[] decodedKey = Base64.getDecoder().decode("50rofsdb0TnQAQCb702wKz8m6XQeLNj6lamEvivKsh8=");
// decode the base64 encoded string
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); // rebuild key using SecretKeySpec
// IV
byte[] initVecBytes = Base64.getDecoder().decode("OUXLZq4SpyhzNGIei0nerA==");
// Decrypt the cipher text
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(initVecBytes);
cipher.init(Cipher.DECRYPT_MODE, originalKey, ivParameterSpec);
byte[] original = cipher.doFinal(encryptedDataBytes);
String s = new String(original);
System.out.println(s);
If someone could provide some help to me on this matter it would be much appreciated
I'm trying to encrypt the contents of one file into another file using a passphrase in Java. The file is getting read to a byte array, encrypted to another byte array, and then written to the new file. Unfortunately, when I try to reverse the encryption, the output file gets decrypted as garbage.
I strongly suspect that the issue has to do with generating an identical key every time the same passphrase is used. I wrote a testing method that dumps the key into a file whenever one gets generated. The key is recorded both directly and in encoded form. The former is identical every time, but the latter is always different for some reason.
In all honesty, I don't know a great deal about encryption methods, especially in Java. I only need the data to be moderately secure, and the encryption doesn't have to withstand an attack from anyone with significant time and skills. Thanks in advance to anyone who has advice on this.
Edit: Esailija was kind enough to point out that I was always setting the cipher with ENCRYPT_MODE. I corrected the problem using a boolean argument, but now I'm getting the following exception:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
That sounds to me like the passphrase isn't being used properly. I was under the impression that "PBEWithMD5AndDES" would hash it into a 16 byte code, which most certainly is a multiple of 8. I'm wondering why the key generates and gets used just fine for encryption mode, but then it complains when trying to decrypt under the exact same conditions.
import java.various.stuff;
/**Utility class to encrypt and decrypt files**/
public class FileEncryptor {
//Arbitrarily selected 8-byte salt sequence:
private static final byte[] salt = {
(byte) 0x43, (byte) 0x76, (byte) 0x95, (byte) 0xc7,
(byte) 0x5b, (byte) 0xd7, (byte) 0x45, (byte) 0x17
};
private static Cipher makeCipher(String pass, Boolean decryptMode) throws GeneralSecurityException{
//Use a KeyFactory to derive the corresponding key from the passphrase:
PBEKeySpec keySpec = new PBEKeySpec(pass.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(keySpec);
//Create parameters from the salt and an arbitrary number of iterations:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 42);
/*Dump the key to a file for testing: */
FileEncryptor.keyToFile(key);
//Set up the cipher:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
//Set the cipher mode to decryption or encryption:
if(decryptMode){
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}
/**Encrypts one file to a second file using a key derived from a passphrase:**/
public static void encryptFile(String fileName, String pass)
throws IOException, GeneralSecurityException{
byte[] decData;
byte[] encData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = FileEncryptor.makeCipher(pass, false);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
decData = new byte[(int)inFile.length()];
inStream.read(decData);
inStream.close();
//Encrypt the file data:
encData = cipher.doFinal(decData);
//Write the encrypted data to a new file:
FileOutputStream outStream = new FileOutputStream(new File(fileName + ".encrypted"));
outStream.write(encData);
outStream.close();
}
/**Decrypts one file to a second file using a key derived from a passphrase:**/
public static void decryptFile(String fileName, String pass)
throws GeneralSecurityException, IOException{
byte[] encData;
byte[] decData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = FileEncryptor.makeCipher(pass, true);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
encData = new byte[(int)inFile.length()];
inStream.read(encData);
inStream.close();
//Decrypt the file data:
decData = cipher.doFinal(encData);
//Write the decrypted data to a new file:
FileOutputStream target = new FileOutputStream(new File(fileName + ".decrypted.txt"));
target.write(decData);
target.close();
}
/**Record the key to a text file for testing:**/
private static void keyToFile(SecretKey key){
try {
File keyFile = new File("C:\\keyfile.txt");
FileWriter keyStream = new FileWriter(keyFile);
String encodedKey = "\n" + "Encoded version of key: " + key.getEncoded().toString();
keyStream.write(key.toString());
keyStream.write(encodedKey);
keyStream.close();
} catch (IOException e) {
System.err.println("Failure writing key to file");
e.printStackTrace();
}
}
}
You are using the Cipher.ENCRYPT_MODE for both, decrypting and encrypting. You should use Cipher.DECRYPT_MODE for decrypting the file.
That has been fixed, but your boolean is wrong. It should be true for encrypt and false for decrypt. I would strongly recommend against using false/true as function arguments and always use enum like Cipher.ENCRYPT... moving on
Then you are encrypting to .encrypted file, but trying to decrypt the original plain text file.
Then you are not applying padding to encryption. I am surprised this actually has to be done manually,
but padding is explained here. The padding scheme PKCS5 appeared to be implicitly used here.
This is full working code, writing encrypted file to test.txt.encrypted, and decrypted file to test.txt.decrypted.txt.
Adding padding in encryption and removing it in decryption is explained in the comments.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class FileEncryptor {
public static void main( String[] args ) {
try {
encryptFile( "C:\\test.txt", "password" );
decryptFile( "C:\\test.txt", "password" );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (GeneralSecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//Arbitrarily selected 8-byte salt sequence:
private static final byte[] salt = {
(byte) 0x43, (byte) 0x76, (byte) 0x95, (byte) 0xc7,
(byte) 0x5b, (byte) 0xd7, (byte) 0x45, (byte) 0x17
};
private static Cipher makeCipher(String pass, Boolean decryptMode) throws GeneralSecurityException{
//Use a KeyFactory to derive the corresponding key from the passphrase:
PBEKeySpec keySpec = new PBEKeySpec(pass.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(keySpec);
//Create parameters from the salt and an arbitrary number of iterations:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 42);
/*Dump the key to a file for testing: */
FileEncryptor.keyToFile(key);
//Set up the cipher:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
//Set the cipher mode to decryption or encryption:
if(decryptMode){
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}
/**Encrypts one file to a second file using a key derived from a passphrase:**/
public static void encryptFile(String fileName, String pass)
throws IOException, GeneralSecurityException{
byte[] decData;
byte[] encData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = FileEncryptor.makeCipher(pass, true);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
int blockSize = 8;
//Figure out how many bytes are padded
int paddedCount = blockSize - ((int)inFile.length() % blockSize );
//Figure out full size including padding
int padded = (int)inFile.length() + paddedCount;
decData = new byte[padded];
inStream.read(decData);
inStream.close();
//Write out padding bytes as per PKCS5 algorithm
for( int i = (int)inFile.length(); i < padded; ++i ) {
decData[i] = (byte)paddedCount;
}
//Encrypt the file data:
encData = cipher.doFinal(decData);
//Write the encrypted data to a new file:
FileOutputStream outStream = new FileOutputStream(new File(fileName + ".encrypted"));
outStream.write(encData);
outStream.close();
}
/**Decrypts one file to a second file using a key derived from a passphrase:**/
public static void decryptFile(String fileName, String pass)
throws GeneralSecurityException, IOException{
byte[] encData;
byte[] decData;
File inFile = new File(fileName+ ".encrypted");
//Generate the cipher using pass:
Cipher cipher = FileEncryptor.makeCipher(pass, false);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile );
encData = new byte[(int)inFile.length()];
inStream.read(encData);
inStream.close();
//Decrypt the file data:
decData = cipher.doFinal(encData);
//Figure out how much padding to remove
int padCount = (int)decData[decData.length - 1];
//Naive check, will fail if plaintext file actually contained
//this at the end
//For robust check, check that padCount bytes at the end have same value
if( padCount >= 1 && padCount <= 8 ) {
decData = Arrays.copyOfRange( decData , 0, decData.length - padCount);
}
//Write the decrypted data to a new file:
FileOutputStream target = new FileOutputStream(new File(fileName + ".decrypted.txt"));
target.write(decData);
target.close();
}
/**Record the key to a text file for testing:**/
private static void keyToFile(SecretKey key){
try {
File keyFile = new File("C:\\keyfile.txt");
FileWriter keyStream = new FileWriter(keyFile);
String encodedKey = "\n" + "Encoded version of key: " + key.getEncoded().toString();
keyStream.write(key.toString());
keyStream.write(encodedKey);
keyStream.close();
} catch (IOException e) {
System.err.println("Failure writing key to file");
e.printStackTrace();
}
}
}
These are some improvements to the #Esailija 's answer given some new features in Java.
By using the CipherInputStream and CipherOutputStream classes, the length and complexity of the code is greatly reduced.
I also use char[] instead of String for the password.
You can use System.console().readPassword("input password: ") to get the password as a char[] so that it is never a String.
public static void encryptFile(String inFileName, String outFileName, char[] pass) throws IOException, GeneralSecurityException {
Cipher cipher = PasswordProtectFile.makeCipher(pass, true);
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(new FileOutputStream(outFileName), cipher);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inFileName))) {
int i;
while ((i = bis.read()) != -1) {
cipherOutputStream.write(i);
}
}
}
public static void decryptFile(String inFileName, String outFileName, char[] pass) throws GeneralSecurityException, IOException {
Cipher cipher = PasswordProtectFile.makeCipher(pass, false);
try (CipherInputStream cipherInputStream = new CipherInputStream(new FileInputStream(inFileName), cipher);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFileName))) {
int i;
while ((i = cipherInputStream.read()) != -1) {
bos.write(i);
}
}
}
private static Cipher makeCipher(char[] pass, Boolean decryptMode) throws GeneralSecurityException {
// Use a KeyFactory to derive the corresponding key from the passphrase:
PBEKeySpec keySpec = new PBEKeySpec(pass);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(keySpec);
// Create parameters from the salt and an arbitrary number of iterations:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 43);
// Set up the cipher:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
// Set the cipher mode to decryption or encryption:
if (decryptMode) {
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}