1005913c0b
* Encrypts all notes going to the database * Creates encrypted snippets for loading note title cards * Creates an encrypted search index when note is changed * Migrates users to encrypted notes on login * Creates new encrypted master keys for newly logged in users
114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
/*
|
|
Crypto String
|
|
Securely Encrypts and decrypts a string using a password
|
|
*/
|
|
|
|
|
|
const IV_BYTE_SIZE = 100 // Size of initialization vector
|
|
const SALT_BYTE_SIZE = 900 // Size of salt
|
|
const KEY_BYTE_SIZE = 32 // size of cipher key
|
|
const AUTH_TAG_SIZE = 16 // Size of authentication tag
|
|
|
|
|
|
const crypto = require('crypto')
|
|
|
|
let CryptoString = module.exports = {}
|
|
|
|
CryptoString.encrypt = (password, salt64, rawText) => {
|
|
|
|
const initializationVector = crypto.randomBytes(IV_BYTE_SIZE)
|
|
const salt = Buffer.from(salt64, 'base64')
|
|
const key = CryptoString.seasonedPassword(password, salt)
|
|
|
|
const cipher = crypto.createCipheriv('aes-256-gcm', key, initializationVector, { 'authTagLength': AUTH_TAG_SIZE })
|
|
let encryptedMessage = cipher.update(rawText)
|
|
|
|
encryptedMessage = Buffer.concat([encryptedMessage, cipher.final()])
|
|
return Buffer.concat([initializationVector, encryptedMessage, cipher.getAuthTag()]).toString('base64')
|
|
|
|
}
|
|
|
|
//Decrypt base64 string cipher text,
|
|
CryptoString.decrypt = (password, salt64, cipherTextString) => {
|
|
|
|
let cipherText = Buffer.from(cipherTextString, 'base64')
|
|
const salt = Buffer.from(salt64, 'base64')
|
|
|
|
const authTag = cipherText.slice(AUTH_TAG_SIZE*-1)
|
|
const initializationVector = cipherText.slice(0, IV_BYTE_SIZE)
|
|
const encryptedMessage = cipherText.slice(IV_BYTE_SIZE, AUTH_TAG_SIZE*-1)
|
|
|
|
const key = CryptoString.seasonedPassword(password, salt)
|
|
|
|
const decipher = crypto.createDecipheriv('aes-256-gcm', key, initializationVector, { 'authTagLength': AUTH_TAG_SIZE })
|
|
|
|
try {
|
|
decipher.setAuthTag(authTag)
|
|
|
|
let messagetext = decipher.update(encryptedMessage)
|
|
messagetext = Buffer.concat([messagetext, decipher.final()]).toString('utf8')
|
|
|
|
return messagetext
|
|
|
|
} catch(err) {
|
|
|
|
// console.log(err)
|
|
return null
|
|
}
|
|
|
|
}
|
|
|
|
//Salt the password - return {buffer}
|
|
CryptoString.seasonedPassword = (password, salt) => {
|
|
|
|
return crypto.scryptSync(password, salt, KEY_BYTE_SIZE)
|
|
}
|
|
|
|
//Create random salt - return {string}
|
|
CryptoString.createSalt = () => {
|
|
|
|
return crypto.randomBytes(SALT_BYTE_SIZE).toString('base64')
|
|
}
|
|
CryptoString.createSmallSalt = () => {
|
|
|
|
return crypto.randomBytes(20).toString('base64')
|
|
}
|
|
|
|
CryptoString.hash = (hashString) => {
|
|
|
|
return crypto.createHash('sha256').update(hashString).digest()
|
|
}
|
|
|
|
CryptoString.test = () => {
|
|
|
|
const pp = (title, output) => {
|
|
console.log('----------------'+title+'----------------')
|
|
console.log(output)
|
|
}
|
|
|
|
const password = 'ItsMePasswordio123'
|
|
const text = '<p>The genesis of  a new note. Very magical.<br></p><p>Quite a weonderful thing<br></p><p><br></p><p>Weonderful for sheore <br></p>'
|
|
|
|
const hashTest = CryptoString.createSalt('password')
|
|
|
|
const salt = CryptoString.createSalt()
|
|
pp('salt',salt.length)
|
|
|
|
const seasonPass = CryptoString.seasonedPassword(password, salt)
|
|
|
|
const cipherText = CryptoString.encrypt(password, salt, text)
|
|
|
|
const decipheredText = CryptoString.decrypt(password, salt, cipherText)
|
|
pp('Success Decrypt', decipheredText == text ? 'Pass 😁':'Fail' )
|
|
|
|
const wrongPass = CryptoString.decrypt('Wrong Password', salt, cipherText)
|
|
pp('Wrong Password', wrongPass === null ? 'Pass':'Fail')
|
|
|
|
const wrongSalt = CryptoString.decrypt(password, 'Wrong Salt', cipherText)
|
|
pp('Wrong Salt', wrongSalt === null ? 'Pass':'Fail')
|
|
|
|
const wrongCipher = CryptoString.decrypt(password, salt, Buffer.from('Hello there'))
|
|
pp('Wrong Cipher Text', wrongCipher === null ? 'Pass':'Fail')
|
|
|
|
}
|