Search code examples
phpnode.jscryptojs

Porting Decryption Function From PHP to NodeJs


I have some problem when porting a function from PHP to NodeJS. I have tried implement this PHP code with Node JS, but its not working.

This is the code in PHP

   <?php 
        require_once 'vendor/autoload.php';
    
        // function decrypt
        function stringDecrypt($key, $string){
            
      
            $encrypt_method = 'AES-256-CBC';
    
            // hash
            $key_hash = hex2bin(hash('sha256', $key));
      
            // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
            $iv = substr(hex2bin(hash('sha256', $key)), 0, 16);
    
            $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key_hash, OPENSSL_RAW_DATA, $iv);
      
            return $output;
        }
        
    ?>

This is my code in NodeJs

    function decryptResponse(timestamp, string, key) {
        var key_hash = hex2bin(crypto.createHash("sha256").update(key).digest('hex'));
        var iv = key_hash.substr(0,16);
        var decoder = crypto.createDecipheriv('aes-256-cbc', key_hash, iv);
        var output = decoder.update(Buffer.from(string).toString('base64'),'base64','utf8') += decoder.final('utf8');
        console.log("Decrypt Result : ", output); //Not Showing on Log
    }

function hex2bin(hex) {
    var bytes = [];
    var str;
    for(var i=0; i< hex.length-1; i+=2){
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    str = String.fromCharCode.apply(String, bytes);

    return str;
  }

This function is called when I get the response from API and need to send it to the user.

var decompressedResponse = decryptResponse(timestamp, response.data.response, key);  
res.send(decompressedResponse);

I need this function to decrypt a response from API so I really need this one working. Thank you for your help.


Solution

  • The hex2bin() function is not needed and can be removed.

    Also, it's easier to determine key and IV as buffer.

    The ciphertext is currently Base64 encoded a second time in update(). To avoid this, it should be passed directly to update().

    And the concatenation of the results of update() and final() call must be done with + instead of += (which is probably just a typo or copy/paste error).

    Overall:

    function decryptResponse(timestamp, string, key) {
        var key_hash = crypto.createHash("sha256").update(key).digest(); // remove hex2bin; use Buffer
        var iv = key_hash.slice(0,16); // use Buffer
        var decoder = crypto.createDecipheriv('aes-256-cbc', key_hash, iv);
        var output = decoder.update(string,'base64','utf8') + decoder.final('utf8'); // don't Base64 encode twice, pass ciphertext directly; apply + instead of +=
        console.log("Decrypt Result : ", output); 
    }
    

    Note that it's insecure to use the key or a part of the key as IV. Usually the (non-secret) IV is randomly generated for each encryption and passed along with the ciphertext (typically concatenated).

    Also, using a hash as key derivation function is insecure. Instead, a reliable key derivation function such as PBKDF2 should be applied.