Last active
March 3, 2025 09:07
-
Star
(431)
You must be signed in to star a gist -
Fork
(109)
You must be signed in to fork a gist
-
-
Save vlucas/2bd40f62d20c1d49237a109d491974eb to your computer and use it in GitHub Desktop.
Stronger Encryption and Decryption in Node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createCipheriv, createDecipheriv, randomBytes } from "crypto"; | |
const ENCRYPTION_KEY: string = process.env.ENCRYPTION_KEY || ""; // Must be 256 bits (32 characters) | |
const IV_LENGTH: number = 16; // For AES, this is always 16 | |
/** | |
* Will generate valid encryption keys for use | |
* Not used in the code below, but generate one and store it in ENV for your own purposes | |
*/ | |
export function keyGen() { | |
return randomBytes(32).toString("hex"); | |
} | |
/** | |
* Encrypt a string | |
* Uses a random IV + encryption key for unique encrypted end result | |
*/ | |
export function encrypt(plainText: string, encryptionKey: string = ENCRYPTION_KEY): string { | |
const iv = randomBytes(IV_LENGTH); // Directly use Buffer returned by randomBytes | |
const cipher = createCipheriv("aes-256-cbc", Buffer.from(encryptionKey, "hex"), iv); | |
const encrypted = Buffer.concat([cipher.update(plainText, "utf8"), cipher.final()]); | |
// Return iv and encrypted data as hex, combined in one line | |
return iv.toString("hex") + ":" + encrypted.toString("hex"); | |
} | |
/** | |
* Decrypt a string | |
*/ | |
export function decrypt(text: string, encryptionKey: string = ENCRYPTION_KEY): string { | |
const [ivHex, encryptedHex] = text.split(":"); | |
if (!ivHex || !encryptedHex) { | |
throw new Error("Invalid or corrupted cipher format"); | |
} | |
const encryptedText = Buffer.from(encryptedHex, "hex"); | |
const decipher = createDecipheriv("aes-256-cbc", Buffer.from(encryptionKey, "hex"), Buffer.from(ivHex, "hex")); | |
let decrypted = Buffer.concat([decipher.update(encryptedText), decipher.final()]); | |
return decrypted.toString(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have one business question. In the case you need to update the ENCRYPTION_KEY in the future
I have 2 ideas:
Option 1: Create a discrete api to update all fields in database, but the transaction is massive and might not ideal for a product.
Option 2: Create a middleware to check the fields when you query and re-encrypt and update the row, but the problem is the old key is still required for decryption.
Then what would be more efficient method for this case? I'm truly stuck!