Search code examples
javascriptphpencryptiontranslatemcrypt

How to translate this encryption function from PHP to Javascript


I am moving a web app from PHP to a JS-based framework. The app uses mcrypt_encrypt and base64 for encryption. I tried using the mcrypt module in Javascript but I'm not getting the same result.

The original PHP function looks like this

function safe_b64encode($string) {
    $data = base64_encode($string);
    $data = str_replace(array('+', '/', '='), array('-', '_', ''), $data);
    return $data;
}

function encrypt($value) {
    $text = $value;
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, ENCRYPTION_KEY, $text, MCRYPT_MODE_ECB, $iv);
    return trim(safe_b64encode($crypttext));
}

My JS version looks like this

const MCrypt = require('mcrypt').MCrypt

const rijndael128Ecb = new MCrypt('rijndael-128', 'ecb')
const iv = rijndael128Ecb.generateIv()

rijndael128Ecb.validateKeySize(false)
rijndael128Ecb.open(ENCRYPTION_KEY, iv)

let cipherText = rijndael128Ecb.encrypt('sometext')
cipherText = Buffer.concat([iv, cipherText]).toString('base64')
cipherText = cipherText.replace('+','-').replace('/','_').replace('=','')

Solution

  • I think you're nearly there, you just need to use the same algorithm, you were using 128-bit Rijndael, I switched to 256-bit in Node.js, it's working now.

    // Surely this key is uncrackable...
    const ENCRYPTION_KEY = 'abcdefghijklmnop';
    const MCrypt = require('mcrypt').MCrypt;
    
    function encryptRijndael256(plainText, encryptionKey) {
    
        const rijndael256Ecb = new MCrypt('rijndael-256', 'ecb');
        const iv = rijndael256Ecb.generateIv();
    
        rijndael256Ecb.validateKeySize(false);
        rijndael256Ecb.open(encryptionKey, iv);
    
        let cipherText = rijndael256Ecb.encrypt(plainText);
        cipherText = cipherText.toString('base64');
        cipherText = cipherText.replace('+','-').replace('/','_').replace('=','')
    
        return cipherText;
    }
    
    const plainText = 'sometext';
    const cipherText = encryptRijndael256(plainText, ENCRYPTION_KEY); 
    console.log("Cipher text: ", cipherText);
    

    I'm getting the following ciphertext (with the trivial and insecure!) key I'm using:

    k3ZQ8AbnxhuO8TW1VciCsNtvSrpbOxlieaWX9qwQcr8
    

    for the result in both PHP and JavaScript.