* 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')
 | |
| 
 | |
| }
 |