Add some additional crypto capabilities; Encrypt model store
This commit is contained in:
parent
abfc4a01a9
commit
35d85dc940
|
@ -16,12 +16,15 @@ define(["sjcl"], function(sjcl) {
|
|||
* @type {[type]}
|
||||
*/
|
||||
var container = Object.create({}, {
|
||||
cipher: {value: ciphers.AES, writable: true, enumerable: true},
|
||||
mode: {value: modes.CCM, writable: true, enumerable: true},
|
||||
iv: {value: "", writable: true, enumerable: true},
|
||||
ct: {value: "", writable: true},
|
||||
adata: {value: [], writable: true},
|
||||
ts: {value: 64, writable: true}
|
||||
cipher: {value: ciphers.AES, writable: true, enumerable: true},
|
||||
mode: {value: modes.CCM, writable: true, enumerable: true},
|
||||
iv: {value: "", writable: true, enumerable: true},
|
||||
salt: {value: "", writable: true, enumerable: true},
|
||||
keySize: {value: 256, writable: true, enumerable: true},
|
||||
iter: {value: 1000, writable: true, enumerable: true},
|
||||
ct: {value: "", writable: true},
|
||||
adata: {value: [], writable: true},
|
||||
ts: {value: 64, writable: true}
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -30,63 +33,86 @@ define(["sjcl"], function(sjcl) {
|
|||
* @param {string} passphrase
|
||||
* A string to be used as base for the key derivation
|
||||
* @param {array} salt
|
||||
* Salt to be used for key derivation. Will be generated if not provided
|
||||
* Base64 encoded salt to be used for key derivation. Will be generated if not provided
|
||||
* @param {number} size
|
||||
* Desired key size. Defaults to 256
|
||||
* @param {number} iter
|
||||
* Numer of iterations to use for the key derivation algorithm. Defaults to 1000
|
||||
* @return {object}
|
||||
* Key object containing the actual _key_ along with the used _salt_
|
||||
* Key object containing the actual _key_ (base64 encoded) along with the used _salt_ and _iter_ations used
|
||||
*/
|
||||
function genKey(passphrase, salt, size, iter) {
|
||||
salt = salt || sjcl.random.randomWords(4,0);
|
||||
var s = salt ? sjcl.codec.base64.toBits(salt) : sjcl.random.randomWords(4,0);
|
||||
size = size || 256;
|
||||
var p = sjcl.misc.cachedPbkdf2(passphrase, {iter: iter || 1000, salt: salt});
|
||||
p.key = p.key.slice(0, size/32);
|
||||
iter = iter || 1000;
|
||||
var p = sjcl.misc.cachedPbkdf2(passphrase, {iter: iter, salt: s});
|
||||
p.key = sjcl.codec.base64.fromBits(p.key.slice(0, size/32));
|
||||
p.salt = sjcl.codec.base64.fromBits(s);
|
||||
p.size = size;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a value inside a _crypto.container_ using the provided _key_
|
||||
* @param {string} key
|
||||
* The encryption key
|
||||
* The encryption key (base64 encoded)
|
||||
* @param {object} value
|
||||
* A _crypto.container_ containing the value to be decrypted
|
||||
*/
|
||||
function decrypt(key, cont) {
|
||||
var aes = new sjcl.cipher.aes(key);
|
||||
var aes = new sjcl.cipher.aes(sjcl.codec.base64.toBits(key));
|
||||
var iv = sjcl.codec.base64.toBits(cont.iv);
|
||||
var ct = sjcl.codec.base64.toBits(cont.ct);
|
||||
var pt = sjcl.mode[cont.mode.toLowerCase()].decrypt(aes, ct, iv, unescape(cont.adata), cont.ts);
|
||||
var pt = sjcl.mode[cont.mode].decrypt(aes, ct, iv, cont.adata, cont.ts);
|
||||
return sjcl.codec.utf8String.fromBits(pt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the _value_ using the provided _key_ and wraps it into a _crypto.container_ object.
|
||||
* @param {string} key
|
||||
* Key to be used for encryption
|
||||
* Key to be used for encryption (base64 encoded)
|
||||
* @param {string} value
|
||||
* Value to be encrypted
|
||||
* @param {array} adata
|
||||
* @param {string} adata
|
||||
* Authenticated data to be used for checking the integrity of the encrypted data and whether
|
||||
* a description was successful
|
||||
* @param {number} tagSize
|
||||
*/
|
||||
function encrypt(key, value, adata, tagSize) {
|
||||
var cont = Object.create(container);
|
||||
var iv = sjcl.random.randomWords(4,0);
|
||||
var aes = new sjcl.cipher.aes(key);
|
||||
var aes = new sjcl.cipher.aes(sjcl.codec.base64.toBits(key));
|
||||
var pt = sjcl.codec.utf8String.toBits(value);
|
||||
cont.adata = adata || sjcl.codec.base64.fromBits(sjcl.random.randomWords(4,0));
|
||||
cont.ts = tagSize || 0;
|
||||
var ct = sjcl.mode[cont.mode].encrypt(aes, pt, iv, cont.adata, cont.ts);
|
||||
cont.iv = sjcl.codec.base64.fromBits(iv);
|
||||
cont.ct = sjcl.codec.base64.fromBits(ct);
|
||||
return cont;
|
||||
}
|
||||
|
||||
function pwdDecrypt(pwd, cont) {
|
||||
var p = genKey(pwd, cont.salt, cont.keySize, cont.iter);
|
||||
return decrypt(p.key, cont);
|
||||
}
|
||||
|
||||
function pwdEncrypt(pwd, value) {
|
||||
var p = genKey(pwd);
|
||||
var cont = encrypt(p.key, value);
|
||||
cont.salt = p.salt;
|
||||
cont.iter = p.iter;
|
||||
cont.keySize = p.size;
|
||||
return cont;
|
||||
}
|
||||
|
||||
return {
|
||||
ciphers: ciphers,
|
||||
modes: modes,
|
||||
container: container,
|
||||
genKey: genKey,
|
||||
decrypt: decrypt,
|
||||
encrypt: encrypt
|
||||
encrypt: encrypt,
|
||||
pwdDecrypt: pwdDecrypt,
|
||||
pwdEncrypt: pwdEncrypt
|
||||
};
|
||||
});
|
49
src/model.js
49
src/model.js
|
@ -1,4 +1,34 @@
|
|||
define(["safe/crypto", "safe/util"], function(crypto, util) {
|
||||
var store = Object.create({}, {
|
||||
password: {
|
||||
value: "", writable: true
|
||||
},
|
||||
fetch: {
|
||||
value: function(coll, password) {
|
||||
this.password = password || this.password;
|
||||
var obj = {};
|
||||
|
||||
var json = localStorage.getItem("coll_" + coll.name);
|
||||
if (json) {
|
||||
try {
|
||||
var c = JSON.parse(json);
|
||||
obj.records = crypto.pwdDecrypt(this.password, c);
|
||||
} catch (e) {
|
||||
console.error("*** failed decrypting! ***", e);
|
||||
}
|
||||
}
|
||||
return coll.parse(obj);
|
||||
}
|
||||
},
|
||||
save: {
|
||||
value: function(coll) {
|
||||
var pt = JSON.stringify(coll.raw());
|
||||
var c = crypto.pwdEncrypt(this.password, pt);
|
||||
localStorage.setItem("coll_" + coll.name, JSON.stringify(c));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var record = Object.create({}, {
|
||||
name: {
|
||||
enumerable: true,
|
||||
|
@ -18,7 +48,7 @@ define(["safe/crypto", "safe/util"], function(crypto, util) {
|
|||
},
|
||||
store: {
|
||||
writable: true,
|
||||
value: null
|
||||
value: store
|
||||
},
|
||||
records: {
|
||||
writable: true,
|
||||
|
@ -27,7 +57,7 @@ define(["safe/crypto", "safe/util"], function(crypto, util) {
|
|||
},
|
||||
parse: {
|
||||
value: function(obj) {
|
||||
this.records = obj.records;
|
||||
this.records = obj.records || [];
|
||||
}
|
||||
},
|
||||
raw: {
|
||||
|
@ -68,21 +98,6 @@ define(["safe/crypto", "safe/util"], function(crypto, util) {
|
|||
}
|
||||
});
|
||||
|
||||
var store = Object.create({}, {
|
||||
fetch: {
|
||||
value: function(coll) {
|
||||
var json = localStorage.getItem("coll_" + coll.name) || "{}";
|
||||
return coll.parse(JSON.parse(json));
|
||||
}
|
||||
},
|
||||
save: {
|
||||
value: function(coll) {
|
||||
var json = JSON.stringify(coll.raw());
|
||||
localStorage.setItem("coll_" + coll.name, json);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
record: record,
|
||||
collection: collection,
|
||||
|
|
Loading…
Reference in New Issue