Updated August 2026 — full tutorial restored for this URL.
In this tutorial you learn how to encrypt and decrypt messages in Node.js using the built-in crypto module. We use AES-256-GCM (authenticated encryption). The URL slug keeps the historical spelling; the title is cleaned up for readers.
Note: True end-to-end encryption also needs key exchange (e.g. X25519) so the server never sees plaintext keys. Here we focus on the encrypt/decrypt building blocks.
1. Generate a key
const crypto = require('crypto');
const key = crypto.randomBytes(32); // store securely!
console.log(key.toString('base64'));
2. Encrypt a message
function encrypt(plaintext, key) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const ciphertext = Buffer.concat([
cipher.update(plaintext, 'utf8'),
cipher.final(),
]);
const tag = cipher.getAuthTag();
return {
iv: iv.toString('base64'),
tag: tag.toString('base64'),
data: ciphertext.toString('base64'),
};
}
3. Decrypt a message
function decrypt(payload, key) {
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
key,
Buffer.from(payload.iv, 'base64')
);
decipher.setAuthTag(Buffer.from(payload.tag, 'base64'));
const plaintext = Buffer.concat([
decipher.update(Buffer.from(payload.data, 'base64')),
decipher.final(),
]);
return plaintext.toString('utf8');
}
4. Wire a tiny CLI / API
const key = Buffer.from(process.env.APP_KEY, 'base64');
const sealed = encrypt('Hello Kindson', key);
console.log(sealed);
console.log(decrypt(sealed, key));
5. Security tips
- Never reuse IV with the same key.
- Prefer GCM/ChaCha20-Poly1305 over ECB/CBC without MAC.
- Do not log keys or plaintext.
- For passwords use
scrypt/argon2, not raw AES keys derived from plain strings without salt.