簡體   English   中英

解密使用 NodeJS 加密的 AES-256-CBC 字符串

[英]Decrypt AES-256-CBC string that is encrypted with NodeJS

我使用以下函數通過 NodeJS 加密/解密,它們工作正常。 但是我無法使用 PHP 解密數據以用於同一項目的某些部分。

節點JS:

function encrypt(text){
  var cipher = crypto.createCipher('aes-256-cbc','strong-key')
  var crypted = cipher.update(text,'utf8','hex')
  crypted += cipher.final('hex');
  return crypted;
}

function decrypt(text){
  var decipher = crypto.createDecipher('aes-256-cbc','strong-key')
  var dec = decipher.update(text,'hex','utf8')
  dec += decipher.final('utf8');
  return dec;
}

我用 PHP 嘗試的是:

openssl_decrypt('fdf32748aa4ce37fc600bbe7be14bfc7', 'AES-256-CBC', "strong-key");

但它一直返回假/空。 我很感激治愈我知道我做錯了什么。

編輯:例如,使用與上述相同的密鑰,使用 PHP 解密28e1dfdedac467a015a9c8720d0a6451應該返回“Hello World”。

確保您的傳入數據格式正確(即沒有任何額外的編碼層)。 它看起來像十六進制,但這不是 openssl_decrypt 所期望的。

這是一個來回 PHP 示例(使用您也應該使用的 IV):

$data = 'hello this is some data';
$key = 'this is a cool and secret password';
$iv = random_bytes(16);

$encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
echo 'iv (as hex): ', bin2hex($iv), PHP_EOL;
echo 'encrypted: ', $encrypted, PHP_EOL; // note this is not hex

$decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $key, 0, $iv);
echo 'decrypted: ', $decrypted, PHP_EOL;
$ php test.php 
iv (as hex): 02c00788438518f241cb86dc90237102
encrypted: oRZAXMjNle6hkJ9rTHTeUl5VoHQol+020Q/iFnbgbeU=
decrypted: hello this is some data

編輯,更具體的例子,強調了解編碼的重要性:

// test.js
const crypto = require('crypto');

let data = 'hello this is some data';

const key = crypto.scryptSync('Password used to generate key', '', 32); // 256 / 8 = 32
const iv = crypto.randomBytes(16); // Initialization vector.

const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let crypted = cipher.update(data,'utf8','hex')
crypted += cipher.final('hex');

console.log('data: ', data);
console.log('key: ', key.toString('hex')); // key:  9266bc531befd01b6a55c232fa0efeb35625079e7024758b2e65d0dd72fe59df
console.log('crypted (as hex): ', crypted); // crypted (as hex):  b571d864da0680d77e4880d0071b49e456a1eead4b1cbfa42a9337965a466362
console.log('iv (as hex): ', iv.toString('hex')); // iv (as hex):  788ac1dcee25824b713b5201d07cc133

這里我們知道我們所有的輸出都是十六進制的,所以我們可以在 PHP 端將它們重新格式化為二進制數據:

// test.php

$iv = hex2bin( '788ac1dcee25824b713b5201d07cc133' );
$encrypted = hex2bin( 'b571d864da0680d77e4880d0071b49e456a1eead4b1cbfa42a9337965a466362' );
$key = hex2bin('9266bc531befd01b6a55c232fa0efeb35625079e7024758b2e65d0dd72fe59df');

$decrypted = openssl_decrypt($encrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
echo 'decrypted: ', $decrypted, PHP_EOL; // hello this is some data

最終編輯:現在可以使用密鑰派生實現。 這成功解密了您的“Hello world”:

$password = 'strong-key';

// derrive key and IV using function from SO, which implements same method node uses
$ar = deriveKeyAndIV($password, 1, 'aes-256-cbc', 'md5');
$key = $ar['key'];
$iv = $ar['iv'];

$decrypted = openssl_decrypt(hex2bin('28e1dfdedac467a015a9c8720d0a6451'), 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
echo 'decrypted: ', $decrypted, PHP_EOL; // Hello world

function deriveKeyAndIV($data,$count,$cipher,$digest) {
    $ivlen  = openssl_cipher_iv_length($cipher);
    $keylen = 32;
    $hash  = "";
    $hdata = "";
    while(strlen($hash) < $keylen+$ivlen) {
        $hdata .= $data;
        $md_buf = openssl_digest($hdata, $digest);
        //
        for ($i = 1; $i < $count; $i++) {
            $md_buf = openssl_digest ( hex2bin($md_buf),$digest);
        }
        $hdata = hex2bin($md_buf);
        $hash .= $hdata;
    }
    //
    $key = substr($hash,0,$keylen);
    $iv  = substr($hash,$keylen,$ivlen);
    //
    return array('key' => $key, 'iv' => $iv);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM