|
4 | 4 | import java.io.IOException; |
5 | 5 | import java.io.InputStream; |
6 | 6 | import java.io.OutputStream; |
| 7 | +import java.nio.ByteBuffer; |
7 | 8 | import java.nio.file.Files; |
8 | 9 | import java.nio.file.Path; |
9 | 10 | import java.nio.file.Paths; |
@@ -42,10 +43,8 @@ public class FileEncryptor { |
42 | 43 | private static final String DEFAULT_CIPHER = "AES/CBC/PKCS5PADDING"; |
43 | 44 | private static final int ITERATION_COUNT = 100000; |
44 | 45 |
|
45 | | - private static String ALGORITHM; |
46 | | - private static String CIPHER; |
47 | | - private static int KEY_LENGTH; |
48 | | - private static int BLOCKSIZE; |
| 46 | + private static String ALGORITHM, CIPHER; |
| 47 | + private static int KEY_LENGTH, BLOCKSIZE; |
49 | 48 |
|
50 | 49 | // Error Message |
51 | 50 | private static final String ERROR_MSG = "\nValid Encryption command: java FileEncryptor enc [Passoword] [inputFile] [outputFile]\n" |
@@ -78,21 +77,19 @@ public static void main(String[] args) throws Exception { |
78 | 77 | if (charArgs.length < 4) { throw new IllegalArgumentException("Not Enough Argunments specified\n" + ERROR_MSG); } |
79 | 78 |
|
80 | 79 | // Options Available |
81 | | - char[] enc = "enc".toCharArray(); |
82 | | - char[] dec = "dec".toCharArray(); |
| 80 | + char[] enc = "enc".toCharArray(), dec = "dec".toCharArray(); |
83 | 81 |
|
84 | 82 | if (!Arrays.equals(charArgs[0], enc) && !Arrays.equals(charArgs[0], dec)) { |
85 | 83 | throw new IllegalArgumentException("Neither enc (encrypt), dec (decrypt) or info option specified\n" + ERROR_MSG); |
86 | 84 | } |
87 | 85 |
|
88 | 86 | if (Arrays.equals(charArgs[0], enc)) { // Encrypt |
89 | 87 |
|
90 | | - char[] aes = "AES".toCharArray(); |
91 | | - char [] blowfish = "Blowfish".toCharArray(); |
| 88 | + char[] aes = "AES".toCharArray(), blowfish = "Blowfish".toCharArray(); |
92 | 89 |
|
93 | 90 | int argIndex = 1; // will get incremented everytime a valid argument is encountered |
94 | 91 |
|
95 | | - // If no or incompatiable algorithm argument is specified the Default will be applied |
| 92 | + // If incompatiable or no algorithm argument is specified the Default will be applied |
96 | 93 | if (Arrays.equals(charArgs[argIndex], aes) || Arrays.equals(charArgs[argIndex], blowfish)) { |
97 | 94 | ALGORITHM = new String(charArgs[1]); |
98 | 95 | CIPHER = ALGORITHM + "/CBC/PKCS5PADDING"; |
@@ -134,7 +131,6 @@ public static void main(String[] args) throws Exception { |
134 | 131 | } else if (Arrays.equals(charArgs[0], dec)) { // Decrypt |
135 | 132 | if (charArgs.length > 4) { throw new IllegalArgumentException("Too many arguments specified for decryption" + ERROR_MSG); } |
136 | 133 | decrypt(charArgs[1], new String(charArgs[2]), new String(charArgs[3])); |
137 | | - |
138 | 134 | } |
139 | 135 |
|
140 | 136 | // Tear Down, clear arrays |
@@ -189,8 +185,14 @@ public static void encrypt(char[] password, String inputPath, String outputPath) |
189 | 185 | final Path plaintextFile = Paths.get(inputPath); |
190 | 186 | final Path encryptedFile = Paths.get(outputPath); |
191 | 187 |
|
| 188 | + // Convert int to byte array to feed into Hmac |
| 189 | + final byte[] blocksize = ByteBuffer.allocate(8).putInt(BLOCKSIZE).array(); |
| 190 | + final byte[] keyLength = ByteBuffer.allocate(8).putInt(KEY_LENGTH/8).array(); |
| 191 | + final byte[] algoLength = ByteBuffer.allocate(8).putInt(ALGORITHM.getBytes().length).array(); |
| 192 | + |
192 | 193 | // Compute Mac for authentication |
193 | | - final byte[] mac = computeMac(hmac, plaintextFile, initVector, salt, macSalt); |
| 194 | + final byte[] mac = computeMac(hmac, plaintextFile, blocksize, keyLength, algoLength, |
| 195 | + ALGORITHM.getBytes(), initVector, salt, macSalt); |
194 | 196 |
|
195 | 197 | // Display the Base64 encoded versions of Key, Vector and computed mac |
196 | 198 | displayInformation(getPair("Secret Key", key), getPair("Init Vector", initVector), getPair("Salt", salt), |
@@ -227,8 +229,8 @@ private static boolean writeEncryptedFile(Path inputPath, Path outputPath, Ciphe |
227 | 229 |
|
228 | 230 | try (FileOutputStream fout = new FileOutputStream(outputPath.toFile());) { |
229 | 231 | // Write Metadata |
230 | | - final byte[] algorithm = Util.convertCharToByte(ALGORITHM.toCharArray()); |
231 | | - |
| 232 | + final byte[] algorithm = ALGORITHM.getBytes(); |
| 233 | + |
232 | 234 | fout.write(BLOCKSIZE); fout.write(KEY_LENGTH/8); fout.write(algorithm.length); |
233 | 235 | fout.write(algorithm); fout.write(cipher.getIV()); fout.write(salt); |
234 | 236 | fout.write(macSalt); fout.write(mac); |
@@ -337,7 +339,14 @@ private static boolean writeDecryptedFile(Path inputPath, Path outputPath, char[ |
337 | 339 | // Check authentication and file integerity |
338 | 340 | Mac hmac = Mac.getInstance(HASH_AlGORITHM); |
339 | 341 | hmac.init(macKeySpec); |
340 | | - final byte[] computedMac = computeMac(hmac, outputPath, initVector, salt, macSalt); |
| 342 | + |
| 343 | + // Convert int to byte array to feed into mac |
| 344 | + final byte[] blocksize = ByteBuffer.allocate(8).putInt(BLOCKSIZE).array(); |
| 345 | + final byte[] keyLength = ByteBuffer.allocate(8).putInt(KEY_LENGTH/8).array(); |
| 346 | + final byte[] algoLengthArry = ByteBuffer.allocate(8).putInt(ALGORITHM.getBytes().length).array(); |
| 347 | + |
| 348 | + final byte[] computedMac = computeMac(hmac, outputPath, blocksize, keyLength, |
| 349 | + algoLengthArry, ALGORITHM.getBytes(), initVector, salt, macSalt); |
341 | 350 |
|
342 | 351 | if (!Arrays.equals(givenMac, computedMac)) { |
343 | 352 | throw new SecurityException("Authentication failed, file may have been tampered with"); |
|
0 commit comments