Java AES and using my own Key

JavaKeyAes

Java Problem Overview


I want to encrypt a string using AES with my own key. But I'm having trouble with the bit length of the key. Can you review my code and see what I need to fix/change.

public static void main(String[] args) throws Exception {
	String username = "[email protected]";
	String password = "Password1";
	String secretID = "BlahBlahBlah";
	String SALT2 = "deliciously salty";

	// Get the Key
	byte[] key = (SALT2 + username + password).getBytes();
	System.out.println((SALT2 + username + password).getBytes().length);
	
	// Need to pad key for AES
	// TODO: Best way?
	
	// Generate the secret key specs.
	SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

	// Instantiate the cipher
	Cipher cipher = Cipher.getInstance("AES");
	cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

	byte[] encrypted = cipher.doFinal((secrectID).getBytes());
	System.out.println("encrypted string: " + asHex(encrypted));

	cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
	byte[] original = cipher.doFinal(encrypted);
	String originalString = new String(original);
	System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " + asHex(original));
}

Right now I get an exception "Invalid AES key length: 86 bytes". Do I need to pad my key? How should I do it?

Also do I need to set anything for ECB or CBC?

Thanks

Java Solutions


Solution 1 - Java

Edit:

As written in the comments the old code is not "best practice". You should use a keygeneration algorithm like PBKDF2 with a high iteration count. You also should use at least partly a non static (meaning for each "identity" exclusive) salt. If possible randomly generated and stored together with the ciphertext.

    SecureRandom sr = SecureRandom.getInstanceStrong();
	byte[] salt = new byte[16];
	sr.nextBytes(salt);

	PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 128 * 8);
	SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);
	Cipher aes = Cipher.getInstance("AES");
	aes.init(Cipher.ENCRYPT_MODE, key);

=========== Old Answer

You should use SHA-1 to generate a hash from your key and trim the result to 128 bit (16 bytes).

Additionally don't generate byte arrays from Strings through getBytes() it uses the platform default Charset. So the password "blaöä" results in different byte array on different platforms.

byte[] key = (SALT2 + username + password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

Edit: If you need 256 bit as key sizes you need to download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files" Oracle download link, use SHA-256 as hash and remove the Arrays.copyOf line. "ECB" is the default Cipher Mode and "PKCS5Padding" the default padding. You could use different Cipher Modes and Padding Modes through the Cipher.getInstance string using following format: "Cipher/Mode/Padding"

For AES using CTS and PKCS5Padding the string is: "AES/CTS/PKCS5Padding"

Solution 2 - Java

You should use a KeyGenerator to generate the Key,

AES key lengths are 128, 192, and 256 bit depending on the cipher you want to use.

Take a look at the tutorial here

Here is the code for Password Based Encryption, this has the password being entered through System.in you can change that to use a stored password if you want.

        PBEKeySpec pbeKeySpec;
        PBEParameterSpec pbeParamSpec;
        SecretKeyFactory keyFac;

        // Salt
        byte[] salt = {
            (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
            (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
        };

        // Iteration count
        int count = 20;

        // Create PBE parameter set
        pbeParamSpec = new PBEParameterSpec(salt, count);

        // Prompt user for encryption password.
        // Collect user password as char array (using the
        // "readPassword" method from above), and convert
        // it into a SecretKey object, using a PBE key
        // factory.
        System.out.print("Enter encryption password:  ");
        System.out.flush();
        pbeKeySpec = new PBEKeySpec(readPassword(System.in));
        keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

        // Create PBE Cipher
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

        // Initialize PBE Cipher with key and parameters
        pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

        // Our cleartext
        byte[] cleartext = "This is another example".getBytes();

        // Encrypt the cleartext
        byte[] ciphertext = pbeCipher.doFinal(cleartext);

Solution 3 - Java

import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;
import java.io.BufferedReader;
import java.io.FileReader;

public class AESFile 
{
private static String algorithm = "AES";
private static byte[] keyValue=new byte[] {'0','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7'};// your key

    // Performs Encryption
    public static String encrypt(String plainText) throws Exception 
    {
            Key key = generateKey();
            Cipher chiper = Cipher.getInstance(algorithm);
            chiper.init(Cipher.ENCRYPT_MODE, key);
            byte[] encVal = chiper.doFinal(plainText.getBytes());
            String encryptedValue = new BASE64Encoder().encode(encVal);
            return encryptedValue;
    }

    // Performs decryption
    public static String decrypt(String encryptedText) throws Exception 
    {
            // generate key 
            Key key = generateKey();
            Cipher chiper = Cipher.getInstance(algorithm);
            chiper.init(Cipher.DECRYPT_MODE, key);
            byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedText);
            byte[] decValue = chiper.doFinal(decordedValue);
            String decryptedValue = new String(decValue);
            return decryptedValue;
    }

//generateKey() is used to generate a secret key for AES algorithm
    private static Key generateKey() throws Exception 
    {
            Key key = new SecretKeySpec(keyValue, algorithm);
            return key;
    }

    // performs encryption & decryption 
    public static void main(String[] args) throws Exception 
    {
	    FileReader file = new FileReader("C://myprograms//plaintext.txt");
		BufferedReader reader = new BufferedReader(file);
	    String text = "";
		String line = reader.readLine();
	while(line!= null)
		{
			text += line;
	line = reader.readLine();
	    }
		reader.close();
	System.out.println(text);

            String plainText = text;
            String encryptedText = AESFile.encrypt(plainText);
            String decryptedText = AESFile.decrypt(encryptedText);

            System.out.println("Plain Text : " + plainText);
            System.out.println("Encrypted Text : " + encryptedText);
            System.out.println("Decrypted Text : " + decryptedText);
    }
}

Solution 4 - Java

MD5, AES, no padding

import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static org.apache.commons.io.Charsets.UTF_8;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class PasswordUtils {

	private PasswordUtils() {}

	public static String encrypt(String text, String pass) {
		try {
			MessageDigest messageDigest = MessageDigest.getInstance("MD5");
			Key key = new SecretKeySpec(messageDigest.digest(pass.getBytes(UTF_8)), "AES");
			Cipher cipher = Cipher.getInstance("AES");
			cipher.init(ENCRYPT_MODE, key);

			byte[] encrypted = cipher.doFinal(text.getBytes(UTF_8));
			byte[] encoded = Base64.getEncoder().encode(encrypted);
    		return new String(encoded, UTF_8);

		} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
			throw new RuntimeException("Cannot encrypt", e);
		}
	}

	public static String decrypt(String text, String pass) {
		try {
			MessageDigest messageDigest = MessageDigest.getInstance("MD5");
			Key key = new SecretKeySpec(messageDigest.digest(pass.getBytes(UTF_8)), "AES");
			Cipher cipher = Cipher.getInstance("AES");
			cipher.init(DECRYPT_MODE, key);
			
			byte[] decoded = Base64.getDecoder().decode(text.getBytes(UTF_8));
			byte[] decrypted = cipher.doFinal(decoded);
			return new String(decrypted, UTF_8);
			
		} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
			throw new RuntimeException("Cannot decrypt", e);
		}
	}
}

