POSTS
Decrypting data encrypted by openssl on Java/Android
I’m posting this little snippet up because I spent ages trying to work out how to do this, and thought that other googlers might benefit from this.
I’ve got an Android application that stores some of its information on the SDCard which has some commercial value, and we don’t want our competitors simply walking away with the information. The security doesn’t need to be too tight, so I’m happy to have a password based encryption scheme which has the password in the code of the application. If a competitor really wants to get at it, they can, but it will stop casual theft of the data.
To do this, I have written a simple little script in ruby to generate and then encrypt the data files. I dind’t want to write the encryption code in java too, so I needed something that would work across Java and Ruby. OpenSSL to the rescue! OpenSSL provides a simple little command line tool to encrypt files. So, to encrypt the files, I used this snippet:
system("openssl enc -aes-128-cbc -in encrypted#{i+1}.txt -out encrypted#{i+1}.dat -pass pass:ThisIsMyPassword ");
I could have also used the built in openssl gems of ruby, but I couldn’t work out how to get it to save the salt/IV in the file as well as the encrypted data, so I just left it as a command line thing. Perhaps somebody can provide an improvement.
Android provides a pretty comprehensive encryption library through the BouncyCastle Project. The documentation isn’t very helpful though, and it took me a while to work out the correct combination of parameters to decrypt it on the Java side. Here’s the result:
Security.addProvider(new BouncyCastleProvider());
byte[] encrypted = read(args[0]); // Whole encrypted file.
String password = "ThisIsMyPassword";
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
// Openssl puts SALTED__ then the 8 byte salt at the start of the file. We simply copy it out.
byte[] salt = new byte[8];
System.arraycopy(encrypted, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND128BITAES-CBC-OPENSSL", "BC");
c.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(password.toCharArray(), salt, 100)));
// Decrypt the rest of the byte array (after stripping off the salt)
byte[] data = c.doFinal(encrypted, 16, encrypted.length-16);
The Key line is the SecretKeyFactory.getInstance()
call, which sets up the cipher to accept the openSSL data. Once we’ve got that, its trivial. Nothing to it really, once you know the magic string!