2626import javax .crypto .spec .PBEKeySpec ;
2727import javax .crypto .spec .SecretKeySpec ;
2828
29-
30-
31-
3229/**
3330 *
3431 * @author Erik Costlow
@@ -82,10 +79,10 @@ public static void main(String[] args) throws Exception {
8279
8380 /**
8481 * Encrypts a plain text input file by outputing an encrypted version. It does this
85- * generating a 128 bit secret key and initialisation vector which are used as the
86- * specifications during the file encryption process. A message aithentication code
87- * is also computed with the intialisaton vector and plaintext values, hence these
88- * values can be checked for tampering during decryption.
82+ * generating a secret key from a passowrd and an initialisation vector which are
83+ * used as the specifications during the file encryption process. A message
84+ * authentication code is also computed and initialised with the vector and plaintext
85+ * values, hence they can be checked for tampering during decryption.
8986 *
9087 * @param password char[] The password specified by the user
9188 * @param inputPath String specifying the Input path of the plaintext file
@@ -113,7 +110,6 @@ public static void encrypt(char[] password, String inputPath, String outputPath)
113110 Arrays .fill (password , '\0' ); password = null ;
114111
115112 SecretKeySpec macKeySpec = new SecretKeySpec (macKey , HASH_AlGORITHM );
116-
117113 Mac hmac = Mac .getInstance (HASH_AlGORITHM );
118114 hmac .init (macKeySpec );
119115
@@ -125,8 +121,7 @@ public static void encrypt(char[] password, String inputPath, String outputPath)
125121 final Path encryptedFile = Paths .get (outputPath );
126122
127123 // Compute Mac for authentication
128- hmac .update (initVector ); hmac .update (salt ); hmac .update (macSalt );
129- final byte [] mac = computeMac (hmac , plaintextFile );
124+ final byte [] mac = computeMac (hmac , plaintextFile , initVector , salt , macSalt );
130125
131126 // Display the Base64 encoded versions of Key, Vector and computed mac
132127 displayInformation (getPair ("Secret Key" , key ), getPair ("Init Vector" , initVector ), getPair ("Salt" , salt ),
@@ -163,10 +158,7 @@ private static boolean writeEncryptedFile(Path inputPath, Path outputPath, Ciphe
163158
164159 try (FileOutputStream fout = new FileOutputStream (outputPath .toFile ());) {
165160 // Write Metadata
166- fout .write (cipher .getIV ());
167- fout .write (salt );
168- fout .write (macSalt );
169- fout .write (mac );
161+ fout .write (cipher .getIV ()); fout .write (salt ); fout .write (macSalt ); fout .write (mac );
170162
171163 try (CipherOutputStream cipherOut = new CipherOutputStream (fout , cipher );) {
172164 final byte [] bytes = new byte [1024 ];
@@ -186,7 +178,8 @@ private static boolean writeEncryptedFile(Path inputPath, Path outputPath, Ciphe
186178 /**
187179 * Decrypts a given cipertext file into its original plaintext form.
188180 * A successful decryption occurs when provided with the right password
189- * to create the Cipher specifications required for decryption.
181+ * to create the Cipher specifications required for decryption. The
182+ * decryption will also fail if any tampering were to be observed.
190183 * Will overwrite the resultant output file if it already exists.
191184 *
192185 * @param password char[] The password specified by the user
@@ -222,7 +215,7 @@ public static void decrypt(char[] password, String inputPath, String outputPath)
222215 * The encrypted files gets decrypted and written out to the output file.
223216 * For a successful decryption the Cipher needs to be initialized in DECRYPT mode
224217 * with the correct key and vector specifications. The IV, salts and mac is read
225- * from the encrypted file as it was saved unencrypted during the encryption process.
218+ * from the encrypted file as it was saved as metadata during the encryption process.
226219 * Decryption will also fail if the computed authentication code doesn't match with
227220 * the given authentication code.
228221 *
@@ -270,9 +263,7 @@ private static boolean writeDecryptedFile(Path inputPath, Path outputPath, char[
270263 // Check authentication and file integerity
271264 Mac hmac = Mac .getInstance (HASH_AlGORITHM );
272265 hmac .init (macKeySpec );
273-
274- hmac .update (initVector ); hmac .update (salt ); hmac .update (macSalt );
275- final byte [] computedMac = computeMac (hmac , outputPath );
266+ final byte [] computedMac = computeMac (hmac , outputPath , initVector , salt , macSalt );
276267
277268 if (!Arrays .equals (givenMac , computedMac )) {
278269 throw new SecurityException ("Authentication failed, file may have been tampered with" );
@@ -349,15 +340,21 @@ private static Cipher createCipher(byte[] key, byte[] initVector, int mode) thro
349340
350341 /**
351342 * Computes a Message authencitaion code for a given inputfile
352- * Takes in an initialised hmac which gets updated with the file's
353- * contents line by line. Once completed the doFinal method will
354- * return a byte array with the computed Mac.
343+ * and any metadata that will be added to the file. Takes in an
344+ * initialised hmac which gets updated with the file's contents
345+ * line by line. Once completed the doFinal method will return a
346+ * byte array with the computed Mac.
355347 *
356348 * @param hmac Mac The initialised Mac object
357349 * @param filePath Path The file path
350+ * @param metadata byte[] Metadata that will be added to the input file
358351 * @return byte[] The file's computed Mac
359352 */
360- private static byte [] computeMac (Mac hmac , Path filePath ) {
353+ private static byte [] computeMac (Mac hmac , Path filePath , byte []... metadata ) {
354+ // feed metadata into mac
355+ for (byte [] data : metadata ) { hmac .update (data ); }
356+
357+ // feed input file into mac
361358 try (InputStream fin = Files .newInputStream (filePath );) {
362359 final byte [] bytes = new byte [1024 ];
363360 for (int length = fin .read (bytes ); length != -1 ; length = fin .read (bytes )){
0 commit comments