4

I want to implement 256 key AES with CBC encryption with Java. Recipient sent me 256 bit passphrase as a String 'absnfjtyrufjdngjvhfgksdfrtifghkv' and it perfectly works using this openssl command:

 echo test | openssl enc  -aes-256-cbc -a -k 'absnfjtyrufjdngjvhfgksdfrtifghkv'

The output in base64 format is : U2FsdGVkX1/yA4J8T+i1M3IZS+TO/V29rBJNl2P88oI=

When i decript it, it returns original input string :

 echo U2FsdGVkX1/yA4J8T+i1M3IZS+TO/V29rBJNl2P88oI= | openssl enc -d -aes-256-cbc -a -k 'absnfjtyrufjdngjvhfgksdfrtifghkv'     

My problem is that i cannot make make my encryption work in java and decrypt it with above command. I know that my key should be generated using my passphrase. Below is example of my code where IV is generated randomly and key is generating using passphrase and random salt.

byte[] input = "test".getBytes();
String passphrase = "absnfjtyrufjdngjvhfgksdfrtifghkv";
int saltLength = 8; 

SecureRandom random = new SecureRandom();

//randomly generate salt
byte[] salt = new byte[saltLength];
random.nextBytes(salt);

// generating key from passphrase and salt
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), salt, 1024, 256);
SecretKey key = factory.generateSecret(spec);
SecretKey kspec = new SecretKeySpec(key.getEncoded(), "AES");

// randomly generate IV
byte iv[] = new byte[16];
random.nextBytes(iv);
IvParameterSpec ips = new IvParameterSpec(iv);

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, kspec, ips);
byte[] encryptedData = c.doFinal(input);
System.out.println(new String(Base64.encodeBase64(encryptedData)));

My java base64 output is XimWIM+8UewzobFOMfevaw== and when I try do run this:

echo XimWIM+8UewzobFOMfevaw= | openssl enc -d -aes-256-cbc -a -k   'absnfjtyrufjdngjvhfgksdfrtifghkv'

I get 'bad magic number' error. What step of java encryption I'm doing wrong?

Marina Sovic
  • 167
  • 2
  • 9

1 Answers1

6

According to this answer, OpenSSL uses a different key derivation algorithm than what you are using in your Java code. Therefore, the key used to encrypt will be different in your OpenSSL command and in your Java program, so the output will be different and incompatible.

You should also check the documentation of the key derivation function in OpenSSL. Apparently it uses MD5 in the algorithm, while your Java code is using SHA1. They won't output the same key.

You have to specify exactly the same key derivation function, or specify the key directly, instead of deriving it from a passphrase.

Finally, avoid creating yourself a key derivation function (that you could easily implement using bash and using Java) and stick to standards, if security is a concern (if it is not, why bother using crypto?); it is most probable that the algorithm will be broken.

Community
  • 1
  • 1
Bruno Reis
  • 34,789
  • 11
  • 109
  • 148
  • Tnx for your answer. I'm wondering is there any function that returns all the possible algorithms that are passed to this function: SecretKeyFactory.getInstance("algorithm") because I'm having difficulties finding proper string to put as openssl algorithm(it's not just "MD5") After reading about how openssl generates key, it looks that IV has to be generated from passphrase too, is that true? Or I can get correct result using randomly generated IV as in my example? – Marina Sovic Feb 04 '13 at 23:32
  • Is there any other library in Java that can do the same work as openssl and that simply takes passphrase and encrypts data without manually generating all of these steps? I think other programming languages(like Ruby..) have that so it must be something similar in Java. – Marina Sovic Feb 04 '13 at 23:33
  • What exactly you are trying to achieve? It is a bit difficult to give good advice without more information. What/who will encrypt data? How will it be transmitted? What/who will decrypt the ciphertext? Against what are you trying to protect (simple eavesdropping/an attacker tampering with transmission of ciphertext/etc)? In any case, did you consider the possibility of using OpenSSL as an external process in your Java program? This way, you don't need to bother with specific details on OpenSSL vs Java KDFs. – Bruno Reis Feb 05 '13 at 05:15
  • I'm trying to regulary send some messages from my application using web service from one company. The only info I have is that I have to encrypt my message, encryption used from their side is AES with CBC and they gave me their passphrase as a string. Decryption is done in Ruby using that passphrase and randomly generated salt. Basicaly, I just need to send correct cipertext that can be decripted from their side using that passphrase. Actually I considered using OpenSSL as an external process in Java but don't have experience with that, so any info or link regarding that would be very helpful. – Marina Sovic Feb 05 '13 at 06:37
  • 1
    Some information is missing. AES in CBC mode needs exactly 2 parameters, that must match exactly when encrypting and decrypting: IV and key. If the company talks about a "passphrase", then they *must* specify the KDF they use -- ie, how exactly do they transform a passphrase into the values needed by AES, which are IV and key? Otherwise, you must guess the correct algorithm until you get it working, which is pointless. To work with external process (and use OpenSSL -- if you're sure that the OpenSSL's KDF matches exactly the company's KDF), open the Javadocs for the class `ProcessBuilder`. – Bruno Reis Feb 05 '13 at 07:01