3

I have a remote system sending me data which it has encrypted via the openssl command line program, using blowfish encryption.

Specifically, the command being run is:

openssl enc -blowfish -a -salt -in original.txt -out encrypted.txt -pass pass:secret

For the input This is a test. that produces U2FsdGVkX19bSsC3dXTOYssoOK5L3THkhXgiB7X1Trv6SaVO2TGz0g==

I'm trying to decrypt this content on the other side in Java with the following code.

// requires commons-io and commons-codec
public void testDecryption() throws Exception {
    File encryptedFile = new File("encrypted.txt");
    String password = "secret";

    byte[] base64EncryptedBytes = FileUtils.readFileToByteArray(encryptedFile);
    byte[] encryptedBytes = new Base64().decode(base64EncryptedBytes);

    SecretKeySpec blowfishKey = new SecretKeySpec(password.getBytes("ASCII"), "Blowfish");
    Cipher blowfishCipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
    blowfishCipher.init(Cipher.DECRYPT_MODE, blowfishKey);
    byte[] decryptedContent = blowfishCipher.doFinal(encryptedBytes);

    System.out.println(new String(decryptedContent));
}

Rather than the original message that currently produces...

êõïÖ¶M≥ O]¢∞;Z<HVÖ_’˚h‘:O›c=w◊®zÉ9˘

What am I doing wrong?

Some possible theories

  • Blowfish/ECB/NoPadding is not the right cypher instance to use. I've tried every combination of mode and padding listed at http://docs.oracle.com/javase/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA except the OAEPWith[digest]And[mgf]Padding padding unsuccessfully.
    • I've noticed that if I decrypt the file from the command line using openssl enc -d -blowfish -a -in encrypted.txt the password prompt is labeled 'bf-cbc', which suggests Blowfish/CBC rather than Blowfish/ECB, however if I use that I get a java.security.InvalidKeyException: Parameters missing exception, but I'm not sure what paramater I could add.
  • The password given on the command line should be transformed somehow, or getBytes("ASCII") is incorrect.
  • Some additional handling is required in the Java code for the salt.
Matt Sheppard
  • 116,545
  • 46
  • 111
  • 131

2 Answers2

3

After a lot of searching around I ran across not-yet-commons-ssl which seems to provide a method for doing this...

byte[] decrypted = OpenSSL.decrypt("blowfish", password.toCharArray(), base64EncryptedBytes);

When I get some time I'll dig into their code and find out exactly what is being done. In the mean time it looks like OpenSSL.java is the place to start.

Matt Sheppard
  • 116,545
  • 46
  • 111
  • 131
1

openssl doesn't use the password "secret" directly, but uses it to derive a key, so you need to replicate the key derivation in Java. If you use the -p parameter with openssl:

$ openssl enc -blowfish -a -salt -in original.txt  -pass pass:secret -p
salt=FB92391C90CF0EA5
key=C8B918619B0736F95704AD3BD53849EC
iv =6F92FB39C5795434
U2FsdGVkX1/7kjkckM8OpYRWgmNmYzHi8JWYOYpDK5w=

you'll see it print out the (hex encoded) salt and also the initialization vector. The salt would normally be passed to a PBEKeySpec when generating the key, e.g.

KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1, 128);

The initialization vector is supplied when you initialize the Cipher:

blowfishCipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));

which is the missing parameter you refer to.

Unfortunately, I don't know which key derivation function openssl uses in this case or if the same algorithm is supported directly in Java. Hopefully someone else can provide that information. A good equivalent example using AES can be found in the answer to this question.

Looking more closely at the encrypted string in the above output, namely "U2FsdGVkX1/7kjkckM8OpYRWgmNmYzHi8JWYOYpDK5w=", if you base64 decode that and then hexdump it, you'll get:

Encrypted bytes: 
0000: 53 61 6C 74 65 64 5F 5F   FB 92 39 1C 90 CF 0E A5  Salted__..9.....
0010: 84 56 82 63 66 63 31 E2   F0 95 98 39 8A 43 2B 9C  .V.cfc1....9.C+.

So the string "Salted__" plus the salt are prepended. In other words, you'll also need to find out how openssl formats the encoded string so that you can successfully extract the salt and the correct ciphertext.

Community
  • 1
  • 1
Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • Thanks Luke - That was very useful info which eventually lead me to the http://juliusdavies.ca/commons-ssl/pbe.html library which seems to handle what I need to do. – Matt Sheppard Dec 12 '11 at 04:44
  • Cool. Glad it was helpful, and thanks for the reference. May need it myself sometime :). – Shaun the Sheep Dec 12 '11 at 13:55