Reputation: 55
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
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