Vadorequest
Vadorequest

Reputation: 17979

Decrypt string in node.js from PHP RIJNDAEL_128 CBC

I'm trying to decrypt a string, previously encrypted by a third party software using PHP RIJNDAEL_128 in CBC mode, using node.js.

Here is an interactive link of the following PHP code, in a sandbox, so you can compile and see for yourself. http://sandbox.onlinephpfunctions.com/code/504a7d052c5b123fac8103a073c05c2ff5f80571

PHP source code:

<?php
class CryptClass{

    private $key;

    public function __construct($key){
        $this->key = $key;
    }

    public function cryptage($message){

        $key = base64_decode($this->key);
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);

        $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $message, MCRYPT_MODE_CBC, $iv);
        $ciphertext = $iv . $ciphertext;

        return base64_encode($ciphertext);
    }

    public function  decryptage($message){
        $key = base64_decode($this->key);
        $iv_size2 = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $ciphertext_dec = base64_decode($message);
        $iv_dec = substr($ciphertext_dec, 0, $iv_size2);
        $ciphertext_dec = substr($ciphertext_dec, $iv_size2);

        $message_decrypt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key,$ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);

        return str_replace("\0", "", $message_decrypt);
    }
}

// Secret key and data
define('KEY', 'azertyuiolskzif');
define('DATA', '[email protected]|1477576941|origin.com');

// Crypt
$Crypt = new CryptClass(base64_encode(KEY));
$encodedData = base64_encode($Crypt->cryptage(DATA));

// Decrypt
$decodedData = $Crypt->decryptage(base64_decode($encodedData));

echo 'base64_encode: '.base64_encode(KEY);
echo "\nDATA: ".DATA;
echo "\nDATA length: ".strlen(DATA);
echo "\n\nencodedData: ".$encodedData;
echo "\n\ndata: ".$decodedData;
echo "\n\ndata length: ".strlen($decodedData);
echo "\n\ncrypt/decrypt match?: ".(DATA == $decodedData ? 'yes':'no');

Here is my implementation in node.js: NOT WORKING, see below for working solution

var crypto = require('crypto');

var textToEncrypt = '[email protected]|1477576941|origin.com';
var encryptionMethod = 'AES-128-CBC';
var secret = "azertyuiolskzif";
var iv = 'aaaabbbbccccdddd';


var encrypt = function (plain_text, encryptionMethod, secret, iv) {
    var encryptor = crypto.createCipheriv(encryptionMethod, secret, iv);
    return encryptor.update(plain_text, 'utf8', 'base64') + encryptor.final('base64');
};

var decrypt = function (encryptedMessage, encryptionMethod, secret, iv) {
    var decryptor = crypto.createDecipheriv(encryptionMethod, secret, iv);
    return decryptor.update(encryptedMessage, 'base64', 'utf8') + decryptor.final('utf8');
};

var encryptedMessage = encrypt(textToEncrypt, encryptionMethod, secret, iv);
var decryptedMessage = decrypt(encryptedMessage, encryptionMethod, secret, iv);

console.log(decrypt());
console.log(encryptedMessage);
console.log(decryptedMessage);

I have tried many things and I'm getting lost here between Invalid key length and other error messages. One thing I don't quite understand is that the KEY apparently used to encrypt the data is azertyuiolskzif which is 15 chars long while most script use a required 32 chars string... Maybe PHP doesn't need a 32 char string but Node does?

Or maybe it's related to the difference between 128 and 256. Or is it due to the difference of padding between PHp and Node implementation?

I tried to follow the advices given at Encrypt string in PHP and decrypt in Node.js but even tho, I didn't succeed at encrypting my data in node yet.


Edit:

After some more digging around (and thanks for the explanations in the answers), I finally made crypt/decrypt work in Node.js. But I haven't succeeded to decrypt something crypted by PHP yet.

var crypto = require('crypto');

var AES = {};

AES.encrypt = function(dataToEncrypt, encryptionMethod, secret, iv, padding) {
    var encipher = crypto.createCipheriv(encryptionMethod, secret, iv);
    encipher.setAutoPadding(padding || 0); // "true" or "128" would work with aes-128-cbc
    var encryptedData = encipher.update(dataToEncrypt, 'utf8', 'base64');

    encryptedData += encipher.final('base64');
    return encryptedData;
};

AES.decrypt = function(encryptedData, encryptionMethod, secret, iv, padding) {
    var decipher = crypto.createDecipheriv(encryptionMethod, secret, iv);
    decipher.setAutoPadding(padding || 0); // "true" or "128" would work with aes-128-cbc
    var decoded = decipher.update(encryptedData, 'base64', 'utf8');

    decoded += decipher.final('utf8');
    return decoded;
};

// ----

var textToEncrypt = '[email protected]|1477576941|origin.com';
var secret = "aaaabbbbccccdddd"; // Must be 16 chars
var iv = crypto.randomBytes(16); // Must be 16 chars
var encryptionMethod = 'AES-128-CBC';

// Testing crypt/decrypt using Node.js algorithm.
var encryptedMessage = AES.encrypt(textToEncrypt, encryptionMethod, secret, iv, 128);
var decryptedMessage = AES.decrypt(encryptedMessage, encryptionMethod, secret, iv, 128);

console.log('encryptedMessage', encryptedMessage); // Displays "GWpMWORNKkqlrHJDPuNgSmTKr1vJhaAApHP+ssK3SH5EALTkdWneUZRp9PXNpVQ2"
console.log('decryptedMessage', decryptedMessage); // Displays "[email protected]|1477576941|origin.com"


// Testing decrypt from a string generated by PHP algorithm.
// XXX Doesn't work "Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length"
// XXX Probably due to wrong padding between PHP/Node implementation?
var stringToDecode = 'RlM3Wkl3N3JRM0dnaEh4SkdoZWFDRy9mZGRoTnkxNlZUL2IvcHl4TkdzUUlRSXQwSWNwWUZ5OFpaRENZQys3S2t0bFZIUWoweUVsZGxUU21sYU9tS0E9PQ==';
console.log('stringToDecode', stringToDecode);
console.log(AES.decrypt(
    stringToDecode,
    encryptionMethod, secret, iv, 128
));

Upvotes: 1

Views: 737

Answers (1)

zaph
zaph

Reputation: 112857

AES keys must be exactly one of 128, 192 or 256-bits. Some implementations will pad keys in some way but this should not be relied on. Make the key a correct size.

Upvotes: 1

Related Questions