Skip to content

Instantly share code, notes, and snippets.

@TravisMullen
Last active March 15, 2019 20:47
Show Gist options
  • Save TravisMullen/88882d1de04c882540527f3d0bd68234 to your computer and use it in GitHub Desktop.
Save TravisMullen/88882d1de04c882540527f3d0bd68234 to your computer and use it in GitHub Desktop.
AES - Cipher Block Chaining (CBC) - 192 bit
const { randomFill, createCipheriv, createDecipheriv } = require('crypto')
const algorithm = 'aes-192-cbc'
/**
* Nonce ================
*/
const _dirtyNonce = {}
/** dirtyNonce - used none. */
const dirtyNonce = () => (
Object
.freeze(
Object
.keys(_dirtyNonce)
)
)
const _nonce = () => {
const buf = Buffer.alloc(16)
return new Promise((resolve, reject) => {
randomFill(buf, (err, buf) => {
if (err) { reject(err) } console.log(buf.toString('hex'))
resolve(buf)
})
})
}
const _nonceGenerator = async () => {
console.time(`nonce generator`)
let nonce = await _nonce()
while (isDirty(nonce)) {
nonce = await _nonce()
}
console.timeEnd(`nonce generator`)
return nonce
}
const isDirty = nonce => {
const iv = nonce.toString('hex')
if (_dirtyNonce[iv]) {
return true
}
_dirtyNonce[iv] = true
return false
}
const isClean = nonce => !(isDirty(nonce))
/**
* Nonce Generator - Validate provide and/or produce unique.
* @param {string|number} nonce Input for custom nonce.
* @return {string|number} Unique nonce that has passed validation.
*/
const nonceGenerator = async nonce => {
// make sure IV is unique and valid length
let iv
if (nonce &&
nonce.length === (Buffer.alloc(16, 0)).length &&
isClean(nonce)
) {
console.log(`Supplied nonce: ${nonce.toString ? nonce.toString('hex') : nonce}
=> Correct IV length to match 'Buffer.alloc(16, 0)'
=> Unique :: Use method 'dirty()' for Array of used nonces.`)
iv = nonce
} else {
iv = await _nonceGenerator()
}
return iv
}
/**
* cipher - convert plaintext to encrypted hex string.
* @param {string|Buffer} options.key Key
* @param {string|Buffer} options.nonce Unique - will create a unique if has been used.
* @param {string} plaintext Payload to encrypt.
* @param {Boolean} persistance Should this be saved locally to a file.
* @return {Promise{ nonce, encrypted, chunks }}
*/
const cipher = async ({ key, nonce }, plaintext, persistance = false) => {
console.time(`${algorithm}:cipher`)
// allow override for testing and
const iv = await nonceGenerator(nonce)
const pher = createCipheriv(algorithm, key, iv)
const encrypted = []
return new Promise(async (resolve, reject) => {
pher.on('readable', () => {
let chunk
while ((chunk = pher.read()) !== null) {
encrypted.push(chunk.toString('hex'))
}
console.count(`cipher::reading chunk`)
})
pher.on('end', () => {
console.log(`encrypted:${encrypted.join('')}
cipher:end`)
console.timeEnd(`${algorithm}:cipher`)
// Prints: some clear text data
resolve({
nonce: iv,
encrypted: encrypted.join(''),
chunks: encrypted
})
})
pher.on('error', err => {
console.log('Encryption Cipher failed!')
reject(err)
})
// could return a complete promise
pher.write(plaintext)
pher.end()
})
}
/**
* decipher - convert plaintext to encrypted hex string.
* @param {string|Buffer} options.key Key
* @param {string|Buffer} options.nonce from cipher.
* @param {string} encrypted Ciphertext to decrypt.
* @return {Promise{ plaintext, chunks }}
*/
const decipher = ({ key, nonce }, encrypted) => {
console.time(`${algorithm}:decipher`)
const pher = createDecipheriv(algorithm, key, nonce)
const plaintext = []
return new Promise((resolve, reject) => {
pher.on('readable', () => {
let chunk
while ((chunk = pher.read()) !== null) {
plaintext.push(chunk.toString('utf8'))
}
console.count(`decipher::reading chunk`)
})
pher.on('end', () => {
// `${plaintext}:iv`
console.log(`plaintext:${plaintext.join('')}
decipher:end`)
console.timeEnd(`${algorithm}:decipher`)
// Prints: some clear text data
//
resolve({
plaintext: plaintext.join(''),
chunks: plaintext
})
})
pher.on('error', err => {
console.log('Decipher failed!')
reject(err)
})
pher.write(encrypted, 'hex')
pher.end()
})
}
module.exports = { cipher, decipher, dirtyNonce }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment