Encrypt and Decrypt Files in Node.js: A Step-by-Step Guide Using AES-256-CBC

Mohammed shamseer pv
5 min readSep 25, 2024

--

In today’s digital world, protecting your sensitive data is more important than ever. Whether you’re storing personal files, sharing confidential information, or securing backups, encryption is a powerful tool that keeps your data safe from unauthorized access. In this guide, I’ll walk you through how to encrypt and decrypt files using Node.js, with a focus on the AES-256-CBC algorithm. Let’s dive in!

Why Encryption Matters

Encryption transforms readable data into an unreadable format using algorithms and keys, making it nearly impossible for unauthorized users to access. When you encrypt a file, it can only be decrypted with the correct passphrase or key, ensuring that your sensitive data remains protected.

Getting Started: What You’ll Need

To follow along with this tutorial, you’ll need:

  • Basic knowledge of JavaScript and Node.js.
  • Node.js installed on your machine.
  • A text editor (like VS Code) and access to the command line.

Step 1: Set Up Your Node.js Project

First, let’s create a new Node.js project. Open your terminal and run the following commands:

mkdir file-encryption
cd file-encryption
npm init -y

This will create a new directory called file-encryption and initialize it with a default package.json file.

Step 2: Understanding the Key Concepts

Before we get into the code, here are some important terms to know:

  • AES-256-CBC: This is a symmetric encryption algorithm that uses a 256-bit key. It’s widely used for its strong security.
  • PBKDF2: A key derivation function that generates a cryptographic key from a passphrase and a salt. It’s used to strengthen passwords by adding computational complexity.
  • Salt: A random value added to the passphrase before encryption. It ensures that even if the same passphrase is used multiple times, the resulting key will be different.
  • IV (Initialization Vector): A random value used to ensure the first block of data is encrypted uniquely, making the encryption process more secure.

Step 3: Writing the Code to Encrypt and Decrypt Files

Let’s break down the complete code into smaller, easy-to-understand sections.

Deriving the Key and IV

We use the PBKDF2 function to derive a cryptographic key and IV from the passphrase and salt. The salt ensures the uniqueness of the key, while the IV is used to add randomness to the encryption process.

const crypto = require('crypto');

// Encryption settings
const algorithm = 'aes-256-cbc'; // Algorithm to use
const iterations = 100000; // Number of iterations for PBKDF2
const keyLength = 32; // Key length for AES-256
const ivLength = 16; // IV length for AES

// Function to derive a key and IV from a passphrase and salt
function deriveKeyAndIV(password, salt) {
// Derive the key using PBKDF2
const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, 'sha256');
const iv = key.slice(0, ivLength); // Use the first 16 bytes as the IV
return { key, iv };
}

Encrypting the File

Next, we’ll encrypt the file using the derived key and IV. The encryption process reads the file, encrypts the content, and saves the encrypted data back to the file along with the salt.

const fs = require('fs');

// Function to encrypt the file content
function encryptFile(filePath, password) {
try {
// Generate a random salt
const salt = crypto.randomBytes(16);

// Derive the key and IV from the passphrase and salt
const { key, iv } = deriveKeyAndIV(password, salt);

// Read the file data
const fileData = fs.readFileSync(filePath);

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

// Encrypt the data
const encryptedData = Buffer.concat([cipher.update(fileData), cipher.final()]);

// Write the salt and encrypted data back to the file
fs.writeFileSync(filePath, Buffer.concat([salt, encryptedData]));

console.log('File encrypted successfully.');
} catch (error) {
console.error('Error during encryption:', error.message);
}
}

Decrypting the File

Decrypting is the reverse process. We extract the salt and encrypted data from the file, derive the key and IV, and then decrypt the data back into its original form.

