Search code examples
node.jsencryptionopensslcryptojs

Encrypt in Node.JS Crypto (aes-256-cbc) then decrypt in OpenSSL CLI


I am encrypting a file in Node.js, and attempting to decrypt using OpenSSL command line. I am an experienced developer, but I am not completely educated on encryption. I essentially just need a good way to encrypt a file programmatically with the ability to decrypt it at a later date using the command line.

Node.JS Code:

const crypto = require('crypto');
const fs = require('fs');
const { pipeline } = require('stream');

const algorithm = 'aes-256-cbc';
const password = 'ABC123';


crypto.scrypt(password, 'salt', 32, (err, key) => {
    if (err) throw err;
    // Then, we'll generate a random initialization vector
    crypto.randomFill(new Uint8Array(16), (err, iv) => {
        if (err) throw err;

        const cipher = crypto.createCipheriv(algorithm, key, iv);


        const input = fs.createReadStream('test.txt');
        const output = fs.createWriteStream('test.enc');

        pipeline(input, cipher, output, (err) => {
            if (err) throw err;
        });
    });
});

My CLI Command:

openssl enc -aes-256-cbc -nosalt -d -in test.enc -out test2.txt

This gives me:

bad decrypt

Solution

  • I believe bad decrypt means that openssl doesn't understand the encryption key

    Here is what happens.

    1. As a first step crypto generates an encryption key using the provided password and salt: crypto.scrypt(password, 'salt', 32,...
    2. As a second step it generates an initialization vector (iv): crypto.randomFill(new Uint8Array(16)
    3. Finally it uses the generated key and iv to create a cipher and actually encrypt the file: pipeline(input, cipher, output,

    So, to decrypt this file using openssl both key and iv need to be provided.

    Here is one way to decrypt it. See added code at the bottom that generates openssl decrypt command:

    const crypto = require('crypto');
    const fs = require('fs');
    const { pipeline } = require('stream');
    
    const algorithm = 'aes-256-cbc';
    const password = 'ABC123';
    
    crypto.scrypt(password, 'salt', 32, {}, (err, key) => {
      if (err) {
        throw err;
      }
      // Then, we'll generate a random initialization vector
      crypto.randomFill(new Uint8Array(16), (err, iv) => {
        if (err) {
          throw err;
        }
    
        const cipher = crypto.createCipheriv(algorithm, key, iv);
    
    
        const input = fs.createReadStream('test.txt');
        const output = fs.createWriteStream('test.enc');
    
        pipeline(input, cipher, output, (err) => {
          if (err) {
            throw err;
          }
        });
    
        // Generate openssl decrypt command
        const hexKey = key.toString('hex');
        const hexIv = Buffer.from(iv).toString('hex');
        console.log(`openssl enc -aes-256-cbc -d -in test.enc -out test2.txt -K ${hexKey} -iv ${hexIv}`);
      });
    });