Reputation: 5283
I am trying to convert some existing php code into nodejs but node js code returns:
TypeError: Salt must be a buffer
I am using node version => v8.11.2
PHP Code :
class SecurityModel {
protected $key;
protected $method;
protected $data;
protected $iv;
function __construct($data, $key = 'testing', $method = 'AES-256-CBC',$InitialVector = "aw90rela942f65u2") {
$this->data = $data;
$this->key = $this->passwordDeriveBytes($key, null);
$this->method = $method;
$this->iv = $InitialVector;
}
function passwordDeriveBytes($password, $salt, $iterations = 100, $len = 32) {
$key = $password . $salt;
for($i = 0; $i < $iterations; $i++) {
$key = sha1($key, true);
}
if (strlen($key) < $len) {
$hx = $this->passwordDeriveBytes($password, $salt, $iterations - 1, 20);
$counter = 0;
while (strlen($key) < $len) {
$counter += 1;
$key .= sha1($counter . $hx, true);
}
}
return substr($key, 0, $len);
}
function encrypt(): string {
return openssl_encrypt($this->data, "aes-256-cbc", $this->key, 0, $this->iv);
}
function decrypt(): string {
return openssl_decrypt($this->data, "aes-256-cbc", $this->key, 0, $this->iv);
}
}
$objSecurityModel = new SecurityModel('437217');
$Encrypted = $objSecurityModel->encrypt();
echo "Encrypted :".$Encrypted ."<br>"; //returns-->C9xJGa03dRQx9ePm0nLnHg==
$objSecurityModel = new SecurityModel($Encrypted);
echo "Decrypted::".$objSecurityModel->decrypt(); //returns-->437217
I tried some what in nodejs
NodeJs Code :
const express = require('express');
const app = express();
var crypto = require('crypto');
key = 'testing'
plaintext = '437217'
iv = 'aw90rela942f65u2'
crypto.pbkdf2('testing', null, 100, 32, 'AES-256-CBC', (err, derivedKey) => {
if (err) throw err;
console.log(derivedKey.toString('hex')); // '3745e48...08d59ae'
key = derivedKey.toString('hex');
});
cipher = crypto.createCipheriv('aes-256-cbc', key,iv)
decipher = crypto.createDecipheriv('aes-256-cbc', key,iv);
var encryptedPassword = cipher.update(plaintext, 'utf8', 'base64');
encryptedPassword += cipher.final('base64')
var decryptedPassword = decipher.update(encryptedPassword, 'base64', 'utf8');
decryptedPassword += decipher.final('utf8');
console.log('original :', plaintext);
console.log('encrypted :', encryptedPassword);
console.log('decrypted :', decryptedPassword);
//PORT
const port = process.env.PORT || 3000;
app.listen(port,() => console.log(`Listening on port ${port}....`));
Upvotes: 1
Views: 8825
Reputation: 85341
PBKDF2 is a great idea and is what the PHP code should have done in the first place. Unfortunately what happens inside passwordDeriveBytes()
is nowhere near PBKDF2. You need to reproduce the looping like what happens inside passwordDeriveBytes()
if you want to match it.
Oh and "Salt must be a buffer" is solved by converting the IV to a Buffer with Buffer.from(iv)
(that is also a sign that a good IV should not be a string but random bytes).
const crypto = require('crypto');
function sha1(input) {
return crypto.createHash('sha1').update(input).digest();
}
function passwordDeriveBytes(password, salt, iterations, len) {
var key = Buffer.from(password + salt);
for(var i = 0; i < iterations; i++) {
key = sha1(key);
}
if (key.length < len) {
var hx = passwordDeriveBytes(password, salt, iterations - 1, 20);
for (var counter = 1; key.length < len; ++counter) {
key = Buffer.concat([key, sha1(Buffer.concat([Buffer.from(counter.toString()), hx]))]);
}
}
return Buffer.alloc(len, key);
}
var password = 'testing';
var plaintext = '437217';
var iv = 'aw90rela942f65u2';
//var key = crypto.pbkdf2Sync(password, '', 100, 32, 'sha1'); // How it should be
var key = passwordDeriveBytes(password, '', 100, 32); // How it is
console.log(key.toString('hex'));
var cipher = crypto.createCipheriv('aes-256-cbc', key, Buffer.from(iv));
var decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(iv));
var part1 = cipher.update(plaintext, 'utf8');
var part2 = cipher.final();
var encrypted = Buffer.concat([part1, part2]).toString('base64');
var decrypted = decipher.update(encrypted, 'base64', 'utf8');
decrypted += decipher.final();
console.log('original :', plaintext);
console.log('encrypted :', encrypted);
console.log('decrypted :', decrypted);
Output:
df07df624db35d0bcf5fe7ff2dfdfffcef93f098939d750ca55595ae1b33925d
original : 437217
encrypted : C9xJGa03dRQx9ePm0nLnHg==
decrypted : 437217
Upvotes: 1