· 5 years ago · Aug 17, 2020, 06:02 AM
1import java.io.BufferedInputStream;
2import java.io.BufferedOutputStream;
3import java.io.FileInputStream;
4import java.io.FileNotFoundException;
5import java.io.FileOutputStream;
6import java.io.IOException;
7import java.security.InvalidAlgorithmParameterException;
8import java.security.InvalidKeyException;
9import java.security.NoSuchAlgorithmException;
10import java.security.SecureRandom;
11import java.security.spec.InvalidKeySpecException;
12import java.security.spec.KeySpec;
13
14import javax.crypto.BadPaddingException;
15import javax.crypto.Cipher;
16import javax.crypto.IllegalBlockSizeException;
17import javax.crypto.NoSuchPaddingException;
18import javax.crypto.SecretKey;
19import javax.crypto.SecretKeyFactory;
20import javax.crypto.spec.IvParameterSpec;
21import javax.crypto.spec.PBEKeySpec;
22import javax.crypto.spec.SecretKeySpec;
23
24/**
25 * Program to encrypt and decrypt files using a key derived from a password by PBKDF2
26 * and AES-128
27 */
28
29/**
30 * @author les
31 * @version $Revision: 1.1 $
32 */
33public class FileEncryptor {
34
35 private static final String progName = "FileEncryptor";
36 private static final int bufSize = 128;
37
38 /**
39 * @param args
40 */
41 public static void main(String[] args) {
42
43 BufferedInputStream in = null; // A buffered input stream to read from
44 BufferedOutputStream out = null; // And a buffered output stream to write to
45 SecretKeyFactory kf = null; // Something to create a key for us
46 KeySpec ks = null; // This is how we specify what kind of key we want it to generate
47 byte[] salt = new byte[20]; // Some salt for use with PBKDF2, only not very salty
48 SecretKey key = null; // The key that it generates
49 Cipher cipher = null; // The cipher that will do the real work
50 SecretKeySpec keyspec = null; // How we pass the key to the Cipher
51 int bytesRead = 0; // Number of bytes read into the input file buffer
52 final int iterations = 1024; // Number of iterations required to create a password from the key
53
54 // First, check the user has provided all the required arguments, and if they haven't, tell them then exit
55 if(args.length != 4) {
56 printUsageMessage(); System.exit(1);
57 }
58
59 // Open the input file
60 try {
61 in = new BufferedInputStream(new FileInputStream(args[1]));
62 } catch (FileNotFoundException e) {
63 printErrorMessage("Unable to open input file: " + args[1], null);
64 System.exit(1);
65 }
66
67 // And then the output file
68 try {
69 out = new BufferedOutputStream(new FileOutputStream(args[2]));
70 } catch (FileNotFoundException e) {
71 printErrorMessage("Unable to open output file: " + args[2], e);
72 System.exit(1);
73 }
74
75 // Create a PBKDF2 secret key factory
76
77
78
79
80
81
82
83 // Set up a KeySpec for password-based key generation of a 128-bit key
84
85
86
87
88
89 // Now run the passphrase through PBKDF2 to get the key
90
91
92
93
94
95
96 // Get the byte encoded key value as a byte array
97 byte[] aeskey = key.getEncoded();
98
99 // Now generate a Cipher object for AES encryption in ECB or CBC mode with PKCS #5 padding
100 // Use ECB for the first task, then switch to CBC for versions 2 and 3
101 try {
102
103 } catch (NoSuchAlgorithmException e) {
104 printErrorMessage("No Such Algorithm Exception when creating main cipher", e);
105 System.exit(2);
106 } catch (NoSuchPaddingException e) {
107 printErrorMessage("No Such Padding Exception when creating main cipher",e);
108 System.exit(2);
109 }
110
111 // Set a variable to indicate whether we're in encrypt or decrypt mode, based upon args[0]
112 int cipherMode = -1;
113 char mode = Character.toLowerCase(args[0].charAt(0));
114 switch (mode) {
115 case 'e' : cipherMode = Cipher.ENCRYPT_MODE; break;
116 case 'd' : cipherMode = Cipher.DECRYPT_MODE; break;
117 default: printUsageMessage(); System.exit(1);
118 }
119
120 // Set up a secret key specification, based on the 16-byte (128-bit) AES key array previously generated
121
122
123 // Now initialize the cipher in the right mode, with the keyspec and the ivspec
124 try {
125
126 } catch (InvalidKeyException e) {
127 printErrorMessage("Invalid Key Spec",e); System.exit(2);
128 } catch (InvalidAlgorithmParameterException e) {
129 printErrorMessage("Invalid Algorithm Parameter", e); System.exit(2);
130 }
131
132 // Set up some input and output byte array buffers
133 byte[] inputBuffer = new byte[bufSize];
134 byte[] outputBuffer = null;
135
136 // "Prime the pump" - we've got to read something before we can encrypt it
137 // and not encrypt anything if we read nothing.
138 try {
139 bytesRead = in.read(inputBuffer);
140 } catch (IOException e) {
141 printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
142 }
143
144 // As long as we've read something, loop around encrypting, writing and reading
145 // bytesRead will be zero if nothing was read, or -1 on EOF - treat them both the same
146 while (bytesRead > 0) {
147
148 // Now encrypt this block
149
150
151 // Write the generated block to file
152 try {
153 out.write(outputBuffer);
154 } catch (IOException e) {
155 printErrorMessage("Error writing to output file " + args[2],e); System.exit(1);
156 }
157
158 // And read in the next block of the file
159 try {
160 bytesRead = in.read(inputBuffer);
161 } catch (IOException e) {
162 printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
163 }
164 }
165
166 // Now do the final processing
167
168
169
170
171
172
173
174
175 // Write the final block of output
176 try {
177 out.write(outputBuffer);
178 } catch (IOException e) {
179 printErrorMessage("Error on final write to output file " + args[2],e); System.exit(1);
180 }
181
182 // Close the output files
183 try {
184 in.close();
185 out.close();
186 } catch (IOException e) {
187 printErrorMessage("Error closing file", e);
188 }
189
190 // If we were continuing beyond this point, we should really overwrite key material, drop KeySpecs, etc.
191 }
192
193 /**
194 * Print an error message on stderr, optionally picking up additional detail from
195 * a passed exception
196 * @param errMsg
197 * @param e
198 */
199 private static void printErrorMessage(String errMsg, Exception e) {
200 System.err.println(errMsg);
201 if (e != null)
202 System.err.println(e.getMessage());
203 }
204
205 /**
206 * Print a usage message
207 */
208 private static void printUsageMessage() {
209 System.out.println(progName + " $Revision: 1.1 $: Usage: " + progName + " E/D infile outfile passphrase");
210 }
211
212}
213