// Function to decrypt the file content
function decryptFile(filePath, password) {
try {
// Read the file data
const fileData = fs.readFileSync(filePath);

// Extract the salt (first 16 bytes) and the encrypted data
const salt = fileData.slice(0, 16);
const encryptedData = fileData.slice(16);

// Derive the key and IV from the passphrase and extracted salt
const { key, iv } = deriveKeyAndIV(password, salt);

// Create decipher
const decipher = crypto.createDecipheriv(algorithm, key, iv);

// Decrypt the data
const decryptedData = Buffer.concat([decipher.update(encryptedData), decipher.final()]);

// Write the decrypted data back to the file
fs.writeFileSync(filePath, decryptedData);

console.log('File decrypted successfully.');
} catch (error) {
console.error('Error during decryption:', error.message);
}
}

Step 4: Testing Your Encryption and Decryption Functions

Now it’s time to put our functions to the test! Replace filePath with the path to your file, and provide a strong password.

// Example usage
const filePath = './thumbnail/thumbnail4.jpg'; // Replace with your file path
const password = 'this is my encryption password'; // Replace with your passphrase

// Encrypt the file
encryptFile(filePath, password);

// Decrypt the file (to verify)
decryptFile(filePath, password);

Full code

const fs = require('fs');
const crypto = require('crypto');

// Encryption settings
const algorithm = 'aes-256-cbc'; // Algorithm to use
const iterations = 100000; // Number of iterations for PBKDF2
const keyLength = 32; // Key length for AES-256
const ivLength = 16; // IV length for AES

// Function to derive a key and IV from a passphrase and salt
function deriveKeyAndIV(password, salt) {
// Derive the key using PBKDF2
const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, 'sha256');
const iv = key.slice(0, ivLength); // Use the first 16 bytes as the IV
return { key, iv };
}

// Function to encrypt the file content
function encryptFile(filePath, password) {
try {
// Generate a random salt
const salt = crypto.randomBytes(16);

// Derive the key and IV from the passphrase and salt
const { key, iv } = deriveKeyAndIV(password, salt);

// Read the file data
const fileData = fs.readFileSync(filePath);

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

// Encrypt the data
const encryptedData = Buffer.concat([cipher.update(fileData), cipher.final()]);

// Write the salt and encrypted data back to the file
fs.writeFileSync(filePath, Buffer.concat([salt, encryptedData]));

console.log('File encrypted successfully.');
} catch (error) {
console.error('Error during encryption:', error.message);
}
}

// Function to decrypt the file content
function decryptFile(filePath, password) {
try {
// Read the file data
const fileData = fs.readFileSync(filePath);

// Extract the salt (first 16 bytes) and the encrypted data
const salt = fileData.slice(0, 16);
const encryptedData = fileData.slice(16);

// Derive the key and IV from the passphrase and extracted salt
const { key, iv } = deriveKeyAndIV(password, salt);

// Create decipher
const decipher = crypto.createDecipheriv(algorithm, key, iv);

// Decrypt the data
const decryptedData = Buffer.concat([decipher.update(encryptedData), decipher.final()]);

// Write the decrypted data back to the file
fs.writeFileSync(filePath, decryptedData);

console.log('File decrypted successfully.');
} catch (error) {
console.error('Error during decryption:', error.message);
}
}

// Example usage
const filePath = './thumbnail/thumbnail4.jpg'; // Replace with your file path
const password = 'this is my encryption password'; // Replace with your passphrase

// Encrypt the file
encryptFile(filePath, password);

// Decrypt the file (to verify)
decryptFile(filePath, password);

Run the code using Node.js:

node index.js

You should see messages confirming that the file was successfully encrypted and then decrypted. Verify that the file’s contents are restored correctly after decryption.

Conclusion

File encryption in Node.js is a powerful way to add an extra layer of security to your data. By leveraging AES-256-CBC and PBKDF2, we can create robust encryption schemes that protect sensitive information from unauthorized access. Whether you’re securing files for personal use or implementing encryption in larger applications, this guide provides a solid foundation to get started.

--

--

Mohammed shamseer pv
Mohammed shamseer pv

Written by Mohammed shamseer pv

skilled in Flutter, Node.js, Python, and Arduino, passionate about AI and creating innovative solutions. Active in tech community projects.

No responses yet