Skip to content

Commit c72bf7d

Browse files
authored
Merge pull request #19 from modothprav/part-1
Part 1
2 parents f8d7084 + db81d56 commit c72bf7d

File tree

5 files changed

+205
-26
lines changed

5 files changed

+205
-26
lines changed

src/FileEncryptor.java

Lines changed: 170 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
import java.io.File;
12
import java.io.IOException;
23
import java.io.InputStream;
34
import java.io.OutputStream;
45
import java.nio.file.Files;
56
import java.nio.file.Path;
7+
import java.nio.file.Paths;
68
import java.security.InvalidAlgorithmParameterException;
79
import java.security.InvalidKeyException;
810
import java.security.NoSuchAlgorithmException;
911
import java.security.SecureRandom;
12+
import java.util.Arrays;
13+
import java.util.Base64;
1014
import java.util.logging.Level;
1115
import java.util.logging.Logger;
1216
import javax.crypto.Cipher;
@@ -16,62 +20,202 @@
1620
import javax.crypto.spec.IvParameterSpec;
1721
import javax.crypto.spec.SecretKeySpec;
1822

23+
1924
/**
2025
*
2126
* @author Erik Costlow
27+
* @author Pravin Modotholi
2228
*/
2329
public class FileEncryptor {
2430
private static final Logger LOG = Logger.getLogger(FileEncryptor.class.getSimpleName());
2531

2632
private static final String ALGORITHM = "AES";
2733
private static final String CIPHER = "AES/CBC/PKCS5PADDING";
2834

29-
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException {
35+
public static void main(String[] args) throws Exception {
36+
// Error Message
37+
final String validCmdMsg = "Valid Encryption command: java FileEncryptor enc [inputFile] [outputFile]\n"
38+
+ "Valid Decryption command: java FileEncryptor dec [Key] [Vector] [inputFile] [outputFile]";
39+
40+
if (args.length < 3) { throw new IllegalArgumentException("Not Enough Argunments specified\n" + validCmdMsg); }
41+
42+
// Convert String arguments to char arrays
43+
char[][] charArgs = Util.getCharArgunments(args);
44+
45+
// Clear String argunments
46+
Arrays.fill(args, null);
47+
48+
if (Arrays.equals(charArgs[0], "enc".toCharArray())) { // Encrypt
49+
encrypt(new String(charArgs[1]), new String(charArgs[2]));
3050

51+
} else if (Arrays.equals(charArgs[0], "dec".toCharArray())) { // Decrypt
52+
53+
if (charArgs.length < 5) { throw new IllegalArgumentException("Not Enough Argunments Provided for Decryption\n" + validCmdMsg ); }
54+
55+
// Decode the Base64 argunments
56+
byte[] key = Base64.getDecoder().decode(Util.convertCharToByte(charArgs[1]));
57+
byte[] initVector = Base64.getDecoder().decode(Util.convertCharToByte(charArgs[2]));
58+
59+
decrypt(key, initVector, new String(charArgs[3]), new String(charArgs[4]));
60+
61+
// Tear Down, clear arrays
62+
Arrays.fill(key, (byte) 0);
63+
Arrays.fill(initVector, (byte) 0);
64+
key = null; initVector = null;
65+
66+
for (int i = 0; i < charArgs.length; i++) {
67+
Arrays.fill(charArgs[i], '\0');
68+
}
69+
charArgs = null;
70+
71+
} else {
72+
throw new IllegalArgumentException("Neither enc (encrypt) or dec (decrypt) option specified\n" + validCmdMsg);
73+
}
74+
}
75+
76+
/**
77+
* Encrypts a plain text input file by outputing an encrypted version. It does this
78+
* generating a 128 bit secret key and initialisation vector which are used as
79+
* specifications during the file encryption process.
80+
*
81+
* @param inputPath - A String specifying the Input path of the plaintext file
82+
* @param outputPath - A String specifying the Ouput path of the ciphertext file
83+
* @throws NoSuchAlgorithmException
84+
* @throws NoSuchPaddingException
85+
* @throws InvalidKeyException
86+
* @throws InvalidAlgorithmParameterException
87+
* @throws IOException
88+
*/
89+
public static void encrypt(String inputPath, String outputPath) throws NoSuchAlgorithmException,
90+
NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException {
3191
//This snippet is literally copied from SymmetrixExample
3292
SecureRandom sr = new SecureRandom();
3393
byte[] key = new byte[16];
3494
sr.nextBytes(key); // 128 bit key
3595
byte[] initVector = new byte[16];
3696
sr.nextBytes(initVector); // 16 bytes IV
37-
System.out.println("Random key=" + Util.bytesToHex(key));
38-
System.out.println("initVector=" + Util.bytesToHex(initVector));
97+
98+
// Display the Base64 encoded versions of Key and Vector
99+
System.out.print("\n<---------------------------------------->\n");
100+
System.out.println("Secret Key is: " + Base64.getEncoder().encodeToString(key));
101+
System.out.println("IV is: " + Base64.getEncoder().encodeToString(initVector));
102+
System.out.print("<---------------------------------------->\n\n");
103+
104+
// Initialize Key and Vector Specfications and the Cipher mode
39105
IvParameterSpec iv = new IvParameterSpec(initVector);
40106
SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
41107
Cipher cipher = Cipher.getInstance(CIPHER);
42108
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
109+
110+
File outputFile = new File(outputPath);
111+
// Create the output file if it doesn't exist
112+
if (!outputFile.exists()) { outputFile.createNewFile(); }
43113

44-
//Look for files here
45-
final Path tempDir = Files.createTempDirectory("packt-crypto");
46-
47-
final Path encryptedPath = tempDir.resolve("1 - Encrypting and Decrypting files.pptx.encrypted");
48-
try (InputStream fin = FileEncryptor.class.getResourceAsStream("1 - Encrypting and Decrypting files.pptx");
49-
OutputStream fout = Files.newOutputStream(encryptedPath);
50-
CipherOutputStream cipherOut = new CipherOutputStream(fout, cipher) {
114+
final Path plaintextFile = Paths.get(inputPath);
115+
final Path encryptedFile = Paths.get(outputPath);
116+
117+
// Write plaintext into ciphertext
118+
if (writeEncryptedFile(plaintextFile, encryptedFile, cipher)) {
119+
LOG.info("Encryption finished, saved at " + encryptedFile);
120+
} else {
121+
LOG.log(Level.WARNING, "Encryption Failed, Ensure Valid File Paths are specified");
122+
}
123+
}
124+
125+
/**
126+
* Writes an encrypted version of the input file, into the output file.
127+
* Uses a FileInputStream to read the plaintext file and wraps the OutputStream
128+
* with a CipherOutStream to write an encrypted version of the plaintext file.
129+
* Returns True if the encryption writing was successfull, False otherwise.
130+
*
131+
* @param inputPath Path The file path of the input file (plaintext)
132+
* @param outputPath Path The file path of the output file (ciphertext)
133+
* @param cipher Cipher The cipher instance initialized with the appropriate
134+
* specifications in ENCRYPT mode
135+
* @return boolean True if encryption successful False otherwise
136+
*/
137+
private static boolean writeEncryptedFile(Path inputPath, Path outputPath, Cipher cipher) {
138+
try (InputStream fin = Files.newInputStream(inputPath);
139+
OutputStream fout = Files.newOutputStream(outputPath);
140+
CipherOutputStream cipherOut = new CipherOutputStream(fout, cipher) {
51141
}) {
52142
final byte[] bytes = new byte[1024];
53-
for(int length=fin.read(bytes); length!=-1; length = fin.read(bytes)){
143+
for(int length = fin.read(bytes); length != -1; length = fin.read(bytes)){
54144
cipherOut.write(bytes, 0, length);
55145
}
56146
} catch (IOException e) {
57-
LOG.log(Level.INFO, "Unable to encrypt", e);
147+
LOG.log(Level.INFO, "Unable to encrypt");
148+
return false;
58149
}
59-
60-
LOG.info("Encryption finished, saved at " + encryptedPath);
61-
150+
151+
return true;
152+
}
153+
154+
/**
155+
* Decrypts a given cipertext file into its original plaintext form.
156+
* A successful decryption occurs when provided with the right key and
157+
* initialisation vector to create the Cipher specifications required
158+
* for decryption. Will overwrite the resultant output file if it
159+
* already exists.
160+
*
161+
* @param key byte[] - The Key used to originally encrypt the input file
162+
* @param initVector byte[] - The initialisation vector originally used for encryption
163+
* @param inputPath String - The input file path (encrypted document)
164+
* @param outputPath String - The file path of the resultant decrypted text
165+
* @throws NoSuchAlgorithmException
166+
* @throws NoSuchPaddingException
167+
* @throws InvalidKeyException
168+
* @throws InvalidAlgorithmParameterException
169+
* @throws IOException
170+
*/
171+
public static void decrypt(byte[] key, byte[] initVector, String inputPath, String outputPath) throws NoSuchAlgorithmException,
172+
NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException {
173+
// Initialize Key and Vector Specifications and the Cipher Mode
174+
IvParameterSpec iv = new IvParameterSpec(initVector);
175+
SecretKeySpec skeySpec = new SecretKeySpec(key, ALGORITHM);
176+
Cipher cipher = Cipher.getInstance(CIPHER);
62177
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
63-
final Path decryptedPath = tempDir.resolve("1 - Encrypting and Decrypting files_decrypted.pptx");
64-
try(InputStream encryptedData = Files.newInputStream(encryptedPath);
65-
CipherInputStream decryptStream = new CipherInputStream(encryptedData, cipher);
66-
OutputStream decryptedOut = Files.newOutputStream(decryptedPath)){
67-
final byte[] bytes = new byte[1024];
68-
for(int length=decryptStream.read(bytes); length!=-1; length = decryptStream.read(bytes)){
69-
decryptedOut.write(bytes, 0, length);
70-
}
178+
179+
File outputFile = new File(outputPath);
180+
// Create a new Decrypted file if it doesn't exist
181+
if (!outputFile.exists()) { outputFile.createNewFile(); }
182+
183+
final Path encryptedFile = Paths.get(inputPath);
184+
final Path decryptedFile = Paths.get(outputPath);
185+
186+
if (writeDecryptedFile(encryptedFile, decryptedFile, cipher)) {
187+
LOG.info("Decryption complete, open " + decryptedFile);
188+
} else {
189+
LOG.log(Level.SEVERE, "Ensure the correct Key, Vector, and Files pahts are specified");
190+
}
191+
}
192+
193+
/**
194+
* Reads an encrypted file by wrapping an InputStream with a CipherInputStream
195+
* The encrypted files gets decrypted and written out to the output file.
196+
* For a successful decryption the Cipher new to be initialized in DECRYPT mode
197+
* with the correct key and vector specifications.
198+
*
199+
* @param inputPath Path The input file path (encrypted file)
200+
* @param outputPath Path The output file path (decrypted file)
201+
* @param cipher Cipher The cipher instance initialized with the appropriate
202+
* specifications in DECRYPT mode
203+
* @return boolean True if Decryption is successful False otherwise
204+
*/
205+
private static boolean writeDecryptedFile(Path inputPath, Path outputPath, Cipher cipher) {
206+
try(InputStream encryptedData = Files.newInputStream(inputPath);
207+
CipherInputStream decryptStream = new CipherInputStream(encryptedData, cipher);
208+
OutputStream decryptedOut = Files.newOutputStream(outputPath)) {
209+
210+
final byte[] bytes = new byte[1024];
211+
for(int length=decryptStream.read(bytes); length!=-1; length = decryptStream.read(bytes)){
212+
decryptedOut.write(bytes, 0, length);
213+
}
214+
71215
} catch (IOException ex) {
72-
Logger.getLogger(FileEncryptor.class.getName()).log(Level.SEVERE, "Unable to decrypt", ex);
216+
Logger.getLogger(FileEncryptor.class.getName()).log(Level.SEVERE, "Unable to decrypt");
217+
return false;
73218
}
74-
75-
LOG.info("Decryption complete, open " + decryptedPath);
219+
return true;
76220
}
77221
}

src/Util.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
/**
23
*
34
* @author Erik Costlow
@@ -17,4 +18,35 @@ public static String bytesToHex(byte[] bytes) {
1718
}
1819
return sb.toString();
1920
}
21+
22+
/**
23+
* Converts an array of Characters into an array of bytes
24+
*
25+
* @param chars An array of characters
26+
* @return byte[] An array of bytes
27+
*/
28+
public static byte[] convertCharToByte(char[] chars) {
29+
byte[] result = new byte[chars.length];
30+
for (int i = 0; i < chars.length; i++) {
31+
result[i] = (byte) chars[i];
32+
}
33+
return result;
34+
}
35+
36+
/**
37+
* Converts an arry of Strings into a 2-Dimensional array of
38+
* characters, each row representing the String as a char array
39+
* and each column in a row representing the individual char value
40+
*
41+
* @param args String[] An array of strings
42+
* @return char[][] A 2-Dimensional character array
43+
*/
44+
public static final char[][] getCharArgunments(String[] args) {
45+
char[][] charArgs = new char[args.length][];
46+
for (int i = 0; i < args.length; i++) {
47+
charArgs[i] = args[i].toCharArray();
48+
}
49+
return charArgs;
50+
}
51+
2052
}

src/resources/ciphertext.enc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
�(v({9�F]J~h- �O�%�AN$�S\=�Y�Xr�@����[��\'�

src/resources/decrypted.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is part one of the assignment

src/resources/plaintext.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is part one of the assignment

0 commit comments

Comments
 (0)