smert
smert

Reputation: 23

AES Encryption and Decryption in Java

I am fairly new to encryption/decryption and have to encrypt some data files, but am not entirely sure I am going about it the right way. Right now, I have a script to encrypt all the files, which is not included in my repo, but the decrypter is included in the repo and the encryption key is read in as an environment variable. I'm assuming even including the decrypter in the repo is bad practice because the algorithm/mode/padding is visible within the code as you can see below.

Aside from that, after some research, it looks like if an attacker knows the initialization vector, they would be able to decrypt the first block in the encrypted file. Am I understanding that right? Also, I have read that the vector should be randomly generated each time but I do not understand how I can do this considering the encrypter would only be run once unless I change the way I go about encrypting files.

One last question...would it make sense to have another environment variable to store the initialization vector being used? I assume not, because of the randomization of the vector being sought after.

    private static byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    private static IvParameterSpec ivspec = new IvParameterSpec(iv);
    private static byte[] decodedKey = Base64.getDecoder().decode(System.getenv("SECRET_KEY"));
    private static SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");

    //any encrypted input file that is not a database will be read in as an input stream
    public static CipherInputStream decryptInputStream(InputStream inputStream) {
        try{
            // Initialize the cipher by specifying the algorithm/mode/padding
            Cipher aes2 = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //
            aes2.init(Cipher.DECRYPT_MODE, originalKey, ivspec);

            CipherInputStream in = new CipherInputStream(inputStream, aes2);

            return in;
        } catch(NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e){
            logger.info(e.getMessage());
            return null;
        }
    }

Upvotes: 1

Views: 749

Answers (1)

gusto2
gusto2

Reputation: 12075

but am not entirely sure I am going about it the right way.

I have a few examples of my own for using crypto.

Aside static IV (already commented) you are missing some form of integrity control (seach for "authenticated encryption"). It can be achieved using modes with integrity built-in (such as AES-CGM) or using HMAC.

I'm assuming even including the decrypter in the repo is bad practice because the algorithm/mode/padding is visible within the code as you can see below.

Whether algorithm/mode/padding is visible should have no effect on the solution security. The only thing you need to protect is the key.

Aside from that, after some research, it looks like if an attacker knows the initialization vector, they would be able to decrypt the first block in the encrypted file.

That's not true. IV needs to be unique (and for CBC the IV needs to be unpredictable/random) for each encryption operation performed with the same key (thx Maarten). Known IV doesn't help attacker to decrypt anything.

As already commented - IV is usually passed as part of the ciphertext. Very often the encryption result looks like IV || ciphertext || MAC where || is denoting concatenation. Size of IV and MAC are fixed, so when decrypting, it's simple to split the parameters.

Am I understanding that right? Also, I have read that the vector should be randomly generated each time

Affirmative

So, the IV should only be randomized between files and not between runs?

The whole point in using IV is that there are some weaknesses in security if you encrypt multiple inputs using the same key. Using unique or random IV actually prevents this sort of weaknesses.

Upvotes: 1

Related Questions