Commit 549b3ed8 authored by amrani's avatar amrani

adding messaging API to cryptostorage

parent 0b8bd163
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
/* /*
* Copyright 2015, Nexedi SA * Copyright 2015, Nexedi SA
* Released under the LGPL license. * Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html * hcrypto, Uint8Array, ArrayBuffer*/
*/
/*jslint nomen: true*/ /*jslint nomen: true*/
/*global jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer*/ /*jslint maxlen: 160 */
/*global jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer, CryptoKey*/
(function (jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer) { (function (jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer,
CryptoKey) {
"use strict"; "use strict";
/* /*
...@@ -16,13 +15,10 @@ ...@@ -16,13 +15,10 @@
go to the website : https://randomkeygen.com/ pike a key and memorize it go to the website : https://randomkeygen.com/ pike a key and memorize it
let suppose the key choseen is "Hwm0jPAmQC" then :
return new RSVP.Queue() return new RSVP.Queue()
.push(function (json_key) { .push(function () {
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt"
key: "Hwm0jPAmQC",
sub_storage: {storage_definition} sub_storage: {storage_definition}
}); });
}); });
...@@ -38,9 +34,6 @@ ...@@ -38,9 +34,6 @@
* @constructor * @constructor
*/ */
var MIME_TYPE = "application/x-jio-aes-gcm-encryption";
//used unibabel.js for converting function
function hexToBuffer(hex) { function hexToBuffer(hex) {
// Xxxx use Uint8Array or ArrayBuffer or DataView // Xxxx use Uint8Array or ArrayBuffer or DataView
...@@ -63,123 +56,50 @@ ...@@ -63,123 +56,50 @@
return arr; return arr;
} }
function utf8ToBinaryString(str) {
var escstr = encodeURIComponent(str),
// replaces any uri escape sequence, such as %0A,
// with binary escape, such as 0x0A
binstr = escstr.replace(/%([0-9A-F]{2})/g, function (p1) {
return String.fromCharCode(parseInt(p1, 16));
});
return binstr;
}
function binaryStringToBuffer(binstr) {
var buf;
if ("undefined" !== Uint8Array) {
buf = new Uint8Array(binstr.length);
} else {
buf = [];
}
Array.prototype.forEach.call(binstr, function (ch, i) {
buf[i] = ch.charCodeAt(0);
});
return buf;
}
function utf8ToBuffer(str) {
var binstr = utf8ToBinaryString(str),
buf = binaryStringToBuffer(binstr);
return buf;
}
function hex(buffer) {
var hexCodes = [],
view = new DataView(buffer),
i,
value,
stringValue,
padding,
paddedValue;
for (i = 0; i < view.byteLength; i += 4) {
// Using getUint32 reduces the number
//of iterations needed (we process 4 bytes each time)
value = view.getUint32(i);
// toString(16) will give the hex representation
//of the number without padding
stringValue = value.toString(16);
// We use concatenation and slice for padding
padding = '00000000';
paddedValue = (padding + stringValue).slice(-padding.length);
hexCodes.push(paddedValue);
}
}
function sha256(str) {
// We transform the string into an arraybuffer.
return crypto.subtle.digest("SHA-256", utf8ToBuffer(str))
.then(function (hash) {
return hex(hash);
});
}
//function for JIO.js substorage
//API for using String Key form user
function CryptStorage(spec) {
if (spec.key !== undefined && spec.key !== null
&& typeof spec.key === 'string') {
this._key = spec.key;
this._userkey = true;
//hash the value of spec.key so if some one try to get it back
sha256(spec.key).then(function (digest) {spec.key = digest; });
this._sub_storage = jIO.createJIO(spec.sub_storage);
} else {
spec.key = null;
this._userkey = false;
this._key = null;
this._sub_storage = jIO.createJIO(spec.sub_storage);
}
}
function convertKey(that) { function convertKey(that) {
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
var passphraseKey = utf8ToBuffer(that._key);
return window.crypto.subtle.importKey(
"raw",
passphraseKey,
{
name: "PBKDF2"
},
false,
["deriveBits", "deriveKey"
]
);
})
.push(function (key) {
return window.crypto.subtle.deriveKey({ return window.crypto.subtle.deriveKey({
"name": "PBKDF2", "name": "PBKDF2",
"salt": hexToBuffer("6f0904840608c09ae18c131542fbd1bd"), "salt": hexToBuffer("6f0904840608c09ae18c131542fbd1bd"),
"iterations": 1000, "iterations": 1000,
//we can add iteration number but slow CPU will freez //we can add iteration number but slow CPU will freez
"hash": "SHA-256" "hash": "SHA-256"
}, key, { }, that.importedkey, {
"name": "AES-GCM", "name": "AES-GCM",
"length": 256 "length": 256
}, false, ["encrypt", "decrypt"]); }, false, ["encrypt", "decrypt"]);
}) })
.push(function (res) { .push(function (res) {
that._key = res; that.key = res;
that._userkey = false;
return; return;
}); });
} }
function addevent(that) {
try {
window.addEventListener('message', function (event) {
if (event.origin !== window.origin) {return; }
if (!(event.data instanceof CryptoKey)) {return; }
if (event.data.algorithm.name !== "PBKDF2" &&
event.data.usages[0] !== "deriveKey") {return; }
that.importedkey = event.data;
convertKey(that);
}, false);
} catch (error) {
throw new jIO.util.jIOError(error + "failed to build event lisener please reload the page", 803);
}
}
var MIME_TYPE = "application/x-jio-aes-gcm-encryption";
function CryptStorage(spec) {
addevent(this);
this.importedkey = "";
this.key = "";
this._sub_storage = jIO.createJIO(spec.sub_storage);
}
CryptStorage.prototype.get = function () { CryptStorage.prototype.get = function () {
return this._sub_storage.get.apply(this._sub_storage, return this._sub_storage.get.apply(this._sub_storage,
arguments); arguments);
...@@ -210,18 +130,11 @@ ...@@ -210,18 +130,11 @@
arguments); arguments);
}; };
CryptStorage.prototype.putAttachment = function (id, name, blob) { CryptStorage.prototype.putAttachment = function (id, name, blob) {
var initializaton_vector = crypto.getRandomValues(new Uint8Array(12)), var initializaton_vector = crypto.getRandomValues(new Uint8Array(12)),
that = this; that = this;
if (that._key !== null) {
return new RSVP.Queue() return new RSVP.Queue()
.push(function () {
if (that._userkey === true) {
return convertKey(that);
}
return;
})
.push(function () { .push(function () {
return jIO.util.readBlobAsDataURL(blob); return jIO.util.readBlobAsDataURL(blob);
}) })
...@@ -239,22 +152,30 @@ ...@@ -239,22 +152,30 @@
name: "AES-GCM", name: "AES-GCM",
iv: initializaton_vector iv: initializaton_vector
}, },
that._key, buf); that.key, buf);
}) })
.push(function (coded) { .push(function (coded) {
var blob = new Blob([initializaton_vector, coded], { var blob = new Blob([initializaton_vector, coded], {
type: MIME_TYPE type: MIME_TYPE
}); });
return that._sub_storage.putAttachment(id, name, blob); return that._sub_storage.putAttachment(id, name, blob);
})
.push(undefined, function (error) {
if (error instanceof DOMException) {
if (error.name === "OperationError") {
throw new jIO.util.jIOError(error.name + " : failed to decrypt due to mismatching password", 801);
}
if (error.name === "InvalidAccessError") {
throw new jIO.util.jIOError(error.name + " : invalid encryption algorithm, or invalid key for specified encryption algorithm", 801);
}
} else if (error instanceof TypeError) {
throw new jIO.util.jIOError(error + " : password is not type CRYPTOKEY ", 801);
}
}); });
} //if the password is not a string or null or undefined
//we do not crypt data
return that._sub_storage.putAttachment(id, name, blob);
}; };
CryptStorage.prototype.getAttachment = function (id, name) { CryptStorage.prototype.getAttachment = function (id, name) {
var that = this; var that = this;
if (that._key !== null) {
return that._sub_storage.getAttachment(id, name) return that._sub_storage.getAttachment(id, name)
.push(function (blob) { .push(function (blob) {
if (blob.type !== MIME_TYPE) { if (blob.type !== MIME_TYPE) {
...@@ -262,11 +183,7 @@ ...@@ -262,11 +183,7 @@
} }
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
if (that._userkey === true) { return new RSVP.Queue()
return convertKey(that);
}
return;
})
.push(function () { .push(function () {
return jIO.util.readBlobAsArrayBuffer(blob); return jIO.util.readBlobAsArrayBuffer(blob);
}) })
...@@ -280,25 +197,29 @@ ...@@ -280,25 +197,29 @@
name: "AES-GCM", name: "AES-GCM",
iv: initializaton_vector iv: initializaton_vector
}, },
that._key, coded.slice(12)); that.key, coded.slice(12));
}) })
.push(function (arr) { .push(function (arr) {
//arraybuffer->string
arr = String.fromCharCode.apply(null, new Uint8Array(arr)); arr = String.fromCharCode.apply(null, new Uint8Array(arr));
return jIO.util.dataURItoBlob(arr); return jIO.util.dataURItoBlob(arr);
}) })
.push(undefined, function (error) { .push(undefined, function (error) {
if (error instanceof DOMException) { if (error instanceof DOMException) {
if (error.name === "OperationError") {
throw new jIO.util.jIOError(error.name + " : failed to decrypt due to mismatching password", 801);
}
if (error.name === "InvalidAccessError") {
throw new jIO.util.jIOError(error.name + " : invalid encryption algorithm, or invalid key for specified encryption algorithm", 801);
}
return blob; return blob;
} }
throw error; if (error instanceof TypeError) {
throw new jIO.util.jIOError(error + " : password is not type CRYPTOKEY ", 801);
}
});
}); });
}); });
}); });
}
//if the password is not a string or null or undefined
//we do not crypt data
return that._sub_storage.getAttachment(id, name);
}; };
CryptStorage.prototype.removeAttachment = function () { CryptStorage.prototype.removeAttachment = function () {
...@@ -313,4 +234,4 @@ ...@@ -313,4 +234,4 @@
jIO.addStorage('crypt', CryptStorage); jIO.addStorage('crypt', CryptStorage);
}(jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer)); }(jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer, CryptoKey));
\ No newline at end of file \ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment