AES-256-GCM String Encryption
Encrypt and authenticate strings with AES-256-GCM, deriving the key from a passphrase and random salt via scrypt.
Code
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "node:crypto";
const ALGORITHM = "aes-256-gcm";
export interface EncryptedPayload {
salt: string;
iv: string;
tag: string;
data: string;
}
export function deriveAesKey(passphrase: string, salt: Buffer): Buffer {
if (typeof passphrase !== "string" || passphrase.length < 12) {
throw new RangeError("passphrase must be at least 12 characters");
}
return scryptSync(passphrase.normalize("NFKC"), salt, 32);
}
export function encryptString(plaintext: string, passphrase: string): EncryptedPayload {
const salt = randomBytes(16);
const iv = randomBytes(12);
const cipher = createCipheriv(ALGORITHM, deriveAesKey(passphrase, salt), iv);
const data = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
return {
salt: salt.toString("base64"),
iv: iv.toString("base64"),
tag: cipher.getAuthTag().toString("base64"),
data: data.toString("base64"),
};
}
export function decryptString(payload: EncryptedPayload, passphrase: string): string {
const salt = Buffer.from(payload.salt, "base64");
const iv = Buffer.from(payload.iv, "base64");
const tag = Buffer.from(payload.tag, "base64");
const decipher = createDecipheriv(ALGORITHM, deriveAesKey(passphrase, salt), iv);
decipher.setAuthTag(tag);
return Buffer.concat([
decipher.update(Buffer.from(payload.data, "base64")),
decipher.final(),
]).toString("utf8");
}Report a problem with this exampleOpens a pre-filled issue on GitHub.