Skip to content

Instantly share code, notes, and snippets.

@Js-Brecht
Last active May 3, 2023 06:07
Show Gist options
  • Save Js-Brecht/97488f1951d6d35502d331c97b3b3c19 to your computer and use it in GitHub Desktop.
Save Js-Brecht/97488f1951d6d35502d331c97b3b3c19 to your computer and use it in GitHub Desktop.
Encryption handler using Node's Cipheriv and Decipheriv
import * as crypto from "crypto";
const ALG_NAME = "aes-256-gcm";
const ALG_SIZES = {
NONCE: 16,
TAG: 16,
KEY: 16,
};
const PBKDF2 = {
NAME: "sha256",
SALT_SIZE: 16,
ITER: 32767,
};
const getPbkdf2 = (password: string, salt: Buffer): Promise<Buffer> => {
return new Promise((resolve, reject) => {
crypto.pbkdf2(Buffer.from(password, "utf8"), salt, PBKDF2.ITER, ALG_SIZES.KEY, PBKDF2.NAME, (err, derivedKey) => {
if (err) {
reject(err);
} else {
resolve(derivedKey);
}
});
});
};
const getCryptoKey = (key: Buffer) => (
crypto.createHash("sha256").update(key).digest()
);
export const encryptContent = async (plainText: string, password: string): Promise<string> => {
// Generate a 128-bit salt using a PBKDF2.
const salt = crypto.randomBytes(PBKDF2.SALT_SIZE);
// Derive a key using PBKDF2.
const key = getCryptoKey(await getPbkdf2(password, salt));
// Generate a 128-bit nonce using a CSPRNG.
const nonce = crypto.randomBytes(ALG_SIZES.NONCE);
// Create the cipher instance.
const cipher = crypto.createCipheriv(ALG_NAME, key, nonce);
// Encrypt and prepend salt.
return Buffer.concat([
salt,
nonce,
cipher.update(plainText),
cipher.final(),
cipher.getAuthTag(),
]).toString("base64");
};
export const decryptContent = async (base64EncryptedContent: string, password: string): Promise<string> => {
// Decode the base64.
const encCipher = Buffer.from(base64EncryptedContent, "base64");
// Create buffers of salt, nonce, encryption cipher, and auth tag
let position = 0;
const salt = encCipher.slice(position, position += PBKDF2.SALT_SIZE);
const nonce = encCipher.slice(position, position += ALG_SIZES.NONCE);
const encContent = encCipher.slice(position, encCipher.length - ALG_SIZES.TAG);
const tag = encCipher.slice(encCipher.length - ALG_SIZES.TAG);
// Derive the key using PBKDF2.
const key = getCryptoKey(await getPbkdf2(password, salt));
const decipher = crypto.createDecipheriv(ALG_NAME, key, nonce);
decipher.setAuthTag(tag);
return Buffer.concat([decipher.update(encContent), decipher.final()]).toString("utf8");
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment