From c36390dbc059ea3a08fd0431dc47f1eee6f8a8c6 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Wed, 8 Mar 2017 18:15:56 -0600 Subject: [PATCH 1/6] ivs wip --- app/assets/javascripts/app/services/helpers/crypto.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/app/services/helpers/crypto.js b/app/assets/javascripts/app/services/helpers/crypto.js index ab09b41e8..f2dbb675b 100644 --- a/app/assets/javascripts/app/services/helpers/crypto.js +++ b/app/assets/javascripts/app/services/helpers/crypto.js @@ -30,9 +30,9 @@ class SNCrypto { } } - decryptText(encrypted_content, key) { + decryptText(encrypted_content, key, iv, auth) { var keyData = CryptoJS.enc.Hex.parse(key); - var ivData = CryptoJS.enc.Hex.parse(""); + var ivData = CryptoJS.enc.Hex.parse(iv || ""); var decrypted = CryptoJS.AES.decrypt(encrypted_content, keyData, { iv: ivData, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } From 2a8bc1a0b4b36f6a4c6cbb39bad84b63038f69a8 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Thu, 9 Mar 2017 17:39:54 -0600 Subject: [PATCH 2/6] 002 encryption type with ivs and auth hash --- .../app/frontend/models/local/itemParams.js | 8 +- .../javascripts/app/services/authManager.js | 12 +++ .../services/directives/views/accountMenu.js | 17 ++- .../app/services/extensionManager.js | 10 +- .../app/services/helpers/crypto.js | 45 +++++--- .../app/services/helpers/encryptionHelper.js | 100 ++++++++++++++---- .../javascripts/app/services/syncManager.js | 4 +- 7 files changed, 140 insertions(+), 56 deletions(-) diff --git a/app/assets/javascripts/app/frontend/models/local/itemParams.js b/app/assets/javascripts/app/frontend/models/local/itemParams.js index 396a51bd1..b1f571fc9 100644 --- a/app/assets/javascripts/app/frontend/models/local/itemParams.js +++ b/app/assets/javascripts/app/frontend/models/local/itemParams.js @@ -1,8 +1,8 @@ class ItemParams { - constructor(item, ek) { + constructor(item, keys) { this.item = item; - this.ek = ek; + this.keys = keys; } paramsForExportFile() { @@ -32,8 +32,8 @@ class ItemParams { var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at}; - if(this.ek) { - EncryptionHelper.encryptItem(itemCopy, this.ek); + if(this.keys) { + EncryptionHelper.encryptItem(itemCopy, this.keys, "002"); params.content = itemCopy.content; params.enc_item_key = itemCopy.enc_item_key; params.auth_hash = itemCopy.auth_hash; diff --git a/app/assets/javascripts/app/services/authManager.js b/app/assets/javascripts/app/services/authManager.js index 96f001166..120e8ef6a 100644 --- a/app/assets/javascripts/app/services/authManager.js +++ b/app/assets/javascripts/app/services/authManager.js @@ -32,6 +32,18 @@ angular.module('app.frontend') return JSON.parse(localStorage.getItem("auth_params")); } + this.keys = function() { + var keys = {mk: localStorage.getItem("mk")}; + if(!localStorage.getItem("encryptionKey")) { + keys = _.merge(keys, Neeto.crypto.generateKeysFromMasterKey(keys.mk)); + localStorage.setItem("encryptionKey", keys.encryptionKey); + localStorage.setItem("authKey", keys.authKey); + } else { + keys = _.merge(keys, {encryptionKey: localStorage.getItem("encryptionKey"), authKey: localStorage.getItem("authKey")}); + } + return keys; + } + this.getAuthParamsForEmail = function(url, email, callback) { var requestUrl = url + "/auth/params"; httpManager.getAbsolute(requestUrl, {email: email}, function(response){ diff --git a/app/assets/javascripts/app/services/directives/views/accountMenu.js b/app/assets/javascripts/app/services/directives/views/accountMenu.js index 7fd9ca4c1..03f63e9cd 100644 --- a/app/assets/javascripts/app/services/directives/views/accountMenu.js +++ b/app/assets/javascripts/app/services/directives/views/accountMenu.js @@ -16,7 +16,7 @@ class AccountMenu { $scope.syncStatus = syncManager.syncStatus; $scope.encryptionKey = function() { - return syncManager.masterKey; + return authManager.keys().mk; } $scope.serverPassword = function() { @@ -223,9 +223,8 @@ class AccountMenu { if(data.auth_params) { Neeto.crypto.computeEncryptionKeysForUser(_.merge({password: password}, data.auth_params), function(keys){ - var mk = keys.mk; try { - EncryptionHelper.decryptMultipleItems(data.items, mk, true); + EncryptionHelper.decryptMultipleItems(data.items, keys, true); // delete items enc_item_key since the user's actually key will do the encrypting once its passed off data.items.forEach(function(item){ item.enc_item_key = null; @@ -319,26 +318,26 @@ class AccountMenu { $scope.downloadDataArchive = function() { // download in Standard File format - var ek = $scope.archiveFormData.encrypted ? syncManager.masterKey : null; - var data = $scope.itemsData(ek); + var keys = $scope.archiveFormData.encrypted ? authManager.keys() : null; + var data = $scope.itemsData(keys); downloadData(data, `SN Archive - ${new Date()}.txt`); // download as zipped plain text files - if(!ek) { + if(!keys) { var notes = modelManager.allItemsMatchingTypes(["Note"]); downloadZippedNotes(notes); } } - $scope.itemsData = function(ek) { + $scope.itemsData = function(keys) { var items = _.map(modelManager.allItemsMatchingTypes(["Tag", "Note"]), function(item){ - var itemParams = new ItemParams(item, ek); + var itemParams = new ItemParams(item, keys); return itemParams.paramsForExportFile(); }.bind(this)); var data = {items: items} - if(ek) { + if(keys) { // auth params are only needed when encrypted with a standard file key data["auth_params"] = authManager.getAuthParams(); } diff --git a/app/assets/javascripts/app/services/extensionManager.js b/app/assets/javascripts/app/services/extensionManager.js index 4be7548b3..6bc189217 100644 --- a/app/assets/javascripts/app/services/extensionManager.js +++ b/app/assets/javascripts/app/services/extensionManager.js @@ -153,7 +153,7 @@ class ExtensionManager { this.httpManager.getAbsolute(action.url, {}, function(response){ action.error = false; var items = response.items || [response.item]; - EncryptionHelper.decryptMultipleItems(items, localStorage.getItem("mk")); + EncryptionHelper.decryptMultipleItems(items, this.authManager.keys()); items = this.modelManager.mapResponseItemsToLocalModels(items); for(var item of items) { item.setDirty(true); @@ -172,7 +172,7 @@ class ExtensionManager { this.httpManager.getAbsolute(action.url, {}, function(response){ action.error = false; - EncryptionHelper.decryptItem(response.item, localStorage.getItem("mk")); + EncryptionHelper.decryptItem(response.item, this.authManager.keys()); var item = this.modelManager.createItem(response.item); customCallback({item: item}); @@ -301,11 +301,11 @@ class ExtensionManager { } outgoingParamsForItem(item, extension) { - var ek = this.syncManager.masterKey; + var keys = this.authManager.keys(); if(!this.extensionUsesEncryptedData(extension)) { - ek = null; + keys = null; } - var itemParams = new ItemParams(item, ek); + var itemParams = new ItemParams(item, keys); return itemParams.paramsForExtension(); } diff --git a/app/assets/javascripts/app/services/helpers/crypto.js b/app/assets/javascripts/app/services/helpers/crypto.js index f2dbb675b..682a1c282 100644 --- a/app/assets/javascripts/app/services/helpers/crypto.js +++ b/app/assets/javascripts/app/services/helpers/crypto.js @@ -1,7 +1,7 @@ class SNCrypto { - generateRandomKey() { - return CryptoJS.lib.WordArray.random(512/8).toString(); + generateRandomKey(bits) { + return CryptoJS.lib.WordArray.random(bits/8).toString(); } generateUUID() { @@ -30,24 +30,30 @@ class SNCrypto { } } - decryptText(encrypted_content, key, iv, auth) { - var keyData = CryptoJS.enc.Hex.parse(key); + decryptText({ciphertextToAuth, contentCiphertext, encryptionKey, iv, authHash, authKey} = {}) { + if(authHash) { + var localAuthHash = Neeto.crypto.hmac256(ciphertextToAuth, authKey); + if(authHash !== localAuthHash) { + console.error("Auth hash does not match, returning null."); + return null; + } + } + var keyData = CryptoJS.enc.Hex.parse(encryptionKey); var ivData = CryptoJS.enc.Hex.parse(iv || ""); - var decrypted = CryptoJS.AES.decrypt(encrypted_content, keyData, { iv: ivData, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); + var decrypted = CryptoJS.AES.decrypt(contentCiphertext, keyData, { iv: ivData, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypted.toString(CryptoJS.enc.Utf8); } - encryptText(text, key) { + encryptText(text, key, iv) { var keyData = CryptoJS.enc.Hex.parse(key); - // items are encrypted with random keys; no two items are encrypted with same key, thus IV is not needed - var ivData = CryptoJS.enc.Hex.parse(""); + var ivData = CryptoJS.enc.Hex.parse(iv || ""); var encrypted = CryptoJS.AES.encrypt(text, keyData, { iv: ivData, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } generateRandomEncryptionKey() { - var salt = Neeto.crypto.generateRandomKey(); - var passphrase = Neeto.crypto.generateRandomKey(); + var salt = Neeto.crypto.generateRandomKey(512); + var passphrase = Neeto.crypto.generateRandomKey(512); return CryptoJS.PBKDF2(passphrase, salt, { keySize: 512/32 }).toString(); } @@ -83,28 +89,37 @@ class SNCrypto { return CryptoJS.HmacSHA256(messageData, keyData).toString(); } + generateKeysFromMasterKey(mk) { + var encryptionKey = Neeto.crypto.hmac256(mk, "e"); + var authKey = Neeto.crypto.hmac256(mk, "a"); + return {encryptionKey: encryptionKey, authKey: authKey}; + } + computeEncryptionKeysForUser({password, pw_salt, pw_func, pw_alg, pw_cost, pw_key_size} = {}, callback) { this.generateSymmetricKeyPair({password: password, pw_salt: pw_salt, pw_func: pw_func, pw_alg: pw_alg, pw_cost: pw_cost, pw_key_size: pw_key_size}, function(keys){ var pw = keys[0]; var mk = keys[1]; - callback({pw: pw, mk: mk}); - }); + callback(_.merge({pw: pw, mk: mk}, this.generateKeysFromMasterKey(mk))); + }.bind(this)); } generateInitialEncryptionKeysForUser({email, password} = {}, callback) { var defaults = this.defaultPasswordGenerationParams(); var {pw_func, pw_alg, pw_key_size, pw_cost} = defaults; - var pw_nonce = this.generateRandomKey(); + var pw_nonce = this.generateRandomKey(512); var pw_salt = this.sha1(email + "SN" + pw_nonce); _.merge(defaults, {pw_salt: pw_salt, pw_nonce: pw_nonce}) this.generateSymmetricKeyPair(_.merge({email: email, password: password, pw_salt: pw_salt}, defaults), function(keys){ var pw = keys[0]; var mk = keys[1]; - callback({pw: pw, mk: mk}, defaults); - }); + var encryptionKey = Neeto.crypto.hmac256(mk, "e"); + var authKey = Neeto.crypto.hmac256(mk, "a"); + + callback(_.merge({pw: pw, mk: mk}, this.generateKeysFromMasterKey(mk)), defaults); + }.bind(this)); } } diff --git a/app/assets/javascripts/app/services/helpers/encryptionHelper.js b/app/assets/javascripts/app/services/helpers/encryptionHelper.js index e0e171af5..58838c240 100644 --- a/app/assets/javascripts/app/services/helpers/encryptionHelper.js +++ b/app/assets/javascripts/app/services/helpers/encryptionHelper.js @@ -1,35 +1,93 @@ class EncryptionHelper { - static encryptItem(item, key) { - var item_key = Neeto.crypto.generateRandomEncryptionKey(); - item.enc_item_key = Neeto.crypto.encryptText(item_key, key); + static _private_encryptString(string, encryptionKey, authKey, version) { + var fullCiphertext, contentCiphertext; + if(version === "001") { + contentCiphertext = Neeto.crypto.encryptText(string, encryptionKey, null); + fullCiphertext = version + contentCiphertext; + } else { + var iv = Neeto.crypto.generateRandomKey(128); + contentCiphertext = Neeto.crypto.encryptText(string, encryptionKey, iv); + var ciphertextToAuth = [version, iv, contentCiphertext].join(":"); + var authHash = Neeto.crypto.hmac256(ciphertextToAuth, authKey); + fullCiphertext = [version, authHash, iv, contentCiphertext].join(":"); + } - var ek = Neeto.crypto.firstHalfOfKey(item_key); - var ak = Neeto.crypto.secondHalfOfKey(item_key); - var encryptedContent = "001" + Neeto.crypto.encryptText(JSON.stringify(item.createContentJSONFromProperties()), ek); - var authHash = Neeto.crypto.hmac256(encryptedContent, ak); - - item.content = encryptedContent; - item.auth_hash = authHash; + return fullCiphertext; } - static decryptItem(item, key) { - var item_key = Neeto.crypto.decryptText(item.enc_item_key, key); + static encryptItem(item, keys, version) { + // encrypt item key + var item_key = Neeto.crypto.generateRandomEncryptionKey(); + if(version === "001") { + // legacy + item.enc_item_key = Neeto.crypto.encryptText(item_key, keys.mk, null); + } else { + item.enc_item_key = this._private_encryptString(item_key, keys.encryptionKey, keys.authKey, version); + } + // encrypt content var ek = Neeto.crypto.firstHalfOfKey(item_key); var ak = Neeto.crypto.secondHalfOfKey(item_key); - var authHash = Neeto.crypto.hmac256(item.content, ak); - if(authHash !== item.auth_hash || !item.auth_hash) { - console.log("Authentication hash does not match.") + var ciphertext = this._private_encryptString(JSON.stringify(item.createContentJSONFromProperties()), ek, ak, version); + if(version === "001") { + var authHash = Neeto.crypto.hmac256(ciphertext, ak); + item.auth_hash = authHash; + } + + item.content = ciphertext; + } + + static encryptionComponentsFromString(string, baseKey, encryptionKey, authKey) { + var encryptionVersion = string.substring(0, 3); + if(encryptionVersion === "001") { + return { + contentCiphertext: string.substring(3, string.length), + encryptionVersion: encryptionVersion, + ciphertextToAuth: string, + iv: null, + authHash: null, + encryptionKey: baseKey + } + } else { + let components = string.split(":"); + return { + encryptionVersion: components[0], + authHash: components[1], + iv: components[2], + contentCiphertext: components[3], + ciphertextToAuth: [components[0], components[2], components[3]].join(":"), + encryptionKey: encryptionKey, + authKey: authKey + } + } + } + + static decryptItem(item, keys) { + // decrypt encrypted key + var encryptedItemKey = item.enc_item_key; + if(!encryptedItemKey.startsWith("002")) { + // legacy encryption type, has no prefix + encryptedItemKey = "001" + encryptedItemKey; + } + var keyParams = this.encryptionComponentsFromString(encryptedItemKey, keys.mk, keys.encryptionKey, keys.authKey); + var item_key = Neeto.crypto.decryptText(keyParams); + + if(!item_key) { return; } - var content = Neeto.crypto.decryptText(item.content.substring(3, item.content.length), ek); + // decrypt content + var ek = Neeto.crypto.firstHalfOfKey(item_key); + var ak = Neeto.crypto.secondHalfOfKey(item_key); + var itemParams = this.encryptionComponentsFromString(item.content, ek, ek, ak); + var content = Neeto.crypto.decryptText(itemParams); + item.content = content; } - static decryptMultipleItems(items, key, throws) { - for (var item of items) { + static decryptMultipleItems(items, keys, throws) { + for (var item of items) { if(item.deleted == true) { continue; } @@ -37,9 +95,9 @@ class EncryptionHelper { var isString = typeof item.content === 'string' || item.content instanceof String; if(isString) { try { - if(item.content.substring(0, 3) == "001" && item.enc_item_key) { + if((item.content.startsWith("001") || item.content.startsWith("002")) && item.enc_item_key) { // is encrypted - this.decryptItem(item, key); + this.decryptItem(item, keys); } else { // is base64 encoded item.content = Neeto.crypto.base64Decode(item.content.substring(3, item.content.length)) @@ -52,7 +110,7 @@ class EncryptionHelper { continue; } } - } + } } } diff --git a/app/assets/javascripts/app/services/syncManager.js b/app/assets/javascripts/app/services/syncManager.js index 54d4c18d8..c08668210 100644 --- a/app/assets/javascripts/app/services/syncManager.js +++ b/app/assets/javascripts/app/services/syncManager.js @@ -164,7 +164,7 @@ class SyncManager { var params = {}; params.limit = 150; params.items = _.map(subItems, function(item){ - var itemParams = new ItemParams(item, localStorage.getItem("mk")); + var itemParams = new ItemParams(item, this.authManager.keys()); itemParams.additionalFields = options.additionalFields; return itemParams.paramsForSync(); }.bind(this)); @@ -252,7 +252,7 @@ class SyncManager { } handleItemsResponse(responseItems, omitFields) { - EncryptionHelper.decryptMultipleItems(responseItems, localStorage.getItem("mk")); + EncryptionHelper.decryptMultipleItems(responseItems, this.authManager.keys()); return this.modelManager.mapResponseItemsToLocalModelsOmittingFields(responseItems, omitFields); } From 23611c31ae7460c949cff161db9de75b4e1b909a Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Thu, 9 Mar 2017 18:01:57 -0600 Subject: [PATCH 3/6] clear auth hash depending on version --- .../app/frontend/models/local/itemParams.js | 9 +++-- .../app/services/helpers/crypto.js | 7 +++- .../app/services/helpers/encryptionHelper.js | 15 +++++--- .../javascripts/app/services/syncManager.js | 34 +++++++++++++------ 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/app/assets/javascripts/app/frontend/models/local/itemParams.js b/app/assets/javascripts/app/frontend/models/local/itemParams.js index b1f571fc9..07582fc42 100644 --- a/app/assets/javascripts/app/frontend/models/local/itemParams.js +++ b/app/assets/javascripts/app/frontend/models/local/itemParams.js @@ -33,10 +33,15 @@ class ItemParams { var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at}; if(this.keys) { - EncryptionHelper.encryptItem(itemCopy, this.keys, "002"); + let encryptionVersion = "001"; + EncryptionHelper.encryptItem(itemCopy, this.keys, encryptionVersion); params.content = itemCopy.content; params.enc_item_key = itemCopy.enc_item_key; - params.auth_hash = itemCopy.auth_hash; + if(encryptionVersion === "001") { + params.auth_hash = itemCopy.auth_hash; + } else { + params.auth_hash = null; + } } else { params.content = this.forExportFile ? itemCopy.createContentJSONFromProperties() : "000" + Neeto.crypto.base64(JSON.stringify(itemCopy.createContentJSONFromProperties())); diff --git a/app/assets/javascripts/app/services/helpers/crypto.js b/app/assets/javascripts/app/services/helpers/crypto.js index 682a1c282..3607d9054 100644 --- a/app/assets/javascripts/app/services/helpers/crypto.js +++ b/app/assets/javascripts/app/services/helpers/crypto.js @@ -30,7 +30,12 @@ class SNCrypto { } } - decryptText({ciphertextToAuth, contentCiphertext, encryptionKey, iv, authHash, authKey} = {}) { + decryptText({ciphertextToAuth, contentCiphertext, encryptionKey, iv, authHash, authKey} = {}, requiresAuth) { + if(requiresAuth && !authHash) { + console.error("Auth hash is required."); + return; + } + if(authHash) { var localAuthHash = Neeto.crypto.hmac256(ciphertextToAuth, authKey); if(authHash !== localAuthHash) { diff --git a/app/assets/javascripts/app/services/helpers/encryptionHelper.js b/app/assets/javascripts/app/services/helpers/encryptionHelper.js index 58838c240..24de8ec7a 100644 --- a/app/assets/javascripts/app/services/helpers/encryptionHelper.js +++ b/app/assets/javascripts/app/services/helpers/encryptionHelper.js @@ -47,7 +47,8 @@ class EncryptionHelper { ciphertextToAuth: string, iv: null, authHash: null, - encryptionKey: baseKey + encryptionKey: baseKey, + authKey: authKey } } else { let components = string.split(":"); @@ -66,12 +67,14 @@ class EncryptionHelper { static decryptItem(item, keys) { // decrypt encrypted key var encryptedItemKey = item.enc_item_key; - if(!encryptedItemKey.startsWith("002")) { + var requiresAuth = true; + if(encryptedItemKey.startsWith("002") === false) { // legacy encryption type, has no prefix encryptedItemKey = "001" + encryptedItemKey; + requiresAuth = false; } var keyParams = this.encryptionComponentsFromString(encryptedItemKey, keys.mk, keys.encryptionKey, keys.authKey); - var item_key = Neeto.crypto.decryptText(keyParams); + var item_key = Neeto.crypto.decryptText(keyParams, requiresAuth); if(!item_key) { return; @@ -81,8 +84,10 @@ class EncryptionHelper { var ek = Neeto.crypto.firstHalfOfKey(item_key); var ak = Neeto.crypto.secondHalfOfKey(item_key); var itemParams = this.encryptionComponentsFromString(item.content, ek, ek, ak); - var content = Neeto.crypto.decryptText(itemParams); - + if(!itemParams.authHash) { + itemParams.authHash = item.auth_hash; + } + var content = Neeto.crypto.decryptText(itemParams, true); item.content = content; } diff --git a/app/assets/javascripts/app/services/syncManager.js b/app/assets/javascripts/app/services/syncManager.js index c08668210..25d4e00f1 100644 --- a/app/assets/javascripts/app/services/syncManager.js +++ b/app/assets/javascripts/app/services/syncManager.js @@ -172,7 +172,7 @@ class SyncManager { params.sync_token = this.syncToken; params.cursor_token = this.cursorToken; - this.httpManager.postAbsolute(this.syncURL, params, function(response){ + var onSyncSuccess = function(response) { this.modelManager.clearDirtyItems(subItems); this.syncStatus.error = null; @@ -209,19 +209,33 @@ class SyncManager { } else { this.callQueuedCallbacksAndCurrent(callback, response); } + }.bind(this); - }.bind(this), function(response){ - console.log("Sync error: ", response); - var error = response ? response.error : {message: "Could not connect to server."}; + try { + this.httpManager.postAbsolute(this.syncURL, params, function(response){ - this.syncStatus.syncOpInProgress = false; - this.syncStatus.error = error; - this.writeItemsToLocalStorage(allDirtyItems, false, null); + try { + onSyncSuccess(response); + } catch(e) { + console.log("Caught sync success exception:", e); + } - this.$rootScope.$broadcast("sync:error", error); + }.bind(this), function(response){ + console.log("Sync error: ", response); + var error = response ? response.error : {message: "Could not connect to server."}; - this.callQueuedCallbacksAndCurrent(callback, {error: "Sync error"}); - }.bind(this)); + this.syncStatus.syncOpInProgress = false; + this.syncStatus.error = error; + this.writeItemsToLocalStorage(allDirtyItems, false, null); + + this.$rootScope.$broadcast("sync:error", error); + + this.callQueuedCallbacksAndCurrent(callback, {error: "Sync error"}); + }.bind(this)); + } + catch(e) { + console.log("Sync exception caught:", e); + } } handleUnsavedItemsResponse(unsaved) { From bc0e76c7dae9b0a15253f463298a37bc10a29dda Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Thu, 9 Mar 2017 20:07:28 -0600 Subject: [PATCH 4/6] fixes hex encoding issue --- app/assets/javascripts/app/app.frontend.js | 2 +- .../app/frontend/models/local/itemParams.js | 2 +- app/assets/javascripts/app/services/authManager.js | 4 ++-- app/assets/javascripts/app/services/helpers/crypto.js | 11 +++++------ 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/app/app.frontend.js b/app/assets/javascripts/app/app.frontend.js index b4d657e94..4511bf882 100644 --- a/app/assets/javascripts/app/app.frontend.js +++ b/app/assets/javascripts/app/app.frontend.js @@ -1,6 +1,6 @@ 'use strict'; -var Neeto = Neeto || {}; +var Neeto = window.Neeto = Neeto || {}; var SN = SN || {}; // detect IE8 and above, and edge. diff --git a/app/assets/javascripts/app/frontend/models/local/itemParams.js b/app/assets/javascripts/app/frontend/models/local/itemParams.js index 07582fc42..63a3fcb68 100644 --- a/app/assets/javascripts/app/frontend/models/local/itemParams.js +++ b/app/assets/javascripts/app/frontend/models/local/itemParams.js @@ -33,7 +33,7 @@ class ItemParams { var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at}; if(this.keys) { - let encryptionVersion = "001"; + let encryptionVersion = "002"; EncryptionHelper.encryptItem(itemCopy, this.keys, encryptionVersion); params.content = itemCopy.content; params.enc_item_key = itemCopy.enc_item_key; diff --git a/app/assets/javascripts/app/services/authManager.js b/app/assets/javascripts/app/services/authManager.js index 120e8ef6a..c2615d1b3 100644 --- a/app/assets/javascripts/app/services/authManager.js +++ b/app/assets/javascripts/app/services/authManager.js @@ -35,11 +35,11 @@ angular.module('app.frontend') this.keys = function() { var keys = {mk: localStorage.getItem("mk")}; if(!localStorage.getItem("encryptionKey")) { - keys = _.merge(keys, Neeto.crypto.generateKeysFromMasterKey(keys.mk)); + _.merge(keys, Neeto.crypto.generateKeysFromMasterKey(keys.mk)); localStorage.setItem("encryptionKey", keys.encryptionKey); localStorage.setItem("authKey", keys.authKey); } else { - keys = _.merge(keys, {encryptionKey: localStorage.getItem("encryptionKey"), authKey: localStorage.getItem("authKey")}); + _.merge(keys, {encryptionKey: localStorage.getItem("encryptionKey"), authKey: localStorage.getItem("authKey")}); } return keys; } diff --git a/app/assets/javascripts/app/services/helpers/crypto.js b/app/assets/javascripts/app/services/helpers/crypto.js index 3607d9054..6991851bd 100644 --- a/app/assets/javascripts/app/services/helpers/crypto.js +++ b/app/assets/javascripts/app/services/helpers/crypto.js @@ -91,12 +91,14 @@ class SNCrypto { hmac256(message, key) { var keyData = CryptoJS.enc.Hex.parse(key); var messageData = CryptoJS.enc.Utf8.parse(message); - return CryptoJS.HmacSHA256(messageData, keyData).toString(); + var result = CryptoJS.HmacSHA256(messageData, keyData).toString(); + console.log("HMAC of:", message, "with key:", key, "keyData", keyData, "is:", result); + return result; } generateKeysFromMasterKey(mk) { - var encryptionKey = Neeto.crypto.hmac256(mk, "e"); - var authKey = Neeto.crypto.hmac256(mk, "a"); + var encryptionKey = Neeto.crypto.hmac256(mk, CryptoJS.enc.Utf8.parse("e").toString(CryptoJS.enc.Hex)); + var authKey = Neeto.crypto.hmac256(mk, CryptoJS.enc.Utf8.parse("a").toString(CryptoJS.enc.Hex)); return {encryptionKey: encryptionKey, authKey: authKey}; } @@ -120,9 +122,6 @@ class SNCrypto { var pw = keys[0]; var mk = keys[1]; - var encryptionKey = Neeto.crypto.hmac256(mk, "e"); - var authKey = Neeto.crypto.hmac256(mk, "a"); - callback(_.merge({pw: pw, mk: mk}, this.generateKeysFromMasterKey(mk)), defaults); }.bind(this)); } From c2654756ef928246c2728aa776168fbb92edf67d Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Thu, 9 Mar 2017 20:07:46 -0600 Subject: [PATCH 5/6] remove log --- app/assets/javascripts/app/services/helpers/crypto.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/assets/javascripts/app/services/helpers/crypto.js b/app/assets/javascripts/app/services/helpers/crypto.js index 6991851bd..42228ee75 100644 --- a/app/assets/javascripts/app/services/helpers/crypto.js +++ b/app/assets/javascripts/app/services/helpers/crypto.js @@ -71,12 +71,10 @@ class SNCrypto { } base64(text) { - // return CryptoJS.enc.Utf8.parse(text).toString(CryptoJS.enc.Base64) return window.btoa(text); } base64Decode(base64String) { - // return CryptoJS.enc.Base64.parse(base64String).toString(CryptoJS.enc.Utf8) return window.atob(base64String); } @@ -92,7 +90,6 @@ class SNCrypto { var keyData = CryptoJS.enc.Hex.parse(key); var messageData = CryptoJS.enc.Utf8.parse(message); var result = CryptoJS.HmacSHA256(messageData, keyData).toString(); - console.log("HMAC of:", message, "with key:", key, "keyData", keyData, "is:", result); return result; } From 70c23973b2349c78b149d76fc6d302b2d3005483 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Sat, 18 Mar 2017 15:50:19 -0500 Subject: [PATCH 6/6] merged master --- app/assets/javascripts/app/frontend/models/local/itemParams.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/app/frontend/models/local/itemParams.js b/app/assets/javascripts/app/frontend/models/local/itemParams.js index 63a3fcb68..22a15ffcd 100644 --- a/app/assets/javascripts/app/frontend/models/local/itemParams.js +++ b/app/assets/javascripts/app/frontend/models/local/itemParams.js @@ -26,6 +26,8 @@ class ItemParams { } __params() { + let encryptionVersion = "001"; + var itemCopy = _.cloneDeep(this.item); console.assert(!this.item.dummy, "Item is dummy, should not have gotten here.", this.item.dummy) @@ -33,7 +35,6 @@ class ItemParams { var params = {uuid: this.item.uuid, content_type: this.item.content_type, deleted: this.item.deleted, created_at: this.item.created_at}; if(this.keys) { - let encryptionVersion = "002"; EncryptionHelper.encryptItem(itemCopy, this.keys, encryptionVersion); params.content = itemCopy.content; params.enc_item_key = itemCopy.enc_item_key;