patternjavaMinor
AES-128 encryption class
Viewed 0 times
128encryptionclassaes
Problem
This is the first time I've written a class in Java to do encryption using AES. Since security is involved I would love it if someone could take a look at it and let me know if anything is wrong with my implementation. Additionally, any feedback about shortcuts I could have taken or sloppy processes I've used would be greatly appreciated!
```
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class Encrypt {
private Cipher encryptCipher;
private SecretKey key;
private IvParameterSpec iv;
private byte[] clearText;
/**
* Encrypts data using AES-128
* @param clearText The data to be encrypted
*/
public Encrypt(String clearText) {
//Generate the IV and key
this.iv = new IvParameterSpec(this.generateIv());
this.key = this.generateKey();
//Create an AES cipher in CBC mode using PKCS5 padding
try {
this.encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try {
this.encryptCipher.init(Cipher.ENCRYPT_MODE, this.key, this.iv);
}
catch(InvalidKeyException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
}
catch(InvalidAlgorithmParameterException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
}
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.get
```
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class Encrypt {
private Cipher encryptCipher;
private SecretKey key;
private IvParameterSpec iv;
private byte[] clearText;
/**
* Encrypts data using AES-128
* @param clearText The data to be encrypted
*/
public Encrypt(String clearText) {
//Generate the IV and key
this.iv = new IvParameterSpec(this.generateIv());
this.key = this.generateKey();
//Create an AES cipher in CBC mode using PKCS5 padding
try {
this.encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try {
this.encryptCipher.init(Cipher.ENCRYPT_MODE, this.key, this.iv);
}
catch(InvalidKeyException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
}
catch(InvalidAlgorithmParameterException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
}
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.get
Solution
Here's my final implementation with the changes based on @Robert Snyder's comment:
My first suggestion is to make refactor a little bit your constructor.
Start by making a Method
that method. Then make another method
make your constructor easier to read. As for your random IV generator
you might want to consider a lesson from how Mifare Desfire passes
enciphered data. You basically start with a IV of 0x00 and have a key
that is known elsewhere. In the end hacking is much more difficult.
```
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class Encrypt {
private Cipher encryptCipher;
private SecretKey key;
private IvParameterSpec iv;
private byte[] clearText;
private byte[] encryptedText;
/**
* Encrypts data using AES-128
* @param clearText The data to be encrypted
*/
public Encrypt(String clearText) {
//Generate the IV and key
this.iv = new IvParameterSpec(this.generateIv());
this.key = this.generateKey();
this.encryptCipher = createCipher();
this.clearText = this.convertClearText(clearText);
this.encryptedText = this.encrypt();
}
/**
* Converts the clear text passed by the user to an array of bytes
* @param clearText The clear text passed by the user
* @return The byte representation of the clear text
*/
private byte[] convertClearText(String clearText) {
//Convert the clear text passed by the user into bytes
try {
return clearText.getBytes("UTF-8");
}
catch(UnsupportedEncodingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Creates an AES cipher using CBC mode with PKCS5 padding
* @return The cipher used to encrypt data
*/
private Cipher createCipher() {
//Create an AES cipher in CBC mode using PKCS5 padding
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.iv);
return cipher;
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(NoSuchPaddingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(InvalidKeyException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(InvalidAlgorithmParameterException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Generates a random IV to be used in the encryption process
* @return The IV's byte representation
*/
private byte[] generateIv() {
SecureRandom random = new SecureRandom();
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
return ivBytes;
}
/**
* Generates a secret key to be used in the encryption process
* @return The secret key
*/
private SecretKey generateKey() {
KeyGenerator keygen;
try {
//Java normally doesn't support 256-bit key sizes without an extra installation so stick with a 128-bit key
keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
SecretKey aesKey = keygen.generateKey();
return aesKey;
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Returns the initialization vector
* @return The randomly generated IV
*/
public IvParameterSpec getIv() {
return this.iv;
}
/**
* Returns the key used for encryption
* @return The randomly generated secret key
*/
public SecretKey getKey() {
return this.key;
}
/**
* Encrypts the data passed during instantiation of this object
* @return The byte representation of the encrypted data
*/
public final byte[] encrypt() {
try {
return this.encr
My first suggestion is to make refactor a little bit your constructor.
Start by making a Method
getCipherInstance() put your try catches inthat method. Then make another method
initializeCipher() This willmake your constructor easier to read. As for your random IV generator
you might want to consider a lesson from how Mifare Desfire passes
enciphered data. You basically start with a IV of 0x00 and have a key
that is known elsewhere. In the end hacking is much more difficult.
```
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class Encrypt {
private Cipher encryptCipher;
private SecretKey key;
private IvParameterSpec iv;
private byte[] clearText;
private byte[] encryptedText;
/**
* Encrypts data using AES-128
* @param clearText The data to be encrypted
*/
public Encrypt(String clearText) {
//Generate the IV and key
this.iv = new IvParameterSpec(this.generateIv());
this.key = this.generateKey();
this.encryptCipher = createCipher();
this.clearText = this.convertClearText(clearText);
this.encryptedText = this.encrypt();
}
/**
* Converts the clear text passed by the user to an array of bytes
* @param clearText The clear text passed by the user
* @return The byte representation of the clear text
*/
private byte[] convertClearText(String clearText) {
//Convert the clear text passed by the user into bytes
try {
return clearText.getBytes("UTF-8");
}
catch(UnsupportedEncodingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Creates an AES cipher using CBC mode with PKCS5 padding
* @return The cipher used to encrypt data
*/
private Cipher createCipher() {
//Create an AES cipher in CBC mode using PKCS5 padding
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.iv);
return cipher;
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(NoSuchPaddingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(InvalidKeyException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(InvalidAlgorithmParameterException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Generates a random IV to be used in the encryption process
* @return The IV's byte representation
*/
private byte[] generateIv() {
SecureRandom random = new SecureRandom();
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
return ivBytes;
}
/**
* Generates a secret key to be used in the encryption process
* @return The secret key
*/
private SecretKey generateKey() {
KeyGenerator keygen;
try {
//Java normally doesn't support 256-bit key sizes without an extra installation so stick with a 128-bit key
keygen = KeyGenerator.getInstance("AES");
keygen.init(128);
SecretKey aesKey = keygen.generateKey();
return aesKey;
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Returns the initialization vector
* @return The randomly generated IV
*/
public IvParameterSpec getIv() {
return this.iv;
}
/**
* Returns the key used for encryption
* @return The randomly generated secret key
*/
public SecretKey getKey() {
return this.key;
}
/**
* Encrypts the data passed during instantiation of this object
* @return The byte representation of the encrypted data
*/
public final byte[] encrypt() {
try {
return this.encr
Code Snippets
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class Encrypt {
private Cipher encryptCipher;
private SecretKey key;
private IvParameterSpec iv;
private byte[] clearText;
private byte[] encryptedText;
/**
* Encrypts data using AES-128
* @param clearText The data to be encrypted
*/
public Encrypt(String clearText) {
//Generate the IV and key
this.iv = new IvParameterSpec(this.generateIv());
this.key = this.generateKey();
this.encryptCipher = createCipher();
this.clearText = this.convertClearText(clearText);
this.encryptedText = this.encrypt();
}
/**
* Converts the clear text passed by the user to an array of bytes
* @param clearText The clear text passed by the user
* @return The byte representation of the clear text
*/
private byte[] convertClearText(String clearText) {
//Convert the clear text passed by the user into bytes
try {
return clearText.getBytes("UTF-8");
}
catch(UnsupportedEncodingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Creates an AES cipher using CBC mode with PKCS5 padding
* @return The cipher used to encrypt data
*/
private Cipher createCipher() {
//Create an AES cipher in CBC mode using PKCS5 padding
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.iv);
return cipher;
}
catch(NoSuchAlgorithmException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(NoSuchPaddingException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(InvalidKeyException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
catch(InvalidAlgorithmParameterException ex) {
Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
/**
* Generates a random IV to be used in the encryption process
* @return The IV's byte representation
*/import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public final class Encrypt {
private Cipher encryptCipher;
private SecretKey key;
private IvParameterSpec iv;
private byte[] clearText;
private byte[] encryptedText;
/**
* Encrypts data using AES-128
*
* @param clearText The data to be encrypted
* @throws java.security.NoSuchAlgorithmException
* @throws javax.crypto.NoSuchPaddingException
* @throws java.security.InvalidKeyException
* @throws javax.crypto.BadPaddingException
* @throws java.security.InvalidAlgorithmParameterException
* @throws javax.crypto.IllegalBlockSizeException
* @throws java.io.UnsupportedEncodingException
*/
public Encrypt(String clearText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException {
//Generate the IV and key
this.iv = new IvParameterSpec(this.generateIv());
this.key = this.generateKey();
this.encryptCipher = createCipher();
this.clearText = this.convertClearText(clearText);
this.encryptedText = this.encrypt();
}
/**
* Converts the clear text passed by the user to an array of bytes
*
* @param clearText The clear text passed by the user
* @return The byte representation of the clear text
*/
private byte[] convertClearText(String clearText) throws UnsupportedEncodingException {
//Convert the clear text passed by the user into bytes
return clearText.getBytes("UTF-8");
}
/**
* Creates an AES cipher using CBC mode with PKCS5 padding
*
* @return The cipher used to encrypt data
*/
private Cipher createCipher() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
//Create an AES cipher in CBC mode using PKCS5 padding
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, this.key, this.iv);
return cipher;
}
/**
* Generates a random IV to be used in the encryption process
*
* @return The IV's byte representation
*/
private byte[] generateIv() {
SecureRandom random = new SecureRandom();
byte[] ivBytes = new byte[16];
random.nextBytes(ivBytes);
return ivBytes;
}
/**
* Generates a secContext
StackExchange Code Review Q#25548, answer score: 3
Revisions (0)
No revisions yet.