not-yet-commons-ssl



OpenSSL's "enc" in Java (PBE / Password Based Encryption)

Not-Yet-Commons-SSL has an implementation of PBE ("password based encryption") that is 100% compatible with OpenSSL's command-line "enc" utility. PBE is a form of symmetric encryption where the same key or password is used to encrypt and decrypt the file.

We are also compatible with openssl enc -K [key] -iv [IV], where the key and IV are provided explicitly, instead of being derived from a password. Look for encrypt()/decrypt() methods that take byte[] key, byte[] iv instead of char[] password.

Please visit the Quick-FAQ if you are having problems.

PBE code example (DES-3):*

char[] password = {'c','h','a','n','g','e','i','t'};
byte[] data = "Hello World!".getBytes();

// Encrypt!
byte[] encrypted = OpenSSL.encrypt("des3", password, data);
System.out.println("ENCRYPTED: [" + new String(encrypted) + "]");

// Decrypt results of previous!
data = OpenSSL.decrypt("des3", password, encrypted);
System.out.println("DECRYPTED: [" + new String(data) + "]");


OUTPUT:
=======================
ENCRYPTED: [U2FsdGVkX19qplb9qVDVVEYxH8wjJDGpMS+F4/2pS2c=]
DECRYPTED: [Hello World!]

* - This code example is not quite right.

Some notes:

Here's a list of supported OpenSSL ciphers. The purple ones require the BouncyCastle JCE. The red ones (desx, desx-cbc) probably require RSA's BSAFE JCE, and have not been tested.

aes-128-cbc               aes-128-cfb               
aes-128-cfb8              aes-128-ecb               aes-128-ofb
aes-192-cbc               aes-192-cfb               
aes-192-cfb8              aes-192-ecb               aes-192-ofb
aes-256-cbc               aes-256-cfb               
aes-256-cfb8              aes-256-ecb               aes-256-ofb
aes128                    aes192                    aes256
bf                        bf-cbc                    bf-cfb
bf-ecb                    bf-ofb                    blowfish
camellia-128-cbc          camellia-128-cfb          
camellia-128-cfb8         camellia-128-ecb          camellia-128-ofb
camellia-192-cbc          camellia-192-cfb          
camellia-192-cfb8         camellia-192-ecb          camellia-192-ofb
camellia-256-cbc          camellia-256-cfb          
camellia-256-cfb8         camellia-256-ecb          camellia-256-ofb
camellia128               camellia192               camellia256
cast                      cast-cbc                  cast5-cbc
cast5-cfb                 cast5-ecb                 cast5-ofb
des                       des-cbc                   des-cfb
                          des-cfb8                  des-ecb
des-ede                   des-ede-cbc               des-ede-cfb
des-ede-ofb               des-ede3                  des-ede3-cbc
des-ede3-cfb              des-ede3-ofb              des-ofb
des3                      desx                      desx-cbc
idea                      idea-cbc                  idea-cfb
idea-ecb                  idea-ofb                  rc2
rc2-40-cbc                rc2-64-cbc                rc2-cbc
rc2-cfb                   rc2-ecb                   rc2-ofb
rc4                       rc4-40                    rc5
rc5-cbc                   rc5-cfb                   rc5-ecb
rc5-ofb

Here are some additional ciphers supported by BouncyCastle, but not by OpenSSL:

cast6
gost (aka: gost28147)
rc6
seed
serpent
skipjack
tea
twofish
xtea

Quick FAQ about PBE and Java


Why do I keep getting "java.security.InvalidKeyException: Illegal key size"?
Don't forget to install your JVM's Unlimited Strength Jurisdiction Policy Files if you want AES-192 and AES-256 to work. (Same is true for Camillia-192, Camellia-256, and GOST28147). Visit http://java.sun.com/javase/downloads/ and scroll to the bottom:
Other Downloads
Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6
You can use DES-3 (168 bit keys) without installing the extra policy files.
Why do the encrypted files always start with "Salted__" ("U2FsdGVkX1" in base64)? Isn't giving away information like this insecure?
The encrypted files must always start with "Salted__" to interoperate with OpenSSL. OpenSSL expects this. The 8 bytes that spell "Salted__" are always immediately followed by another random 8 bytes of salt. The encrypted stream starts at the 17th byte. This way, even if you use the same password to encrypt 2 different files, the actual secret keys used to encrypt these 2 files are very different.

It is possible to omit the salt, but this is highly discouraged:
boolean useBase64 = true;
boolean useSalt = false; // Omitting the salt is bad for security!
byte[] result = OpenSSL.encrypt(alg, pwd, data, useBase64, useSalt);

Why is code example above "not quite right"?
It relies on the platform's default character set. Here is the proper version (forcing UTF-8):
PBE example (DES-3):

char[] password = {'c','h','a','n','g','e','i','t'};
byte[] data = "Hello World!".getBytes("UTF-8");

// Encrypt!
byte[] encrypted = OpenSSL.encrypt("des3", password, data);
System.out.println("ENCRYPTED: [" + new String(encrypted, "UTF-8") + "]");

// Decrypt results of previous!
data = OpenSSL.decrypt("des3", password, encrypted);
System.out.println("DECRYPTED: [" + new String(data, "UTF-8") + "]");

OUTPUT:
======================
ENCRYPTED: [U2FsdGVkX19qplb9qVDVVEYxH8wjJDGpMS+F4/2pS2c=]
DECRYPTED: [Hello World!]