Search code examples
javabashscalaencryptionblowfish

Blowfish encrypt in Java/Scala and decrypt in bash


I'm trying to build a tool to decrypt content in bash encrypted in a scala application:

But first, I've to succeed encoding the same message in both languages and make them equal:

Given the passphrase "0123456789abcdef"
(hex: "30313233343536373839616263646566" and byte[]:[48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102])

scala> import javax.crypto.Cipher
scala> import javax.crypto.spec.SecretKeySpec
scala> val cipher = Cipher.getInstance("Blowfish")
scala> cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("0123456789abcdef".getBytes("utf-8"), "Blowfish"))
scala> javax.xml.bind.DatatypeConverter.printBase64Binary(cipher.doFinal("message".getBytes("utf-8")))
res7: String = K679Jz06jmc=

But I can't reproduce the same with openssl in bash.

$ echo "message" | openssl enc -a -e -blowfish -nosalt -nopad -k "0123456789abcdef"
LJ3iFJ2/mYk=
$ echo "message" | openssl enc -a -e -blowfish -nosalt -nopad -k "30313233343536373839616263646566"
JkkJgYv3fQg=

Any hint? Thanks!


Solution

  • It would be more accurate to tag OpenSSL, which runs the same from any shell or no shell at all.

    OpenSSL enc by default does password-based encryption, with a key (plus IV) derivation similar to (but not exactly) PBKDF1. To encrypt with a key, not password, you need to use UPPERCASE -K with hex, and you need to specify at least part of -iv; on the other hand -nosalt is useless.

    Also the echo command adds a newline to the data it echoes, and encryption of 'm e s s a g e NL' is entirely different from encryption of 'm e s s a g e'. Some OSes and shells, depending on whether the echo you are using is builtin or external, have ways to omit the newline, but they aren't all the same. OTOH all POSIX systems support printf, so:

    $ printf %s message | openssl enc -blowfish -K 30313233343536373839616263646566 -iv 00 -a
    K679Jz06jmc=
    

    EDIT: Artjom is correct; Java/Scala (probably) defaults to ECB, which is a Bad Idea; you should specify /CBC or /CTR and padding. Unlike aventurin I see no reason you should force yourself into the straightjacket of /NoPadding; Java /PKCS5Padding is compatible with OpenSSL's default. For CBC or CTR you need to explicitly set the IV (with the third argument to Cipher.init) to get a deterministic result -- and you must either set the IV, or retrieve the default random one, to produce a decryptable result, which people usually want. OpenSSL enc -blowfish defaults to CBC, but it's clearer to explicitly state -bf-cbc or -bf-ctr. Or -bf-ecb if you really want ECB, which as above is Unrecommended.