SolidScribe/server/helpers/CryptoString.js
Max G 1005913c0b Fully Encrypted notes Beta
* 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
2020-05-06 07:10:27 +00:00

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&nbsp 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')
}