A simple Node.js library (written in TypeScript) and accompanying CLI tool for encrypting and decrypting data using the AES-256 CBC algorithm.
I wrote this simple package because I needed a quick and easy way to store credentials such as API keys and crypto wallet seed phrases on my development machine without having to keep them inside plain text files. In fact, my pain point was two-fold:
-
First, I wanted my Node.js scripts to prompt me for a password when it was time to decrypt the sensible information at runtime. This is what this package's library's core functions (i.e.,
encrypt
,encryptAsync
,decrypt
, anddecryptAsync
) are for. -
Secondly, I needed a simple program allowing me to manually encrypt the sensible information from a terminal, without having to store the data inside a file at any point during the encryption process. This is what this package's CLI (i.e., the
prompt-encrypt
command) is for.
The recommended way of installing this package is through the NPM registry.
# Install the package
npm install --save-dev @bb301/simple-encryption-util
# Use the CLI inside the current NPM project
npx prompt-encrypt
npm install --save @bb301/simple-encryption-util
# Install globally
npm install -g @bb301/simple-encryption-util
# Use the CLI from anywhere
prompt-encrypt
This library's core functions are encrypt
and decrypt
(which also have async
equivalents; i.e., encryptAsync
and decryptAsync
, respectively), and they are based on the AES-256 CBC algorithm
made available by Node's crypto module.
The library functions are declared inside src/lib.ts, and they are all carefully documented. The user should read the documentation and inspect the source code before using this library in a project.
This package also includes a CLI named prompt-encrypt
that can be used to start an interactive terminal that will prompt the user for a password and for the secret message to be encrypted. The result will be outputted to the terminal as an hexadecimal string, but the user will also be offered the possibility to save the result inside a text file.
Below are three examples illustrating (1) how to use the CLI to encrypt a secret message, (2) how to use the encrypt
and decrypt
library functions in a Node script, and (3) how to use the utility function requestPassword
along with decryptAsync
in order to decrypt a secret message at runtime.
This is a simple example that illustrates how to use the prompt-encrypt
CLI
command to encrypt a secret message using a password. prompt-encrypt
will
initialize a simple interactive terminal that will prompt the user twice for a password (to
make sure no input errors are made), and then twice for the secret message
(again, to make sure no input errors are made). At the end, the CLI
will print the encrypted message, and ask the user whether the user would like to
save the encrypted message to a file as well. In this example, we decline and
the interactive terminal session ends.
prompt-encrypt
#
# This is a simple CLI tool based on the AES-256 CBC algorithm.
# [read more](https://github.com/BB-301/node-simple-encryption-util)
#
# Enter password: ****
# Enter password again: ****
#
# Enter message: *****
# Enter message again: *****
#
# Here's your hex-encoded encrypted message:
#
# 10f1315f6ff11b87be9654ce4c23a342032145bc8c6c6d4b72b02d6854a26a0a
#
# Would you like to save the encrypted message to a file? (yes/y) n
The following example illustrates how this library's core functions encrypt
and decrypt
can be used to encrypt and decrypt a message using a given
password. Depending on the context, the user may prefer to use the asynchronous
versions of those two functions; i.e., encryptAsync
and decryptAsync
, respectively.
import assert from "assert";
import { encrypt, decrypt } from "@bb301/simple-encryption-util";
const main = () => {
const secretMessage: string = "This is a secret message";
const password: string = "strong_password";
const key = Buffer.from(password, "utf-8");
const encrypted = encrypt(Buffer.from(secretMessage, "utf-8"), key);
console.log(`Encrypted data: ${encrypted.toString("hex")}`);
const decrypted = decrypt(encrypted, key).toString("utf-8");
assert.deepStrictEqual(decrypted, secretMessage, "Decrypted message should match initial message");
console.log(`Decrypted message: ${secretMessage}`);
}
main();
This final example illustrates how the requestPassword
utility function can
be used along with the decryptAsync
function inside a script to prompt the
user for a password at runtime to decrypt a secret message.
import assert from "assert";
import { decryptAsync, requestPassword } from "../lib";
const EXPECTED_MESSAGE: string = "This is a secret message!";
const HEX_ENCRYPTED_MESSAGE: string = "0a2a0794611400aca0fa45e21e35c1131e600316802365b363db7008366e5bf2195929980d6136be8478686b7515792f";
const main = async () => {
// NOTE: The password is 'weak_password'
const password = await requestPassword("Please enter your password: ");
const key = Buffer.from(password, "utf-8");
const data = Buffer.from(HEX_ENCRYPTED_MESSAGE, "hex");
const decryptedMessage = (await decryptAsync(data, key)).toString("utf-8");
assert.deepStrictEqual(decryptedMessage, EXPECTED_MESSAGE);
console.log(`The secret message is: ${decryptedMessage}\n`);
}
main().catch(e => {
console.error(e);
process.exit(1);
});
I am not a cryptography expert, so I wouldn't necessarily know if there were anything wrong with my current implementation, although based on my research of the subject, I believe my implementation to be correct. So please make sure to review the source code before using this library (or CLI tool) in your project. And please let me know if you find anything that needs correcting in my implementation.
If you have any questions, if you find bugs, or if you have suggestions for this project, please feel free to contact me by opening an issue on the repository.
This project is released under the MIT License.
Copyright (c) 2024 BB-301 (fw3dg3@gmail.com)