1

I'm trying to convert my symmetric AES-256-CBC encryption from PHP to NodeJS. But i think i'm not converting correctly the IV, and i tried different things, but not worked.

My PHP Code:

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

My NodeJS code:

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

I think, Buffer.alloc(16) is not working as i expect, and i don't know how to change it. Can someone help-me please!

5
  • 2
    Why are you using a static IV? Please see cwe.mitre.org/data/definitions/329.html and especially the "Observed Examples" section, which lists how a static IV helps attackers break the security of popular software products. Commented Mar 30, 2021 at 22:59
  • @RobertKawecki 'Cos i want static encrypted responses, isn't it the better way? Commented Mar 30, 2021 at 23:08
  • 2
    "static encrypted responses" == "encryption that's easy to break". Ideally calling encrypt("foo") N times should yield N distinct outputs so as to make cryptanalysis difficult. If you want to uniquely identify a piece of encrypted content then you could provide a hash, HMAC, or signature of the plaintext content, with the signature having the additional effect of validating message origin. Commented Mar 30, 2021 at 23:14
  • @Sammitch So, if i want to store this data in database, for every encrypted column, i would have a "blind index", with an HMAC. For example, if i store "Foo Bar Baz" and "Foo Bar Qux", i store in blind index of both "Foo", search for it, and decrypt every row to find my data? Commented Apr 5, 2021 at 11:04
  • 1
    "Securely encrypted" and "easily searchable" are mutually exclusive concepts outside of the blind index. You might want to re-examine your design and reconsider when and where you really need to implement additional security. Commented Apr 5, 2021 at 18:44

1 Answer 1

1

The Node.js code below should give the same result as the PHP code:

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

Both should give an output of

IEqTyL_k1xgQaBZGFLYYfTmzytKzFgicM-5mWMyxgYw

As @robert-kawecki pointed out, you should ideally use a different IV for each encryption to ensure the best level of security.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.