Decrypting Blowfish CBC in Javascript that has been encrypted with PHP mcrypt

1.6k views Asked by At

I'm having a hard time trying to decrypt a String that has been encrypted with Blowfish CBC in PHP;

I'm working on the client side in Javascript with Node.js on a unit test written with Mocha. I'm using the inbuilt crypto functions of Node.

Here's is the code that is working to decrypt the string in PHP.

<?php
 $cipher = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, '');
 $iv = "my_iv";
 $key = substr("my_key", 0, 56);

 // I read that php automaticly pads my key with \0 to make it 56char long.

 if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
   $text = mdecrypt_generic($cipher, urldecode("X%10%8F%AD%1C%1D%E1f%29%CD%D2%E1%81%B0%BE%D2M%8E3%D6%5DO%29%E3%E6%EF%24%A0%E0g%22%DA%D7YK%5B%AA%E6P%91%BA%B8U%C1%87k%7F%07%FD%9D%BF%1F%BD%95r%04%F0%18%A9%27%E17%2C%A8"));
   mcrypt_generic_deinit($cipher);
   echo rtrim($text, "\0");
 } else {
    echo "ERRROR";
 }
?>

This code give me the correct output, which is a serialised Array as a String.

I tried then two libraries to decrypt using the same flow in JS,

With crypto (inbuilt with node):

var crypto = require('crypto');
var iv = new Buffer('my_iv');
var key = new Buffer('my_key');
var text = new Buffer(unescape("X%10%8F%AD%1C%1D%E1f%29%CD%D2%E1%81%B0%BE%D2M%8E3%D6%5DO%29%E3%E6%EF%24%A0%E0g%22%DA%D7YK%5B%AA%E6P%91%BA%B8U%C1%87k%7F%07%FD%9D%BF%1F%BD%95r%04%F0%18%A9%27%E17%2C%A8"));
var decipher = crypto.createDecipheriv('bf-cbc', key, iv);
var decrypted = decipher.update(text, '', '');
    decrypted += decipher.final('');
    console.log(decrypted);

Gives me this error :

error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
TypeError: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
at Decipheriv.Cipher.final (crypto.js:320:27)

And with the mcrypt module for node : https://github.com/tugrul/node-mcrypt

    var MCrypt = require('mcrypt').MCrypt;
    var bfCcb = new MCrypt('blowfish', 'cbc');
    var iv = Buffer.from('my_iv');
    var key = Buffer.from('my_key_padded_with_0\0\0');
    var text = Buffer.from(unescape("X%10%8F%AD%1C%1D%E1f%29%CD%D2%E1%81%B0%BE%D2M%8E3%D6%5DO%29%E3%E6%EF%24%A0%E0g%22%DA%D7YK%5B%AA%E6P%91%BA%B8U%C1%87k%7F%07%FD%9D%BF%1F%BD%95r%04%F0%18%A9%27%E17%2C%A8"));

    bfCcb.open(key, iv);

    var plaintext = bfCcb.decrypt(text);
    console.log(plaintext.toString());

It gives me the wrong output,

I don't know if it has something to do with possible encoding, or if i'm missing something with configuring my javascripts objects...

If anyone has already encountered this problem, please let me know.

1

There are 1 answers

1
zaph On

OK, ignoring security.

Note: Blowfish has a 64-bit block size and a key length of anywhere from 32 bits to 448 bits.

The error message states what the error is: "wrong final block length", that is very specific. Block based encryption requires the input to be a multiple of the block size. "my_url_encodeed_string" is 22 bytes ling which is not a multiple of the Blowfish block size of 8-bytes.

"my_url_encodeed_string" is not encrypted (encrypted appears to be random bits and bytes) so it can not be decrypted. It is also not URL encoded so there is no need to unescape.

That mcrypt does not produce an error does not mean that it successfully decrypted it's data. Blowfish encryption by itself can not tell if decryption is successful or not. Further (you are not going to like this):

It is best not to use mcrypt, it is abandonware, has not been updated in years and does not support standard PKCS#7 padding, only non-standard null padding that can't even be used with binary data. Instead consider using defuse, it is being maintained and is correct.

Further: do not rely on argument padding, since there is no standard each implementation can do whatever it likes. Simply provide the correct lengths for the IV and key.