Last active
December 20, 2022 18:45
-
-
Save rigwild/a4f4cf1527bc044dbbc92f37f727484e to your computer and use it in GitHub Desktop.
`aes-256-gcm` encryption with native crypto module
This file contains hidden or 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
const crypto = require('crypto') | |
/** | |
* Encrypts text by given key | |
* @param {string} text to encrypt | |
* @param {Buffer | string} masterkey | |
* @returns {string} encrypted text, base64 encoded | |
*/ | |
function encrypt(text, masterkey) { | |
// random initialization vector | |
const iv = crypto.randomBytes(16) | |
// random salt | |
const salt = crypto.randomBytes(64) | |
// derive encryption key: 32 byte key length | |
// in assumption the masterkey is a cryptographic and NOT a password there is no need for | |
// a large number of iterations. It may can replaced by HKDF | |
// the value of 2145 is randomly chosen! | |
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512') | |
// AES 256 GCM Mode | |
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv) | |
// encrypt the given text | |
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]) | |
// extract the auth tag | |
const tag = cipher.getAuthTag() | |
// generate output | |
return Buffer.concat([salt, iv, tag, encrypted]).toString('base64') | |
} | |
/** | |
* Decrypts text by given key | |
* @param {string} encdata encoded input data | |
* @param {Buffer | string} masterkey | |
* @returns {string} decrypted (original) text | |
*/ | |
function decrypt(encdata, masterkey) { | |
// base64 decoding | |
const bData = Buffer.from(encdata, 'base64') | |
// convert data to buffers | |
const salt = bData.slice(0, 64) | |
const iv = bData.slice(64, 80) | |
const tag = bData.slice(80, 96) | |
const text = bData.slice(96) | |
// derive key using; 32 byte key length | |
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512') | |
// AES 256 GCM Mode | |
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv) | |
decipher.setAuthTag(tag) | |
// encrypt the given text | |
const decrypted = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8') | |
return decrypted | |
} | |
// Usage | |
// Get a random secret key, or your own | |
const secret = [...Array(50)].map(() => Math.random().toString(36)[2]).join('') | |
// const secret = 'this is my safe secret 123' | |
const key = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 32) | |
const str = 'hello world!' | |
const encrypted = encrypt(str, key) | |
console.log(encrypted) | |
const decrypted = decrypt(encrypted, key) | |
console.log(str === decrypted, decrypted) |
This file contains hidden or 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 crypto from 'crypto' | |
/** Encrypt text by given key */ | |
function encrypt(text: string, masterkey: Buffer | string): string { | |
// random initialization vector | |
const iv = crypto.randomBytes(16) | |
// random salt | |
const salt = crypto.randomBytes(64) | |
// derive encryption key: 32 byte key length | |
// in assumption the masterkey is a cryptographic and NOT a password there is no need for | |
// a large number of iterations. It may can replaced by HKDF | |
// the value of 2145 is randomly chosen! | |
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512') | |
// AES 256 GCM Mode | |
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv) | |
// encrypt the given text | |
const encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]) | |
// extract the auth tag | |
const tag = cipher.getAuthTag() | |
// generate output | |
return Buffer.concat([salt, iv, tag, encrypted]).toString('base64') | |
} | |
/** Decrypt text by given key */ | |
function decrypt(encdata: string, masterkey: Buffer | string): string { | |
// base64 decoding | |
const bData = Buffer.from(encdata, 'base64') | |
// convert data to buffers | |
const salt = bData.slice(0, 64) | |
const iv = bData.slice(64, 80) | |
const tag = bData.slice(80, 96) | |
const text = bData.slice(96) | |
// derive key using; 32 byte key length | |
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512') | |
// AES 256 GCM Mode | |
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv) | |
decipher.setAuthTag(tag) | |
// encrypt the given text | |
// const decrypted = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8') | |
const decrypted = decipher.update(text.toString('binary'), 'binary', 'utf8') + decipher.final('utf8') | |
// const decrypted = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8') | |
return decrypted | |
} | |
// Usage | |
// Get a random secret key, or your own | |
const secret = [...Array(50)].map(() => Math.random().toString(36)[2]).join('') | |
// const secret = 'this is my safe secret 123' | |
const key = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 32) | |
const str = 'hello world!' | |
const encrypted = encrypt(str, key) | |
console.log(encrypted) | |
const decrypted = decrypt(encrypted, key) | |
console.log(str === decrypted, decrypted) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment