Last active
May 3, 2023 06:07
-
-
Save Js-Brecht/97488f1951d6d35502d331c97b3b3c19 to your computer and use it in GitHub Desktop.
Encryption handler using Node's Cipheriv and Decipheriv
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 * 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