From 50b789fc396da192e4d4cbe232137ceb3a19a5b1 Mon Sep 17 00:00:00 2001 From: azivner Date: Sun, 12 Nov 2017 21:40:26 -0500 Subject: [PATCH] server side encryption WIP --- public/javascripts/dialogs/settings.js | 2 - public/javascripts/encryption.js | 75 ++------------------------ public/javascripts/note_editor.js | 8 --- public/javascripts/note_tree.js | 2 - routes/api/notes.js | 9 ++++ 5 files changed, 12 insertions(+), 84 deletions(-) diff --git a/public/javascripts/dialogs/settings.js b/public/javascripts/dialogs/settings.js index 63ae5aa51..95fb21dbf 100644 --- a/public/javascripts/dialogs/settings.js +++ b/public/javascripts/dialogs/settings.js @@ -91,8 +91,6 @@ settings.addModule((function() { // encryption password changed so current encryption session is invalid and needs to be cleared encryption.resetEncryptionSession(); - - encryption.setEncryptedDataKey(result.new_encrypted_data_key); } else { showError(result.message); diff --git a/public/javascripts/encryption.js b/public/javascripts/encryption.js index 5cff94da6..f7574d5ae 100644 --- a/public/javascripts/encryption.js +++ b/public/javascripts/encryption.js @@ -23,10 +23,6 @@ const encryption = (function() { encryptedDataKey = settings.encrypted_data_key; }); - function setEncryptedDataKey(encDataKey) { - encryptedDataKey = encDataKey; - } - function setEncryptionSessionTimeout(encSessTimeout) { encryptionSessionTimeout = encSessTimeout; } @@ -34,7 +30,7 @@ const encryption = (function() { function ensureEncryptionIsAvailable(requireEncryption, modal) { const dfd = $.Deferred(); - if (requireEncryption && dataKey === null) { + if (requireEncryption && !isEncryptionAvailable()) { // if this is entry point then we need to show the app even before the note is loaded showAppIfHidden(); @@ -58,54 +54,6 @@ const encryption = (function() { return dfd.promise(); } - async function getDataKey(password) { - const passwordDerivedKey = await computeScrypt(password, passwordDerivedKeySalt); - - const dataKeyAes = getDataKeyAes(passwordDerivedKey); - - return decrypt(dataKeyAes, encryptedDataKey); - } - - function computeScrypt(password, salt) { - const normalizedPassword = password.normalize('NFKC'); - const passwordBuffer = new buffer.SlowBuffer(normalizedPassword); - const saltBuffer = new buffer.SlowBuffer(salt); - - // this settings take ~500ms on my laptop - const N = 16384, r = 8, p = 1; - // 32 byte key - AES 256 - const dkLen = 32; - - return new Promise((resolve, reject) => { - scrypt(passwordBuffer, saltBuffer, N, r, p, dkLen, (error, progress, key) => { - if (error) { - showError(error); - - reject(error); - } - else if (key) { - resolve(key); - } - }); - }); - } - - function decryptTreeItems() { - if (!isEncryptionAvailable()) { - return; - } - - for (const noteId of glob.allNoteIds) { - const note = treeUtils.getNodeByKey(noteId); - - if (note.data.encryption > 0) { - const title = decryptString(note.data.note_title); - - note.setTitle(title); - } - } - } - async function setupEncryptionSession() { const password = encryptionPasswordEl.val(); encryptionPasswordEl.val(""); @@ -122,6 +70,7 @@ const encryption = (function() { dialogEl.dialog("close"); + noteEditor.reload(); noteTree.reload(); if (encryptionDeferred !== null) { @@ -158,7 +107,7 @@ const encryption = (function() { } function isEncryptionAvailable() { - return dataKey !== null; + return protectedSessionId !== null; } function getDataAes() { @@ -167,10 +116,6 @@ const encryption = (function() { return new aesjs.ModeOfOperation.ctr(dataKey, new aesjs.Counter(5)); } - function getDataKeyAes(passwordDerivedKey) { - return new aesjs.ModeOfOperation.ctr(passwordDerivedKey, new aesjs.Counter(5)); - } - function encryptNoteIfNecessary(note) { if (note.detail.encryption === 0) { return note; @@ -307,17 +252,6 @@ const encryption = (function() { noteEditor.setNoteBackgroundIfEncrypted(note); } - function decryptNoteIfNecessary(note) { - if (note.detail.encryption > 0) { - decryptNote(note); - } - } - - function decryptNote(note) { - note.detail.note_title = decryptString(note.detail.note_title); - note.detail.note_text = decryptString(note.detail.note_text); - } - async function encryptSubTree(noteId) { await ensureEncryptionIsAvailable(true, true); @@ -433,10 +367,8 @@ const encryption = (function() { }, 5000); return { - setEncryptedDataKey, setEncryptionSessionTimeout, ensureEncryptionIsAvailable, - decryptTreeItems, resetEncryptionSession, isEncryptionAvailable, encryptNoteIfNecessary, @@ -444,7 +376,6 @@ const encryption = (function() { decryptString, encryptNoteAndSendToServer, decryptNoteAndSendToServer, - decryptNoteIfNecessary, encryptSubTree, decryptSubTree, getProtectedSessionId diff --git a/public/javascripts/note_editor.js b/public/javascripts/note_editor.js index 8f374a728..f365fe9f2 100644 --- a/public/javascripts/note_editor.js +++ b/public/javascripts/note_editor.js @@ -209,8 +209,6 @@ const noteEditor = (function() { encryptionPasswordEl.val(''); - encryption.decryptNoteIfNecessary(currentNote); - noteTitleEl.val(currentNote.detail.note_title); noteChangeDisabled = true; @@ -234,12 +232,6 @@ const noteEditor = (function() { async function loadNote(noteId) { const note = await $.get(baseApiUrl + 'notes/' + noteId); - if (note.detail.encryption > 0 && !encryption.isEncryptionAvailable()) { - return; - } - - encryption.decryptNoteIfNecessary(note); - return note; } diff --git a/public/javascripts/note_tree.js b/public/javascripts/note_tree.js index 019829f9e..81273c639 100644 --- a/public/javascripts/note_tree.js +++ b/public/javascripts/note_tree.js @@ -190,8 +190,6 @@ const noteTree = (function() { // this will also reload the note content await treeEl.fancytree('getTree').reload(treeResp.notes); - - encryption.decryptTreeItems(); } function loadTree() { diff --git a/routes/api/notes.js b/routes/api/notes.js index b6206ed18..c4ba3fedb 100644 --- a/routes/api/notes.js +++ b/routes/api/notes.js @@ -7,6 +7,8 @@ const sql = require('../../services/sql'); const options = require('../../services/options'); const utils = require('../../services/utils'); const notes = require('../../services/notes'); +const protected_session = require('../../services/protected_session'); +const data_encryption = require('../../services/data_encryption'); router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { let noteId = req.params.noteId; @@ -20,6 +22,13 @@ router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { detail = sql.getSingleResult("select * from notes where note_id = ?", [noteId]); } + if (detail.encryption > 0) { + const dataKey = protected_session.getDataKey(req); + + detail.note_title = data_encryption.decrypt(dataKey, detail.note_title); + detail.note_text = data_encryption.decrypt(dataKey, detail.note_text); + } + res.send({ detail: detail, images: await sql.getResults("select * from images where note_id = ? order by note_offset", [noteId]),