I have information security project about encrypting file using AES. and the using key in this algorithm is also encrypted using RSA algorithm and public key,
the problem is: after encrypting the random key it returns array byte[], how this array byte converted into key so I can encrypt the file?
NOTE [public_Key is generated from user using JPasswordField
and this is the challenge I faced from my course project]
public void AESEncryption(File file) throws FileNotFoundException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
String data;
SecretKey random_key;
int key_size=128;
Scanner myReader = new Scanner(file);
while (myReader.hasNextLine()) {
data = myReader.nextLine();
}
// create GenerateKey object to access public key
// GenerateKey is my personal class and contain public key
GenerateKey key = new GenerateKey();
// convert public key to string
String public_Key = key.PublicKey.getText();
// convert string public key to secret key
byte[] decodedKey = Base64.getDecoder().decode(public_Key);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
// generate random key
KeyGenerator g = KeyGenerator.getInstance("AES");
// give it size
g.init(key_size);
random_key = g.generateKey();
// encrypt the random key with RSA and public key
byte[] random_byteKey = random_key.getEncoded();
Cipher cipher_Key = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher_Key.init(Cipher.ENCRYPT_MODE, originalKey);
byte[] encrypted_key = cipher_Key.doFinal(random_byteKey); //RSA key
// after generating RSA key we will Encrypt file using RSA key
byte[] byte_message = data.getBytes();
Cipher cipherTxt = Cipher.getInstance("AES/GCM/NoPadding");
// the problem in here
cipherTxt.init(Cipher.ENCRYPT_MODE, encrypted_key);
byte[] encByte = cipherTxt.doFinal(byte_message);
}
You are not understanding what you need to do. First you generate a random AES key that is used solely for the data encryption. Then you encrypt that key with RSA using the trusted RSA public key which is part of the key pair of the receiver. So you never have to convert either the public key or the RSA ciphertext to a symmetric key.
As an aside, instead of using Cipher#doFinal() you should use Cipher#wrap() , which takes a symmetric key. That way you don't have to encode them to a byte array. It may also be more secure if a hardware module is used, for instance, depending on the Cipher implementation.
I'd strongly suggest you generate separate methods for these separate steps as well as for the file handling.
In the end, you'll need something more akin to this:
public static void hybridEncrypt(RSAPublicKey publicKey, File in, File out) throws IOException, InvalidKeyException {
int key_size=128;
try {
KeyGenerator g = KeyGenerator.getInstance("AES");
g.init(key_size);
SecretKey dataKey = g.generateKey();
// encrypt the random data key with the RSA public key
Cipher cipher_Key = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher_Key.init(Cipher.WRAP_MODE, publicKey);
byte[] encryptedKey = cipher_Key.wrap(dataKey);
Cipher cipherTxt = Cipher.getInstance("AES/GCM/NoPadding");
cipherTxt.init(Cipher.ENCRYPT_MODE, dataKey);
byte[] message = Files.readAllBytes(in.toPath());
byte[] encryptedMessage = cipherTxt.doFinal(message);
out.createNewFile();
Files.write(out.toPath(), encryptedKey);
Files.write(out.toPath(), encryptedMessage, StandardOpenOption.APPEND);
} catch(NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException e) {
throw new RuntimeException("RSA or AES/GCM not available", e);
} catch (BadPaddingException e) {
throw new RuntimeException("Padding failed for NoPadding", e);
}
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(3072);
KeyPair keyPairReceiver = kpGen.generateKeyPair();
RSAPublicKey publicKeyReceiver = (RSAPublicKey) keyPairReceiver.getPublic();
hybridEncrypt(publicKeyReceiver, new File("plain.txt"), new File("bla.bin"));
}
Beware that this is still not best practice code, for instance it uses the old PKCS#1 encryption instead of OAEP. Don't copy paste this guys - with encryption you need to understand what you are doing, and preferably use a well vetted high level library.
I am trying to read a password based encrypted private key from a file, but I'm getting the following exception:
java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:561)
at sun.security.util.DerValue.init(DerValue.java:365)
at sun.security.util.DerValue.<init>(DerValue.java:294)
at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:84) ...
This is how I encrypt and write to file the private key:
public static void savePrivateKeyToDisk(PrivateKey privateKey, String passord){
try {
// unencrypted PKCS#8 private key
byte[] encodedPrivateKey = privateKey.getEncoded();
String MYPBEALG = "PBEWithSHA1AndDESede";
int count = 20;
SecureRandom random = new SecureRandom();
byte[] salt = new byte[8];
random.nextBytes(salt);
// Create PBE parameter set
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count);
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFac = SecretKeyFactory.getInstance(MYPBEALG);
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
Cipher pbeCipher = Cipher.getInstance(MYPBEALG);
// Initialize PBE Cipher with key and parameters
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
// Encrypt the encoded Private Key with the PBE key
byte[] cipherText = pbeCipher.doFinal(encodedPrivateKey);
// Now construct PKCS #8 EncryptedPrivateKeyInfo object
AlgorithmParameters algparms = AlgorithmParameters.getInstance(MYPBEALG);
algparms.init(pbeParamSpec);
EncryptedPrivateKeyInfo encinfo = new EncryptedPrivateKeyInfo(algparms, cipherText);
// DER encoded PKCS#8 encrypted key
byte[] encryptedPkcs8 = encinfo.getEncoded();
File encryptedPrivate = new File(PRIVATE_KEY_FILE);
if (encryptedPrivate.getParentFile() != null) {
encryptedPrivate.getParentFile().mkdirs();
}
encryptedPrivate.createNewFile();
ObjectOutputStream publicKeyOS = new ObjectOutputStream(
new FileOutputStream(encryptedPrivate));
publicKeyOS.writeObject(encryptedPkcs8);
publicKeyOS.close();
}
catch (Exception e){
e.printStackTrace();
}
}
... and this is how I'm trying to read the encrypted private key:
public static PrivateKey getPrivateKey(String passwd){
try {
byte[] encodedPrivateKey = getFileBytes(PRIVATE_KEY_FILE);
// exception thrown from here
EncryptedPrivateKeyInfo encryptPKInfo = new EncryptedPrivateKeyInfo(encodedPrivateKey);
Cipher cipher = Cipher.getInstance(encryptPKInfo.getAlgName());
PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray());
SecretKeyFactory secFac = SecretKeyFactory.getInstance(encryptPKInfo.getAlgName());
Key pbeKey = secFac.generateSecret(pbeKeySpec);
AlgorithmParameters algParams = encryptPKInfo.getAlgParameters();
cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);
KeySpec pkcs8KeySpec = encryptPKInfo.getKeySpec(cipher);
KeyFactory kf = KeyFactory.getInstance(ALGORITHM);
return kf.generatePrivate(pkcs8KeySpec);
}
catch (Exception e){
e.printStackTrace();
return null;
}
}
... the getFileBytes method:
private static byte[] getFileBytes(String infile){
File f = new File(infile) ;
int sizecontent = ((int) f.length());
byte[] data = new byte[sizecontent];
try
{
FileInputStream freader = new FileInputStream(f);
freader.read(data, 0, sizecontent) ;
freader.close();
return data;
}
catch(IOException ioe)
{
System.out.println(ioe.toString());
return null;
}
}
It seems like the encrypted private key is not in the right format, but I save it in DER PKCS#8 format.
So, the question: What is the mistake in this code?
I guess the problem is that you write an Object, but then you read byte[] (not an Object)
I would suggest that you either read the whole object and then get the required bytes or even better write byte[] directly (don't use ObjectOutputStream) and then load these bytes, eg:
FileOutputStream fos = new FileOutputStream(PRIVATE_KEY_FILE);
fos.write(myByteArray);
fos.close();
and then to retrieve it:
byte[] bytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILE));
I need to decrypt file in C++. What I have is byte array and pair of keys generated in Java using KeyPairGenerator from java.security;
Java Code:
public void generateKeys() {
try {
final KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance(algorithmName);
pairGenerator.initialize(1024); //1024 - keysize
final KeyPair keyPair = pairGenerator.generateKeyPair();
savePublicKeyIntoFile(keyPair);
savePrivateKeyIntoFile(keyPair);
} catch (Exception e) {
System.err.println("Class EncryptionTool.generateKeys() ");
e.printStackTrace();
}
}
public static String encrypt() throws Exception {
// Encrypt the string using the public key
ObjectInputStream inputStream = null;
inputStream = new ObjectInputStream(new FileInputStream(publicKeyFilepath));
final PublicKey publicKey = (PublicKey) inputStream.readObject();
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance(algorithmName);
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherText = null;
**cipherText = cipher.doFinal( loadPassword() );**
return changeByteArrayToString(cipherText);
}
I have generated keys saved in files and this cipherText array in C++.
What should I use to decrypt this ?
I am using OpenSSL RSA1_5 for decrypting the CEK (Content Encryption Key).
My aim is to decrypt the JWK (JSON Web Key) by which I will be getting CEK, so by using CEK I can decrypt my ciphertext which is actually the encrypted data.
After using Base64Decode, JWE Header is
{"alg":"RSA1_5","enc":"A128CBC-HS256","typ":"JOSE"}
where "alg" is the algorithm used to decrypt the CEK. Please help me decrypting the CEK first, after this I need to decrypt the Cipher.
My Java class is:
package com.decryption;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.security.interfaces.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
public class RSADecrypt
{
public RSADecrypt(String inFileName, String outFileName) {
try {
System.out.println("Inside TRY");
/* Get the encrypted message from file. */
FileInputStream cipherfile = new FileInputStream(inFileName);
byte[] ciphertext = new byte[cipherfile.available()];
cipherfile.read(ciphertext);
cipherfile.close();
System.out.println("Inside 1");
/* Get the private key from file. */
//PrivateKey privatekey = readPrivateKey("D://sso//mmdevnopass.key");
PrivateKey privatekey = readPrivateKey("D://sso//mmdevJWE.key");
System.out.println("Inside 2");
/* Create cipher for decryption. */
Cipher decrypt_cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decrypt_cipher.init(Cipher.DECRYPT_MODE, privatekey);
System.out.println("Inside 3");
/* Reconstruct the plaintext message. */
byte[] plaintext = decrypt_cipher.doFinal(ciphertext);
FileOutputStream plainfile = new FileOutputStream(outFileName);
plainfile.write(plaintext);
plainfile.close();
} catch (Exception e) {
System.out.println("catch1");
e.printStackTrace();
}
}
public static PrivateKey readPrivateKey(String filename) throws Exception {
System.out.println("readPrivateKey()");
FileInputStream file = new FileInputStream(filename);
byte[] bytes = new byte[file.available()];
file.read(bytes);
file.close();
System.out.println("readPrivateKey() 1");
PKCS8EncodedKeySpec privspec = new PKCS8EncodedKeySpec(bytes);
// X509EncodedKeySpec privspec= new X509EncodedKeySpec(bytes);
//RSAPrivateKeySpec privspec = new RSAPrivateKeySpec(modulus, privateExponent)
System.out.println("readPrivateKey() 2");
KeyFactory factory = KeyFactory.getInstance("RSA");
System.out.println("readPrivateKey() 3");
PrivateKey privkey = factory.generatePrivate(privspec);
System.out.println("readPrivateKey() 4");
return privkey;
}
public static void main(String[] arg) {
/*if (arg.length != 2) {
System.err.println("Usage: java RSADecrypt <src file> <dest file>");
} else {*/
System.out.println("Welcome");
String inFileName="D://sso//myJEK.txt";
String outFileName="D://sso//out.txt";
new RSADecrypt(inFileName,outFileName);
// }
}
}
I am getting output as
Welcome
Inside TRY
Inside 1
readPrivateKey()
readPrivateKey() 1
readPrivateKey() 2
readPrivateKey() 3
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:175)
at java.security.KeyFactory.generatePrivate(KeyFactory.java:322)
at com.decryption.RSADecrypt.readPrivateKey(RSADecrypt.java:85)
at com.decryption.RSADecrypt.<init>(RSADecrypt.java:46)
at com.decryption.RSADecrypt.main(RSADecrypt.java:102)
Caused by: java.security.InvalidKeyException: invalid key format
at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:324)
at sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:350)
at sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:74)
at sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:58)
at sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:274)
at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:171)
... 4 more
catch1
Please help me to decrypt the CEK and solve this exception.
Your problem is caused by your private key file. Firstly, your method of reading the bytes is error-prone:
FileInputStream file = new FileInputStream(filename);
byte[] bytes = new byte[file.available()];
file.read(bytes);
file.close();
This may not read the entire file. The available() method does not indicate how many bytes are in the file. Please search for a better way of reading this file (perhaps from this question: File to byte[] in Java).
Once this is fixed, you may still have errors unless your file is a DER-encoded PKCS #8 object. A common mistake is to try and use a PEM-encoded file (e.g. containing ----- BEGIN PRIVATE KEY ---- headers and base64-encoded data).
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;
}