AES-256-CBC in Java
Asked Answered
B

3

5

I'm trying to write a simple Java program that will encrypt plain text with AES-256-CBC. There is class:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AesCBC {
    private byte[] key;
    private byte[] iv;

    private static final String ALGORITHM="AES";

    public AesCBC(byte[] key, byte[] iv) {
        this.key = key;
        this.iv = iv;
    }

    public byte[] encrypt(byte[] plainText) throws Exception{
        SecretKeySpec secretKey=new SecretKeySpec(key,ALGORITHM);
        IvParameterSpec ivParameterSpec=new IvParameterSpec(iv);
        Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE,secretKey,ivParameterSpec);
        return cipher.doFinal(plainText);
    }

    public byte[] getKey() {
        return key;
    }

    public void setKey(byte[] key) {
        this.key = key;
    }

    public byte[] getIv() {
        return iv;
    }

    public void setIv(byte[] iv) {
        this.iv = iv;
    }
}

And there is possible usage:

byte[] test="a".getBytes();

byte[] key=DatatypeConverter.parseHexBinary("b38b730d4cc721156e3760d1d58546ce697adc939188e4c6a80f0e24e032b9b7");
byte[] iv=DatatypeConverter.parseHexBinary("064df9633d9f5dd0b5614843f6b4b059");
AesCBC aes=new AesCBC(key,iv);
try{
    String result=DatatypeConverter.printBase64Binary(aes.encrypt(test));
    System.out.println(result);
}catch(Exception e){
    e.printStackTrace();
}

My output is VTUOJJp38Tk+P5ikR4YLfw==, but when I execute this command:

/usr/bin/openssl enc -A -aes-256-cbc -base64 -K "b38b730d4cc721156e3760d1d58546ce697adc939188e4c6a80f0e24e032b9b7" -iv "064df9633d9f5dd0b5614843f6b4b059" <<< "a"

I get something diffrent than in Java program( Y65q9DFdR3k1XcWhA2AO2Q== ). Sadly I have no idea why results aren't the same since I use the same algorithm with the same key and iv. Does it mean my Java program doesn't work properly? Any help would be appreciated.

Blanca answered 19/10, 2017 at 16:59 Comment(1)
Have you tried decrypting the Java output using Java and/or OpenSSL? If you encrypt with OpenSSL again, do you get the same output? According to the openssl enc help page near the bottom (wiki.openssl.org/index.php/Enc) , "also all salting options are obsolete." I believe if you are using a key, OpenSSL will always salt your results.Osrick
F
8

Both ways are working correctly, however you are encrypting different things.

The here string syntax (<<<) adds a newline to the string. So the Java output is the result of encrypting "a", and the command line output is the result of encrypting "a\n" (i.e. the character a followed by a newline).

Try this from the command line:

printf "a" | /usr/bin/openssl enc -aes-256-cbc -base64 -K "b38b730d4cc721156e3760d1d58546ce697adc939188e4c6a80f0e24e032b9b7" -iv "064df9633d9f5dd0b5614843f6b4b059"

the result is VTUOJJp38Tk+P5ikR4YLfw==, matching your Java result.

Formation answered 19/10, 2017 at 17:29 Comment(0)
S
0

The Java result is correct, see AES CALCULATOR.

Thus the openssl command line encryption is incorrect, read the man page carefully.

Note that I added the PKCS#7 padding manually to the input data.
Also VTUOJJp38Tk+P5ikR4YLfw== in hex is 55350E249A77F1393E3F98A447860B7F

Selftaught answered 19/10, 2017 at 17:22 Comment(0)
S
0

Very nicely documented and explained. Wonderful Example. You may want to extend your code if the data is ASCII instead of hex.

// when data is ASCII
byte[] key="abcdefghi123456".getBytes();
byte[] iv="1234567890123456".getBytes();
Subscription answered 27/2, 2021 at 10:11 Comment(1)
It is maybe not the best idea to convert from String to a byte array without using a fixed standard charset (e.g. "UTF-8")Bathy

© 2022 - 2024 — McMap. All rights reserved.