Rui Rocha
Rui Rocha

Reputation: 55

Converting PHP encryption to NodeJS

I'm currently implementing encryption on my API. I have to implement this the same way it is encrypted and decrypted in a specific script written in PHP.

This works all fine when I output the result in, let's say, base64. The PHP decrypt method runs against it and works just fine. The problem is that I need to output not in base64 but in binary due to certain requirements, but when I encrypt from the Nodejs side into binary the result is different than when I encrypt in the PHP into binary when it should be the same.

PHP Encryption:

function vd_encrypt($plaintext, $password) {
$method = "AES-256-CBC";
$key = hash('sha256', $password, true);
$iv = openssl_random_pseudo_bytes(16);

$ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
$hash = hash_hmac('sha256', $ciphertext, $key, true);

return $iv . $hash . $ciphertext;

}

Javascript Encryption:

import crypto from 'crypto';

export function encrypt (plain_text: string): string {
    const encryptionMethod = 'AES-256-CBC';
    const iv = crypto.randomBytes(IV_LENGTH);
    const key = crypto.createHash("sha256").update(secret).digest();

    var encryptor = crypto.createCipheriv(encryptionMethod, key, iv);

    const result = iv + encryptor.update(plain_text, 'utf8', 'binary') + encryptor.final('binary');

    return result;
}

Upvotes: 1

Views: 456

Answers (1)

Terry Lennox
Terry Lennox

Reputation: 30675

I've updated your code slightly to accept an iv parameter. You can generate this in the same way as before (e.g. openssl_random_pseudo_bytes).

For the purposes of demonstration I'll use a fixed IV so we can show the same result.

PHP

function vd_encrypt($plaintext, $password, $iv) {
    $method = "AES-256-CBC";
    $key = hash('sha256', $password, true);
    $ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
    $hash = hash_hmac('sha256', $ciphertext, $key, true);
    return $iv . $hash . $ciphertext;
}

// Replace with below code in production
// $iv = openssl_random_pseudo_bytes(16);
$iv = base64_decode("eQMrc61Gt8qRejRjhJOkVw==");
$result = vd_encrypt("He was a man take him for all in all, I shall not look upon his like again", "password", $iv);

echo "Result (base64): " . base64_encode($result) . "\n";

Node.js

import crypto from 'crypto';

export function encrypt (plaintext: string, password: string, iv: string): string {
    const encryptionMethod = 'AES-256-CBC';
    const key = crypto.createHash("sha256").update(password).digest();
    const encryptor = crypto.createCipheriv(encryptionMethod, key, iv);

    const encryptedData = Buffer.concat([encryptor.update(plaintext, 'utf8'), encryptor.final()]);
    const hash = crypto.createHmac("sha256", key).update(encryptedData).digest();

    return Buffer.concat([iv, hash, encryptedData]);
}

// Replace with below code in production 
//const iv = crypto.randomBytes(16);
const iv = Buffer.from("eQMrc61Gt8qRejRjhJOkVw==", "base64");
const result = encrypt("He was a man take him for all in all, I shall not look upon his like again", "password", iv);
console.log("Result (base64):", result.toString("base64"));

In this case the results will be like so:

PHP:

Result (base64): eQMrc61Gt8qRejRjhJOkVxsqZTqUjSUnaL46yZDLGGK5+o7WKLyIiG4UKj0ST93Wi7UlaAyTFIjpIs0C893SFsnHeuVshG+6EJF99GrLSUCMFJG3J1pJnmxF4Pu8ZCbN7Ounp0BjhJKIpu9yQn6uEYylJLXWpzNw+aCwsnIV1h0=

Node.js:

Result (base64): eQMrc61Gt8qRejRjhJOkVxsqZTqUjSUnaL46yZDLGGK5+o7WKLyIiG4UKj0ST93Wi7UlaAyTFIjpIs0C893SFsnHeuVshG+6EJF99GrLSUCMFJG3J1pJnmxF4Pu8ZCbN7Ounp0BjhJKIpu9yQn6uEYylJLXWpzNw+aCwsnIV1h0=

Upvotes: 4

Related Questions