auth hash

This commit is contained in:
Mo Bitar
2016-12-18 21:11:55 -06:00
parent 3794d0496c
commit 47b986f15f
7 changed files with 165 additions and 168 deletions

View File

@@ -6,7 +6,7 @@ class BaseCtrl {
// data.password = new_keys.pw;
// data.password_confirmation = new_keys.pw;
// $auth.updatePassword(data);
// apiController.setGk(new_keys.gk);
// apiController.setMk(new_keys.mk);
// }
// var note = new Note();

View File

@@ -82,7 +82,7 @@ class Item {
}
encryptionEnabled() {
return this.loc_eek;
return this.enc_item_key;
}
presentationURL() {

View File

@@ -6,7 +6,6 @@ angular.module('app.frontend')
abstract: true,
})
// Homepage
.state('home', {
url: '/',
parent: 'base',
@@ -18,39 +17,6 @@ angular.module('app.frontend')
}
})
// Auth routes
// .state('auth', {
// abstract: true,
// url: '/auth',
// parent: 'base',
// views: {
// 'content@' : {
// templateUrl: 'frontend/auth/wrapper.html',
// }
// }
// })
// .state('auth.login', {
// url: '/login',
// templateUrl: 'frontend/auth/login.html',
// })
// .state('auth.forgot', {
// url: '/forgot',
// templateUrl: 'frontend/auth/forgot.html',
// })
// .state('auth.reset', {
// url: '/reset?reset_password_token&email',
// templateUrl: 'frontend/auth/reset.html',
// controller: function($rootScope, $stateParams) {
// $rootScope.resetData = {reset_password_token: $stateParams.reset_password_token, email: $stateParams.email};
//
// // Clear reset_password_token on change state
// $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options) {
// $rootScope.reset_password_token = null;
// });
// },
// })
// 404 Error
.state('404', {
parent: 'base',

View File

@@ -78,6 +78,7 @@ angular.module('app.frontend')
callback(user, items);
}.bind(this))
.catch(function(error){
console.log("Error getting current user", error);
callback(null);
})
}
@@ -85,7 +86,7 @@ angular.module('app.frontend')
this.login = function(email, password, callback) {
this.getAuthParamsForEmail(email, function(authParams){
Neeto.crypto.computeEncryptionKeysForUser(_.merge({email: email, password: password}, authParams), function(keys){
this.setGk(keys.gk);
this.setMk(keys.mk);
var request = Restangular.one("auth/sign_in");
request.user = {password: keys.pw, email: email};
request.post().then(function(response){
@@ -98,8 +99,8 @@ angular.module('app.frontend')
this.register = function(email, password, callback) {
Neeto.crypto.generateInitialEncryptionKeysForUser({password: password, email: email}, function(keys){
this.setGk(keys.gk);
keys.gk = null;
this.setMk(keys.mk);
keys.mk = null;
var request = Restangular.one("auth");
request.user = _.merge({password: keys.pw, email: email}, keys);
request.post().then(function(response){
@@ -123,10 +124,10 @@ angular.module('app.frontend')
this._performPasswordChange(currentKeys, newKeys, function(response){
if(response && !response.errors) {
// this.showNewPasswordForm = false;
// reencrypt data with new gk
this.reencryptAllItemsAndSave(user, newKeys.gk, currentKeys.gk, function(success){
// reencrypt data with new mk
this.reencryptAllItemsAndSave(user, newKeys.mk, currentKeys.mk, function(success){
if(success) {
this.setGk(newKeys.gk);
this.setMk(newKeys.mk);
alert("Your password has been changed and your data re-encrypted.");
} else {
// rollback password
@@ -258,14 +259,16 @@ angular.module('app.frontend')
})
if(encrypted) {
this.encryptSingleItem(itemCopy, this.retrieveGk());
this.encryptSingleItem(itemCopy, this.retrieveMk());
params.content = itemCopy.content;
params.loc_eek = itemCopy.loc_eek;
params.enc_item_key = itemCopy.enc_item_key;
params.auth_hash = itemCopy.auth_hash;
}
else {
params.content = forExportFile ? itemCopy.content : JSON.stringify(itemCopy.content);
if(!forExportFile) {
params.loc_eek = null;
params.enc_item_key = null;
params.auth_hash = null;
}
}
@@ -450,87 +453,104 @@ angular.module('app.frontend')
Encrpytion
*/
this.retrieveGk = function() {
if(!this.gk) {
this.gk = localStorage.getItem("gk");
this.retrieveMk = function() {
if(!this.mk) {
this.mk = localStorage.getItem("mk");
}
return this.gk;
return this.mk;
}
this.setGk = function(gk) {
localStorage.setItem('gk', gk);
this.setMk = function(mk) {
localStorage.setItem('mk', mk);
}
this.signout = function() {
localStorage.removeItem("jwt");
localStorage.removeItem("gk");
localStorage.removeItem("mk");
}
this.encryptSingleItem = function(item, key) {
var ek = null;
if(item.loc_eek) {
ek = Neeto.crypto.decryptText(item.loc_eek, key);
this.encryptSingleItem = function(item, masterKey) {
var item_key = null;
if(item.enc_item_key) {
item_key = Neeto.crypto.decryptText(item.enc_item_key, masterKey);
} else {
ek = Neeto.crypto.generateRandomEncryptionKey();
item.loc_eek = Neeto.crypto.encryptText(ek, key);
item_key = Neeto.crypto.generateRandomEncryptionKey();
item.enc_item_key = Neeto.crypto.encryptText(item_key, masterKey);
}
item.content = Neeto.crypto.encryptText(JSON.stringify(item.content), ek);
var ek = Neeto.crypto.firstHalfOfKey(item_key);
var ak = Neeto.crypto.secondHalfOfKey(item_key);
var encryptedContent = Neeto.crypto.encryptText(JSON.stringify(item.content), ek);
var authHash = Neeto.crypto.hmac256(encryptedContent, ak);
item.content = encryptedContent;
item.auth_hash = authHash;
item.local_encryption_scheme = "1.0";
console.log("Encrypting item. itemKey:", item_key, "authHash:", item.auth_hash);
}
this.encryptItems = function(items, key) {
this.encryptItems = function(items, masterKey) {
items.forEach(function(item){
this.encryptSingleItem(item, key);
this.encryptSingleItem(item, masterKey);
}.bind(this));
}
this.encryptSingleItemWithLocalKey = function(item) {
this.encryptSingleItem(item, this.retrieveGk());
this.encryptSingleItem(item, this.retrieveMk());
}
this.encryptItemsWithLocalKey = function(items) {
this.encryptItems(items, this.retrieveGk());
this.encryptItems(items, this.retrieveMk());
}
this.encryptNonPublicItemsWithLocalKey = function(items) {
var nonpublic = items.filter(function(item){
return !item.isPublic() && !item.pending_share;
})
this.encryptItems(nonpublic, this.retrieveGk());
this.encryptItems(nonpublic, this.retrieveMk());
}
this.decryptSingleItemWithLocalKey = function(item) {
this.decryptSingleItem(item, this.retrieveGk());
this.decryptSingleItem(item, this.retrieveMk());
}
this.decryptSingleItem = function(item, key) {
var ek = Neeto.crypto.decryptText(item.loc_eek || item.local_eek, key);
this.decryptSingleItem = function(item, masterKey) {
var item_key = Neeto.crypto.decryptText(item.enc_item_key, masterKey);
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.")
return;
}
var content = Neeto.crypto.decryptText(item.content, ek);
// console.log("decrypted contnet", content);
item.content = content;
}
this.decryptItems = function(items, key) {
this.decryptItems = function(items, masterKey) {
items.forEach(function(item){
// console.log("is encrypted?", item);
if(item.loc_eek && typeof item.content === 'string') {
this.decryptSingleItem(item, key);
if(item.enc_item_key && typeof item.content === 'string') {
this.decryptSingleItem(item, masterKey);
}
}.bind(this));
}
this.decryptItemsWithLocalKey = function(items) {
this.decryptItems(items, this.retrieveGk());
this.decryptItems(items, this.retrieveMk());
}
this.reencryptAllItemsAndSave = function(user, newKey, oldKey, callback) {
this.reencryptAllItemsAndSave = function(user, newMasterKey, oldMasterKey, callback) {
var items = user.filteredItems();
items.forEach(function(item){
if(item.loc_eek && typeof item.content === 'string') {
// first decrypt eek with old key
var ek = Neeto.crypto.decryptText(item.loc_eek, oldKey);
// now encrypt ek with new key
item.loc_eek = Neeto.crypto.encryptText(ek, newKey);
if(item.enc_item_key && typeof item.content === 'string') {
// first decrypt item_key with old key
var item_key = Neeto.crypto.decryptText(item.enc_item_key, oldMasterKey);
// now encrypt item_key with new key
item.enc_item_key = Neeto.crypto.encryptText(item_key, newMasterKey);
}
});

View File

@@ -31,6 +31,14 @@ class SNCrypto {
return CryptoJS.PBKDF2(passphrase, salt, { keySize: 256/32 }).toString();
}
firstHalfOfKey(key) {
return key.substring(0, key.length/2);
}
secondHalfOfKey(key) {
return key.substring(key.length/2, key.length);
}
sha256(text) {
return CryptoJS.SHA256(text).toString();
}
@@ -39,13 +47,17 @@ class SNCrypto {
return CryptoJS.SHA1(text).toString();
}
hmac256(message, secret) {
return CryptoJS.HmacSHA256(message, secret).toString();
}
computeEncryptionKeysForUser({email, 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 gk = keys[1];
var mk = keys[1];
callback({pw: pw, gk: gk});
callback({pw: pw, mk: mk});
});
}
@@ -56,9 +68,9 @@ class SNCrypto {
var pw_salt = this.sha1(email + "SN" + pw_nonce);
this.generateSymmetricKeyPair(_.merge({email: email, password: password, pw_salt: pw_salt}, defaults), function(keys){
var pw = keys[0];
var gk = keys[1];
var mk = keys[1];
callback(_.merge({pw: pw, gk: gk, pw_nonce: pw_nonce}, defaults));
callback(_.merge({pw: pw, mk: mk, pw_nonce: pw_nonce}, defaults));
});
}
}

View File

@@ -58,6 +58,16 @@ var SNCrypto = function () {
var passphrase = Neeto.crypto.generateRandomKey();
return CryptoJS.PBKDF2(passphrase, salt, { keySize: 256 / 32 }).toString();
}
}, {
key: 'firstHalfOfKey',
value: function firstHalfOfKey(key) {
return key.substring(0, key.length / 2);
}
}, {
key: 'secondHalfOfKey',
value: function secondHalfOfKey(key) {
return key.substring(key.length / 2, key.length);
}
}, {
key: 'sha256',
value: function sha256(text) {
@@ -68,6 +78,11 @@ var SNCrypto = function () {
value: function sha1(text) {
return CryptoJS.SHA1(text).toString();
}
}, {
key: 'hmac256',
value: function hmac256(message, secret) {
return CryptoJS.HmacSHA256(message, secret).toString();
}
}, {
key: 'computeEncryptionKeysForUser',
value: function computeEncryptionKeysForUser() {
@@ -85,9 +100,9 @@ var SNCrypto = function () {
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 gk = keys[1];
var mk = keys[1];
callback({ pw: pw, gk: gk });
callback({ pw: pw, mk: mk });
});
}
}, {
@@ -109,9 +124,9 @@ var SNCrypto = function () {
var pw_salt = this.sha1(email + "SN" + pw_nonce);
this.generateSymmetricKeyPair(_.merge({ email: email, password: password, pw_salt: pw_salt }, defaults), function (keys) {
var pw = keys[0];
var gk = keys[1];
var mk = keys[1];
callback(_.merge({ pw: pw, gk: gk, pw_nonce: pw_nonce }, defaults));
callback(_.merge({ pw: pw, mk: mk, pw_nonce: pw_nonce }, defaults));
});
}
}]);
@@ -362,10 +377,7 @@ angular.module('app.frontend', ['ui.router', 'restangular', 'oc.lazyLoad', 'angu
$stateProvider.state('base', {
abstract: true
})
// Homepage
.state('home', {
}).state('home', {
url: '/',
parent: 'base',
views: {
@@ -376,39 +388,6 @@ angular.module('app.frontend', ['ui.router', 'restangular', 'oc.lazyLoad', 'angu
}
})
// Auth routes
// .state('auth', {
// abstract: true,
// url: '/auth',
// parent: 'base',
// views: {
// 'content@' : {
// templateUrl: 'frontend/auth/wrapper.html',
// }
// }
// })
// .state('auth.login', {
// url: '/login',
// templateUrl: 'frontend/auth/login.html',
// })
// .state('auth.forgot', {
// url: '/forgot',
// templateUrl: 'frontend/auth/forgot.html',
// })
// .state('auth.reset', {
// url: '/reset?reset_password_token&email',
// templateUrl: 'frontend/auth/reset.html',
// controller: function($rootScope, $stateParams) {
// $rootScope.resetData = {reset_password_token: $stateParams.reset_password_token, email: $stateParams.email};
//
// // Clear reset_password_token on change state
// $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams, options) {
// $rootScope.reset_password_token = null;
// });
// },
// })
// 404 Error
.state('404', {
parent: 'base',
@@ -437,7 +416,7 @@ var BaseCtrl = function BaseCtrl($rootScope, modelManager) {
// data.password = new_keys.pw;
// data.password_confirmation = new_keys.pw;
// $auth.updatePassword(data);
// apiController.setGk(new_keys.gk);
// apiController.setMk(new_keys.mk);
// }
// var note = new Note();
@@ -1375,7 +1354,7 @@ var Item = function () {
}, {
key: 'encryptionEnabled',
value: function encryptionEnabled() {
return this.loc_eek;
return this.enc_item_key;
}
}, {
key: 'presentationURL',
@@ -1582,6 +1561,7 @@ var User = function User(json_obj) {
var user = _.omit(plain, ["items"]);
callback(user, items);
}.bind(this)).catch(function (error) {
console.log("Error getting current user", error);
callback(null);
});
};
@@ -1589,7 +1569,7 @@ var User = function User(json_obj) {
this.login = function (email, password, callback) {
this.getAuthParamsForEmail(email, function (authParams) {
Neeto.crypto.computeEncryptionKeysForUser(_.merge({ email: email, password: password }, authParams), function (keys) {
this.setGk(keys.gk);
this.setMk(keys.mk);
var request = Restangular.one("auth/sign_in");
request.user = { password: keys.pw, email: email };
request.post().then(function (response) {
@@ -1602,8 +1582,8 @@ var User = function User(json_obj) {
this.register = function (email, password, callback) {
Neeto.crypto.generateInitialEncryptionKeysForUser({ password: password, email: email }, function (keys) {
this.setGk(keys.gk);
keys.gk = null;
this.setMk(keys.mk);
keys.mk = null;
var request = Restangular.one("auth");
request.user = _.merge({ password: keys.pw, email: email }, keys);
request.post().then(function (response) {
@@ -1627,10 +1607,10 @@ var User = function User(json_obj) {
this._performPasswordChange(currentKeys, newKeys, function (response) {
if (response && !response.errors) {
// this.showNewPasswordForm = false;
// reencrypt data with new gk
this.reencryptAllItemsAndSave(user, newKeys.gk, currentKeys.gk, function (success) {
// reencrypt data with new mk
this.reencryptAllItemsAndSave(user, newKeys.mk, currentKeys.mk, function (success) {
if (success) {
this.setGk(newKeys.gk);
this.setMk(newKeys.mk);
alert("Your password has been changed and your data re-encrypted.");
} else {
// rollback password
@@ -1759,13 +1739,15 @@ var User = function User(json_obj) {
});
if (encrypted) {
this.encryptSingleItem(itemCopy, this.retrieveGk());
this.encryptSingleItem(itemCopy, this.retrieveMk());
params.content = itemCopy.content;
params.loc_eek = itemCopy.loc_eek;
params.enc_item_key = itemCopy.enc_item_key;
params.auth_hash = itemCopy.auth_hash;
} else {
params.content = forExportFile ? itemCopy.content : JSON.stringify(itemCopy.content);
if (!forExportFile) {
params.loc_eek = null;
params.enc_item_key = null;
params.auth_hash = null;
}
}
@@ -1944,87 +1926,104 @@ var User = function User(json_obj) {
Encrpytion
*/
this.retrieveGk = function () {
if (!this.gk) {
this.gk = localStorage.getItem("gk");
this.retrieveMk = function () {
if (!this.mk) {
this.mk = localStorage.getItem("mk");
}
return this.gk;
return this.mk;
};
this.setGk = function (gk) {
localStorage.setItem('gk', gk);
this.setMk = function (mk) {
localStorage.setItem('mk', mk);
};
this.signout = function () {
localStorage.removeItem("jwt");
localStorage.removeItem("gk");
localStorage.removeItem("mk");
};
this.encryptSingleItem = function (item, key) {
var ek = null;
if (item.loc_eek) {
ek = Neeto.crypto.decryptText(item.loc_eek, key);
this.encryptSingleItem = function (item, masterKey) {
var item_key = null;
if (item.enc_item_key) {
item_key = Neeto.crypto.decryptText(item.enc_item_key, masterKey);
} else {
ek = Neeto.crypto.generateRandomEncryptionKey();
item.loc_eek = Neeto.crypto.encryptText(ek, key);
item_key = Neeto.crypto.generateRandomEncryptionKey();
item.enc_item_key = Neeto.crypto.encryptText(item_key, masterKey);
}
item.content = Neeto.crypto.encryptText(JSON.stringify(item.content), ek);
var ek = Neeto.crypto.firstHalfOfKey(item_key);
var ak = Neeto.crypto.secondHalfOfKey(item_key);
var encryptedContent = Neeto.crypto.encryptText(JSON.stringify(item.content), ek);
var authHash = Neeto.crypto.hmac256(encryptedContent, ak);
item.content = encryptedContent;
item.auth_hash = authHash;
item.local_encryption_scheme = "1.0";
console.log("Encrypting item. itemKey:", item_key, "authHash:", item.auth_hash);
};
this.encryptItems = function (items, key) {
this.encryptItems = function (items, masterKey) {
items.forEach(function (item) {
this.encryptSingleItem(item, key);
this.encryptSingleItem(item, masterKey);
}.bind(this));
};
this.encryptSingleItemWithLocalKey = function (item) {
this.encryptSingleItem(item, this.retrieveGk());
this.encryptSingleItem(item, this.retrieveMk());
};
this.encryptItemsWithLocalKey = function (items) {
this.encryptItems(items, this.retrieveGk());
this.encryptItems(items, this.retrieveMk());
};
this.encryptNonPublicItemsWithLocalKey = function (items) {
var nonpublic = items.filter(function (item) {
return !item.isPublic() && !item.pending_share;
});
this.encryptItems(nonpublic, this.retrieveGk());
this.encryptItems(nonpublic, this.retrieveMk());
};
this.decryptSingleItemWithLocalKey = function (item) {
this.decryptSingleItem(item, this.retrieveGk());
this.decryptSingleItem(item, this.retrieveMk());
};
this.decryptSingleItem = function (item, key) {
var ek = Neeto.crypto.decryptText(item.loc_eek || item.local_eek, key);
this.decryptSingleItem = function (item, masterKey) {
var item_key = Neeto.crypto.decryptText(item.enc_item_key, masterKey);
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.");
return;
}
var content = Neeto.crypto.decryptText(item.content, ek);
// console.log("decrypted contnet", content);
item.content = content;
};
this.decryptItems = function (items, key) {
this.decryptItems = function (items, masterKey) {
items.forEach(function (item) {
// console.log("is encrypted?", item);
if (item.loc_eek && typeof item.content === 'string') {
this.decryptSingleItem(item, key);
if (item.enc_item_key && typeof item.content === 'string') {
this.decryptSingleItem(item, masterKey);
}
}.bind(this));
};
this.decryptItemsWithLocalKey = function (items) {
this.decryptItems(items, this.retrieveGk());
this.decryptItems(items, this.retrieveMk());
};
this.reencryptAllItemsAndSave = function (user, newKey, oldKey, callback) {
this.reencryptAllItemsAndSave = function (user, newMasterKey, oldMasterKey, callback) {
var items = user.filteredItems();
items.forEach(function (item) {
if (item.loc_eek && typeof item.content === 'string') {
// first decrypt eek with old key
var ek = Neeto.crypto.decryptText(item.loc_eek, oldKey);
// now encrypt ek with new key
item.loc_eek = Neeto.crypto.encryptText(ek, newKey);
if (item.enc_item_key && typeof item.content === 'string') {
// first decrypt item_key with old key
var item_key = Neeto.crypto.decryptText(item.enc_item_key, oldMasterKey);
// now encrypt item_key with new key
item.enc_item_key = Neeto.crypto.encryptText(item_key, newMasterKey);
}
});

File diff suppressed because one or more lines are too long