Java – Symmetric-Key Cryptography example
Symmetric-Key Cryptography is an encryption system in which the same key is used for the encoding and decoding of the data. The safe distribution of the key is one of the drawbacks of this method, but what it lacks in security it gains in time complexity.
One should always assume that the encryption algorithms are publicly known and not rely on “Security through obscurity”. The most popular Symmetric Algorithms are DES, Triple-DES, AES, Blowfish, RC2, RC4(ARCFOUR), RC5, RC6.
1. Use Case of Symmetric Key Cryptography
Below you can see the code of an application that uses Symmetric-Key Cryptography to encrypt or decrypt a pre-set directory. The constructor is initialized with the password, the length of the key and the algorithm that will be used for the cipher. To learn more about the key lengths for each algorithm refer to Import Limits on Cryptographic Algorithms.
If you want to read more about Encryption Algorithms, refer to Performance Analysis of Data Encryption Algorithms: 2.5 Compared Algorithms
In this example we use AES as it is considered the silver lining between speed and security.
package com.mkyong.symmetric;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.swing.JOptionPane;
public class SymmetricKeyExample {
private SecretKeySpec secretKey;
private Cipher cipher;
public SymmetricKeyExample(String secret, int length, String algorithm)
throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException {
byte[] key = new byte[length];
key = fixSecret(secret, length);
this.secretKey = new SecretKeySpec(key, algorithm);
this.cipher = Cipher.getInstance(algorithm);
}
private byte[] fixSecret(String s, int length) throws UnsupportedEncodingException {
if (s.length() < length) {
int missingLength = length - s.length();
for (int i = 0; i < missingLength; i++) {
s += " ";
}
}
return s.substring(0, length).getBytes("UTF-8");
}
public void encryptFile(File f)
throws InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException {
System.out.println("Encrypting file: " + f.getName());
this.cipher.init(Cipher.ENCRYPT_MODE, this.secretKey);
this.writeToFile(f);
}
public void decryptFile(File f)
throws InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException {
System.out.println("Decrypting file: " + f.getName());
this.cipher.init(Cipher.DECRYPT_MODE, this.secretKey);
this.writeToFile(f);
}
public void writeToFile(File f) throws IOException, IllegalBlockSizeException, BadPaddingException {
FileInputStream in = new FileInputStream(f);
byte[] input = new byte[(int) f.length()];
in.read(input);
FileOutputStream out = new FileOutputStream(f);
byte[] output = this.cipher.doFinal(input);
out.write(output);
out.flush();
out.close();
in.close();
}
public static void main(String[] args) {
File dir = new File("src/cryptodir");
File[] filelist = dir.listFiles();
SymmetricKeyExample ske;
try {
ske = new SymmetricKeyExample("!@#$MySecr3tPassw0rd", 16, "AES");
int choice = -2;
while (choice != -1) {
String[] options = { "Encrypt All", "Decrypt All", "Exit" };
choice = JOptionPane.showOptionDialog(null, "Select an option", "Options", 0,
JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
switch (choice) {
case 0:
Arrays.asList(filelist).forEach(file -> {
try {
ske.encryptFile(file);
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException
| IOException e) {
System.err.println("Couldn't encrypt " + file.getName() + ": " + e.getMessage());
}
});
System.out.println("Files encrypted successfully");
break;
case 1:
Arrays.asList(filelist).forEach(file -> {
try {
ske.decryptFile(file);
} catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException
| IOException e) {
System.err.println("Couldn't decrypt " + file.getName() + ": " + e.getMessage());
}
});
System.out.println("Files decrypted successfully");
break;
default:
choice = -1;
break;
}
}
} catch (UnsupportedEncodingException ex) {
System.err.println("Couldn't create key: " + ex.getMessage());
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
System.err.println(e.getMessage());
}
}
}
Output
When the button “Encrypt All” is clicked.
Encrypting file: Hello world.docx
Encrypting file: Hello world.pdf
Encrypting file: Smiley.png
Encrypting file: Text.txt
Files encrypted successfully
When the button “Decrypt All” is clicked.
Decrypting file: Hello world.docx
Decrypting file: Hello world.pdf
Decrypting file: Smiley.png
Decrypting file: Text.txt
Files decrypted successfully
Original text file.
This is a text file.
Text file is encrypted.
‡(?ê?z@ou7ÿ—pø"é³.Õ0Ò;jVi¶‚
Be advised: Before you run this code creates a separate directory with files just for the purposes of this example. Download the source code below if you do not know exactly what you are doing.
I’m struggling with this myself, but I don’t think this is secure. Isn’t this just using CBC mode, which isn’t secure? Should it be using GCM?
Some comment or something about the reason behind the need for the fixSecret() method would have been nice.