Created
May 17, 2019 21:20
-
-
Save marclundgren/b508c766301774ddbc046119575443be to your computer and use it in GitHub Desktop.
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
/* https://functional.works-hub.com/learn/how-i-encrypted-a-database-without-storing-the-keys-anywhere-9da75?utm_source=reddit&utm_medium=organicsocial&utm_campaign=j.kaplan */ | |
const crypto = require('crypto'); | |
// Uses the PBKDF2 algorithm to stretch the string 's' to an arbitrary size, | |
// in a way that is completely deterministic yet impossible to guess without | |
// knowing the original string | |
function stretchString(s, salt, outputLength) { | |
return crypto.pbkdf2Sync(s, salt, 100000, outputLength, 'sha512'); | |
} | |
// Stretches the password in order to generate a key (for encrypting) | |
// and a large salt (for hashing) | |
function keyFromPassword(password){ | |
// We need 24 bytes for the key, and another 48 bytes for the salt | |
const keyPlusHashingSalt = stretchString(password, 'salt', 24 + 48); | |
return { | |
cipherKey: keyPlusHashingSalt.slice(0,24), | |
hashingSalt: keyPlusHashingSalt.slice(24) | |
}; | |
} | |
// Encrypts data using the key generated using the 'keyFromPassword' function | |
function encrypt(key, sourceData){ | |
const iv = Buffer.alloc(16, 0); // Initialization vector | |
const cipher = crypto.createCipheriv('aes-192-cbc', key.cipherKey, iv); | |
let encrypted = cipher.update(sourceData, 'binary', 'binary'); | |
encrypted += cipher.final('binary'); | |
return encrypted; | |
} | |
// Decrypts data using the key generated using the 'keyFromPassword' function | |
function decrypt(key, encryptedData){ | |
const iv = Buffer.alloc(16, 0); // Initialization vector | |
const decipher = crypto.createDecipheriv('aes-192-cbc', key.cipherKey, iv); | |
let decrypted = decipher.update(encryptedData, 'binary', 'binary'); | |
decrypted += decipher.final('binary'); | |
return decrypted; | |
} | |
// Computes a unique (integer) hash from the given data, using the salt | |
// we generated from the password (using 'keyFromPassword') | |
function hash(key, sourceData){ | |
const hashBuffer = stretchString(sourceData, key.hashingSalt, 8); | |
return hashBuffer.readUIntLE(0, 6); | |
} | |
const key = keyFromPassword('Our password'); | |
const encryptedTest = encrypt(key, 'This is a test'); | |
// prints 'This is a test', after encrypting it and decrypting it again | |
console.log( | |
decrypt(key, encryptedTest) | |
); | |
// Prints the hash 120042280565918, generated from 'This is another test' | |
console.log( | |
hash(key, 'This is another test') | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Changes from the original script
readUIntLE byteLength must satisfy 0 < byteLength <= 6.