Search code examples
javanode.jsencryptionblowfish

Cannot convert decryption code usingg Blowfish ECB from Java to Node.js


I cannot seem to figure out what's causing the difference between languages. In Java I have:

byte[] buf = Base64.getDecoder().decode("AutMdzthDvPlE+UnhcHa2h4UZGPdme7t");
System.out.println(buf.length);
String key = "" + 2270457870L;
byte[] keyBytes = key.getBytes("UTF8");
System.out.println(keyBytes.length);

Cipher cipher = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, "Blowfish"));

byte[] newBytes = cipher.doFinal(buf);
System.out.println(newBytes.length);
System.out.println(Arrays.toString(newBytes));

(runnable online at http://ideone.com/0dXuJL)

Then in Node I turned this into:

const buf = Buffer.from("AutMdzthDvPlE+UnhcHa2h4UZGPdme7t");
console.log(buf.length);
const keyBytes = Buffer.from('2270457870', 'utf8');
console.log(keyBytes.length);
const decipher = require('crypto').createDecipher('bf-ecb', keyBytes);

const buffers = [];
buffers.push(decipher.update(buf));
buffers.push(decipher.final());

const newBytes = Buffer.concat(buffers);
console.log(newBytes.length);
console.log(newBytes);

(runnable online at https://tonicdev.com/paulbgd/57b66c8ea0630d1400081ad0)

Which outputs the error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt


Solution

  • There are a couple of issues here:

    1. The string encoding is missing for buf. By default, utf8 is used, but the string is actually base64-encoded. To remedy that use this instead:

      const buf = Buffer.from("AutMdzthDvPlE+UnhcHa2h4UZGPdme7t", "base64");
      
    2. The second argument passed to createDecipher() is a password, not a key. The difference is that createDecipher() hashes the password argument (with MD5) to generate the key. Since you have the key already, what you want instead is createDecipheriv(), which expects a key and IV. The IV argument can just be a zero-length Buffer since ECB mode does not utilize an IV. So use this instead:

      const decipher = require('crypto').createDecipheriv('bf-ecb', keyBytes, Buffer.alloc(0));
      

    Lastly, if you want to match the bytes output from Java, you can replace console.log(newBytes) with something like this:

    for (var i = 0; i < newBytes.length; ++i)
      process.stdout.write(newBytes.readInt8(i) + ' ');
    console.log();