Solution 5 - Java

This wll work.

public class CryptoUtils {
    
    private  final String TRANSFORMATION = "AES";
    private  final String encodekey = "1234543444555666";
    public  String encrypt(String inputFile)
            throws CryptoException {
        return doEncrypt(encodekey, inputFile);
    }


    public  String decrypt(String input)
            throws CryptoException {
    // return  doCrypto(Cipher.DECRYPT_MODE, key, inputFile);
    return doDecrypt(encodekey,input);
    }

    private  String doEncrypt(String encodekey, String inputStr)   throws CryptoException {
        try {

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        
            byte[] key = encodekey.getBytes("UTF-8");
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16); // use only first 128 bit

            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
        
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

            byte[] inputBytes = inputStr.getBytes();     
            byte[] outputBytes = cipher.doFinal(inputBytes);

            return Base64Utils.encodeToString(outputBytes);

        } catch (NoSuchPaddingException | NoSuchAlgorithmException
                | InvalidKeyException | BadPaddingException
                | IllegalBlockSizeException | IOException ex) {
            throw new CryptoException("Error encrypting/decrypting file", ex);
       }
     }


    public  String doDecrypt(String encodekey,String encrptedStr) { 
	      try {   	
		  
		      Cipher dcipher = Cipher.getInstance(TRANSFORMATION);
		      dcipher = Cipher.getInstance("AES");
		      byte[] key = encodekey.getBytes("UTF-8");
              MessageDigest sha = MessageDigest.getInstance("SHA-1");
              key = sha.digest(key);
              key = Arrays.copyOf(key, 16); // use only first 128 bit

              SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
          
              dcipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
	        // decode with base64 to get bytes
	
              byte[] dec = Base64Utils.decode(encrptedStr.getBytes());	
              byte[] utf8 = dcipher.doFinal(dec);

              // create new string based on the specified charset
              return new String(utf8, "UTF8");

	      } catch (Exception e) {

	        e.printStackTrace();

	      }
	  return null;
      }
 }

Solution 6 - Java

    byte[] seed = (SALT2 + username + password).getBytes();
    SecureRandom random = new SecureRandom(seed);
    KeyGenerator generator;
    generator = KeyGenerator.getInstance("AES");
    generator.init(random);
    generator.init(256);
    Key keyObj = generator.generateKey();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBernie PerezView Question on Stackoverflow
Solution 1 - JavamknjcView Answer on Stackoverflow
Solution 2 - JavaKeiboshView Answer on Stackoverflow
Solution 3 - JavaShankar MurthyView Answer on Stackoverflow
Solution 4 - JavaMikeView Answer on Stackoverflow
Solution 5 - JavaTaranView Answer on Stackoverflow
Solution 6 - JavasonnykweView Answer on Stackoverflow