【问题标题】:Cannot convert PHP OpenSSL IV to Node.JS无法将 PHP OpenSSL IV 转换为 Node.JS
【发布时间】:2021-03-30 22:37:11
【问题描述】:

我正在尝试将我的对称 AES-256-CBC 加密从 PHP 转换为 NodeJS。但我认为我没有正确转换 IV,我尝试了不同的方法,但没有奏效。

我的 PHP 代码:

<?php
    class Encryption{
        const method = 'AES-256-CBC';
        private static $passwordString;
        private static $iv;
        private static $password;
        
        public static function encryptString($string){
            self::setEncryptionPasswordString();
            self::setEncryptionIV();
            self::setEncryptionPassword();
            
            $encrypted = openssl_encrypt($string, self::method, self::$password, OPENSSL_RAW_DATA, self::$iv);
            $encrypted = base64_encode($encrypted);
            $encrypted = str_replace(['+', '/', '='], ['-', '_', ''], $encrypted);
            return $encrypted;
        }
        
        public static function decryptString($string){
            self::setEncryptionPasswordString();
            self::setEncryptionIV();
            self::setEncryptionPassword();

            $string = str_replace(['-', '_'], ['+', '/'], $string);
            $string = base64_decode($string);
            $decrypted = openssl_decrypt($string, self::method, self::$password, OPENSSL_RAW_DATA, self::$iv);
            return $decrypted;
        }
        
        private static function setEncryptionPasswordString(){
            self::$passwordString = getenv("ENC_PASS");
        }

        private static function setEncryptionIV(){
            self::$iv = chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0) . chr(0x0);
        }
        
        private static function setEncryptionPassword(){
            self::$password = substr(hash('sha256', self::$passwordString, true), 0, 32);
        }
    }
?>

我的 NodeJS 代码:

const crypto = require("crypto");
const method = "AES-256-CBC";
const iv = Buffer.alloc(16);
const password = "my_password";

function encrypt(string){   
    //let key = crypto.createHash("SHA-256").update(String(password)).digest("base64").substr(0, 32); Not Working
    let key = "my_iv";
    let cipher = crypto.createCipheriv(method, key.substr(0, 32), iv);
    let encrypted = cipher.update(string);
    let result = encrypted.toString("base64").replace(/[=]/g, "").replace(/[+]/g, "-").replace(/[\/]/g, "_");

    return result;
}

function decrypt(string){

}

module.exports.encrypt = (string) => encrypt(string);
module.exports.decrypt = (string) => decrypt(string);

我认为,Buffer.alloc(16) 没有按预期工作,我不知道如何更改它。有人可以帮帮我吗!

【问题讨论】:

  • 为什么要使用静态 IV?请参阅cwe.mitre.org/data/definitions/329.html,尤其是“观察到的示例”部分,其中列出了静态 IV 如何帮助攻击者破坏流行软件产品的安全性。
  • @RobertKawecki '因为我想要静态加密响应,这不是更好的方法吗?
  • "静态加密响应" == "容易破解的加密"。理想情况下,调用encrypt("foo") N 次应该会产生 N 个不同的输出,从而使密码分析变得困难。如果您想唯一标识一段加密内容,则可以提供明文内容的哈希、HMAC 或签名,签名具有验证消息来源的附加效果。
  • @Sammitch 因此,如果我想将此数据存储在数据库中,对于每个加密列,我将有一个带有 HMAC 的“盲索引”。例如,如果我存储“Foo Bar Baz”和“Foo Bar Qux”,我将存储在两个“Foo”的盲索引中,搜索它,然后解密每一行以找到我的数据?
  • “安全加密”和“易于搜索”是盲索引之外的相互排斥的概念。您可能需要重新检查您的设计并重新考虑何时何地您真正需要实施额外的安全性。

标签: php node.js encryption openssl node-crypto


【解决方案1】:

下面的 Node.js 代码应该给出与 PHP 代码相同的结果:

Node.js

const crypto = require("crypto");
const Algorithm = "aes-256-cbc";

function encrypt(plainText, key, iv, outputEncoding = "base64") {
    const cipher = crypto.createCipheriv(Algorithm, key, iv);
    const output = Buffer.concat([cipher.update(plainText), cipher.final()]).toString(outputEncoding);
    return output.replace('+', '-').replace('/', '_').replace('=', '');
}

function decrypt(cipherText, key, iv, outputEncoding = "base64") {
    cipherText = Buffer.from(cipherText.replace('-', '+').replace('_', '/'), "base64");
    const cipher = crypto.createDecipheriv(Algorithm, key, iv);
    return Buffer.concat([cipher.update(cipherText), cipher.final()]).toString(outputEncoding);
}

const passwordString = "test password";

const KEY = crypto.createHash('sha256').update(passwordString).digest();
const IV = Buffer.alloc(16);

console.log("Key length (bits):", KEY.length * 8);
console.log("IV length (bits):", IV.length * 8);
const encrypted = encrypt("Brevity is the soul of wit", KEY, IV, "base64");
console.log("Encrypted (base64):", encrypted);
const decrypted = decrypt(encrypted, KEY, IV, "utf8")
console.log("Decrypted:", decrypted);

PHP

putenv('ENC_PASS=test password');
$x = new Encryption();
$encrypted = $x->encryptString("Brevity is the soul of wit");
echo "Encrypted (base64): " . $encrypted . "\r\n";
echo "Decrypted: " . $x->encryptString("Brevity is the soul of wit") . "\r\n";

两者都应该给出输出

IEqTyL_k1xgQaBZGFLYYfTmzytKzFgicM-5mWMyxgYw

正如@robert-kawecki 指出的那样,理想情况下,您应该为每种加密使用不同的 IV,以确保最佳安全级别。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 2020-07-17
    • 2017-10-15
    • 1970-01-01
    • 2015-03-07
    • 2019-05-25
    • 2011-07-22
    相关资源
    最近更新 更多