使用AES中的初始向量进行aes-256-cbc加密解密

时间:2018-09-27 06:29:59

标签: php node.js encryption cryptojs

我正在尝试将一些现有的php代码转换为nodejs,但是node js代码返回:

  

TypeError:Salt必须是缓冲区

我正在使用节点版本=> v8.11.2

PHP代码:

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

我尝试了一些nodejs

NodeJs代码:

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}....`));

1 个答案:

答案 0 :(得分:1)

PBKDF2是一个很棒的主意,它是PHP代码首先应该完成的工作。不幸的是,passwordDeriveBytes()内部发生的事情与PBKDF2无关。如果要匹配,则需要像passwordDeriveBytes()内部那样重现循环。

Oh和“ 盐必须是缓冲区”可以通过将IV转换为带有Buffer.from(iv)的Buffer来解决(这也是一个好的IV不应不< / em>为字符串,但为随机字节)。

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);

输出:

df07df624db35d0bcf5fe7ff2dfdfffcef93f098939d750ca55595ae1b33925d
original  : 437217
encrypted : C9xJGa03dRQx9ePm0nLnHg==
decrypted : 437217