2

So I know next to nothing about encryption - but I am trying to figure it all out. I got some example code from here but I can't figure out how to call the decrypt method when I restart the program and the INSTANCE gets reset. I'm guessing I need some way of storing the salt and parsing it to the decrypt method? Any help appreciated.

This is the code:

public class AES {

    private static final String password = "encrypt";
    private static String salt;
    private static final int pswdIterations = 65536;
    private static final int keySize = 128;
    private byte[] ivBytes;

    public String encrypt(String plainText) throws Exception {

        //get salt
        salt = generateSalt();
        byte[] saltBytes = salt.getBytes("UTF-8");

        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(
                password.toCharArray(),
                saltBytes,
                pswdIterations,
                keySize
        );

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        //encrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
        return new Base64().encodeAsString(encryptedTextBytes);
    }

    @SuppressWarnings("static-access")
    public String decrypt(String encryptedText) throws Exception {

        byte[] saltBytes = salt.getBytes("UTF-8");
        byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText);

        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(
                password.toCharArray(),
                saltBytes,
                pswdIterations,
                keySize
        );

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // Decrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));

        byte[] decryptedTextBytes = null;
        try {
            decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
        }

        return new String(decryptedTextBytes);
    }

    public String generateSalt() {
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[20];
        random.nextBytes(bytes);
        String s = new String(bytes);
        return s;
    }
}
Julien Vincent
  • 1,210
  • 3
  • 17
  • 40

1 Answers1

1

One common method is is to use the generated random salt as byte[] directly and concatenate it in front of the ciphertext before encoding it as base 64. This would be an extremely good idea for the given code, as the line:

String s = new String(bytes);

within the generateSalt method is faulty and may lose information. This would mean that the wrong key is generated, which means that the plaintext is lost (unless recovered by brute forcing the salt). To make things fun, this only happens for specific values of the salt bytes, i.e. irregularly.

Hint: don't rely on random code found on the Internet to learn crypto. You'll only learn how to do it incorrectly (there are stackoverflow answers with over 100 votes that contain insecure cryptography!).

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263