Commit 9d01d533 authored by amrani's avatar amrani

major change to cryptostorage

parent b345214e
/* /*
* Copyright 2015, Nexedi SA * Copyright 2018, Nexedi SA
* Released under the LGPL license. * Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html * http://www.gnu.org/licenses/lgpl.html
*/ */
/*jslint nomen: true*/ /*jslint nomen: true*/
/*global jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer*/ /*global jIO, RSVP, DOMParser, Blob, DOMException, crypto, Uint8Array,
ArrayBuffer, CryptoKey*/
(function (jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer) { /*jslint maxlen: 160 */
(function (jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer, CryptoKey) {
"use strict"; "use strict";
/* /*
The cryptography system used by this storage is AES-GCM. The cryptography system used by this storage is AES-GCM.
Here is an example of how to generate a key to the json format:
Here is an example of how to generate a strong user key :
-go to the website : https://randomkeygen.com/ pike a key and memorize it
after that you can Import your key like in exemple above .
-exemple of key generation :
var your_key = mySuperHardKey2018,
buffer = new TextEncoder("utf-8").encode(your_key);
return new RSVP.Queue()
.push(function () {
return RSVP.all([window.crypto.subtle.digest("SHA-256", buffer),
window.crypto.subtle.importKey(
"raw",
buffer,
{name: "PBKDF2"
},
false,
["deriveKey"]
)
]);
})
.push(function (my_array) {
return {
CryptoKey: my_array[1],
Salt: my_array[0]
};
})
.push(undefined, function (error) {
throw error;
});
-once storage created you use the callback to call addkey function and add
the required CryptoKey you generated earlier .
utils = {"crypto_getCryptoKey": function (callback) {
return new RSVP.Queue()
.push(function () {
addkey = callback.addkey_crypto;
error = callback.error_crypto;
})
.push(undefined, function (error) {
throw error;
});
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return crypto.subtle.generateKey({name: "AES-GCM", length: 256},
true, ["encrypt", "decrypt"]);
})
.push(function (key) {
return crypto.subtle.exportKey("jwk", key);
})
.push(function (json_key) {
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt"
key: json_key,
sub_storage: {storage_definition} sub_storage: {storage_definition}
}); }, utils);
}); });
Find more informations about this cryptography system on Find more informations about this cryptography system on
https://github.com/diafygi/webcrypto-examples#aes-gcm https://github.com/diafygi/webcrypto-examples#aes-gcm
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey
*/ */
/** /**
...@@ -41,26 +79,14 @@ ...@@ -41,26 +79,14 @@
* @constructor * @constructor
*/ */
var MIME_TYPE = "application/x-jio-aes-gcm-encryption";
function CryptStorage(spec) { var MIME_TYPE = "application/x-jio-aes-gcm-encryption";
this._key = spec.key;
this._jsonKey = true;
this._sub_storage = jIO.createJIO(spec.sub_storage);
}
function convertKey(that) { function CryptStorage(spec, utils) {
return new RSVP.Queue() this._utils = utils;
.push(function () { this._keyid = spec.keyid;
return crypto.subtle.importKey("jwk", that._key, this._key = "";
"AES-GCM", false, this._sub_storage = jIO.createJIO(spec.sub_storage, utils);
["encrypt", "decrypt"]);
})
.push(function (res) {
that._key = res;
that._jsonKey = false;
return;
});
} }
CryptStorage.prototype.get = function () { CryptStorage.prototype.get = function () {
...@@ -93,18 +119,10 @@ ...@@ -93,18 +119,10 @@
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;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () {
if (that._jsonKey === true) {
return convertKey(that);
}
return;
})
.push(function () { .push(function () {
return jIO.util.readBlobAsDataURL(blob); return jIO.util.readBlobAsDataURL(blob);
}) })
...@@ -114,64 +132,116 @@ ...@@ -114,64 +132,116 @@
buf = new ArrayBuffer(strLen), buf = new ArrayBuffer(strLen),
bufView = new Uint8Array(buf), bufView = new Uint8Array(buf),
i; i;
dataURL = dataURL.target.result; dataURL = dataURL.target.result;
for (i = 0; i < strLen; i += 1) { for (i = 0; i < strLen; i += 1) {
bufView[i] = dataURL.charCodeAt(i); bufView[i] = dataURL.charCodeAt(i);
} }
return crypto.subtle.encrypt({ return crypto.subtle.encrypt({
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], {type: MIME_TYPE}); var blob = new Blob([initializaton_vector, coded], {
type: MIME_TYPE
});
return that._sub_storage.putAttachment(id, name, blob); return that._sub_storage.putAttachment(id, name, blob);
})
.push(undefined, function (error) {
var cryptoerror = {keyid: that._keyid},
callback_crypto = {
addkey_crypto: that.addkey.bind(that),
error_crypto: cryptoerror
};
if (that._utils === undefined) {
throw new jIO.util.jIOError(that._keyid + ": no callback function declared");
}
if (!that._utils.hasOwnProperty("crypto_getCryptoKey")) {
throw new jIO.util.jIOError(that._keyid + ":crypto_getCryptoKey function not declared in callback");
}
if (error instanceof DOMException) {
if (error.name === "OperationError") {
cryptoerror.error_type = error.name;
cryptoerror.error_message = "Failed to decrypt due to incorrect password or data";
} else if (error.name === "InvalidAccessError") {
cryptoerror.error_type = error.name;
cryptoerror.error_message = "invalid encryption algorithm, or invalid key for specified encryption algorithm";
}
} else if (error instanceof TypeError) {
cryptoerror.error_type = error.name;
cryptoerror.error_message = "password is not type CRYPTOKEY";
}
return new RSVP.Queue()
.push(function () {
return that._utils.crypto_getCryptoKey(callback_crypto);
})
.push(function () {
throw new jIO.util.jIOError(that._keyid + " : " + cryptoerror.error_type +
" : " + cryptoerror.error_message, 801);
});
}); });
}; };
CryptStorage.prototype.getAttachment = function (id, name) { CryptStorage.prototype.getAttachment = function (id, name) {
var that = this; var that = this;
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) {
return blob;
}
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
if (that._jsonKey === true) {
return convertKey(that);
}
return;
})
.push(function () {
return jIO.util.readBlobAsArrayBuffer(blob);
})
.push(function (coded) {
var initializaton_vector;
coded = coded.target.result;
initializaton_vector = new Uint8Array(coded.slice(0, 12));
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return crypto.subtle.decrypt({ return jIO.util.readBlobAsArrayBuffer(blob);
name : "AES-GCM",
iv : initializaton_vector
},
that._key, coded.slice(12));
}) })
.push(function (arr) { .push(function (coded) {
//arraybuffer->string var initializaton_vector;
arr = String.fromCharCode.apply(null, new Uint8Array(arr)); coded = coded.target.result;
return jIO.util.dataURItoBlob(arr); initializaton_vector = new Uint8Array(coded.slice(0, 12));
}) return new RSVP.Queue()
.push(undefined, function (error) { .push(function () {
if (error instanceof DOMException) { return crypto.subtle.decrypt({
return blob; name: "AES-GCM",
} iv: initializaton_vector
throw error; },
that._key, coded.slice(12));
})
.push(function (arr) {
arr = String.fromCharCode.apply(null, new Uint8Array(arr));
return jIO.util.dataURItoBlob(arr);
})
.push(undefined, function (error) {
var cryptoerror = {keyid: that._keyid},
callback_crypto = {
addkey_crypto: that.addkey.bind(that),
error_crypto: cryptoerror
};
if (that._utils === undefined) {
throw new jIO.util.jIOError(that._keyid + ": no callback function declared");
}
if (!that._utils.hasOwnProperty("crypto_getCryptoKey")) {
throw new jIO.util.jIOError(that._keyid + ":crypto_getCryptoKey function not declared in callback");
}
if (error instanceof DOMException) {
if (error.name === "OperationError") {
cryptoerror.error_type = error.name;
cryptoerror.error_message = "Failed to decrypt due to incorrect password or data";
} else if (error.name === "InvalidAccessError") {
cryptoerror.error_type = error.name;
cryptoerror.error_message = "invalid encryption algorithm, or invalid key for specified encryption algorithm";
}
} else if (error instanceof TypeError) {
cryptoerror.error_type = error.name;
cryptoerror.error_message = "password is not type CRYPTOKEY";
}
return new RSVP.Queue()
.push(function () {
return that._utils.crypto_getCryptoKey(callback_crypto);
})
.push(function () {
throw new jIO.util.jIOError(that._keyid + " : " + cryptoerror.error_type
+ " : " + cryptoerror.error_message, 801);
});
});
}); });
}); });
}); });
...@@ -187,6 +257,32 @@ ...@@ -187,6 +257,32 @@
arguments); arguments);
}; };
CryptStorage.prototype.addkey = function (key) {
var that = this;
if (key === undefined || key === null) {return; }
if (!(key.hasOwnProperty("CryptoKey") && key.hasOwnProperty("Salt"))) {return; }
if (!(key.CryptoKey instanceof CryptoKey && key.Salt instanceof ArrayBuffer)) {return; }
if (key.CryptoKey.algorithm.name !== "PBKDF2"
&& key.CryptoKey.usages[0] !== "deriveKey") {return; }
return new RSVP.Queue()
.push(function () {
return window.crypto.subtle.deriveKey({
"name": "PBKDF2",
"salt": key.Salt,
"iterations": 1000,
//we can add iteration number but slow CPU will freez
"hash": "SHA-256"
}, key.CryptoKey, {
"name": "AES-GCM",
"length": 256
}, false, ["encrypt", "decrypt"]);
})
.push(function (res) {
that._key = res;
});
};
jIO.addStorage('crypt', CryptStorage); jIO.addStorage('crypt', CryptStorage);
}(jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer)); }(jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer, CryptoKey));
/*jslint nomen: true*/ /*jslint nomen: true*/
/*global Blob, crypto, Uint8Array, ArrayBuffer*/ /*global Blob, crypto, Uint8Array, ArrayBuffer, TextEncoder, window*/
/*jslint maxlen: 130 */
(function (jIO, QUnit, Blob) { (function (jIO, QUnit, Blob) {
"use strict"; "use strict";
var test = QUnit.test, var test = QUnit.test,
...@@ -11,9 +12,47 @@ ...@@ -11,9 +12,47 @@
equal = QUnit.equal, equal = QUnit.equal,
throws = QUnit.throws, throws = QUnit.throws,
module = QUnit.module, module = QUnit.module,
key = {"alg": "A256GCM", "ext": true, callback = {callback: function () {return true; }},
"k": "seeaLzpu8dHG07bO2ANH2GywbTqs_zrs4Vq8zmtYeE4", convertKey = function (str) {
"key_ops": ["encrypt", "decrypt"], "kty": "oct"}; var buffer = new TextEncoder("utf-8").encode(str);
// We transform the string into an arraybuffer.
return new RSVP.Queue()
.push(function () {
return RSVP.all([crypto.subtle.digest("SHA-256", buffer),
crypto.subtle.importKey(
"raw",
buffer,
{name: "PBKDF2"
},
false,
["deriveKey"]
)
]);
})
.push(function (my_array) {
return {
CryptoKey: my_array[1],
Salt: my_array[0]
};
})
.push(undefined, function (error) {
throw error;
});
},
userkey = "passwordHADR0909",
utils = {"crypto_getCryptoKey": function (callback) {
return new RSVP.Queue()
.push(function () {
return convertKey(userkey);
})
.push(function (crypto_key) {
return callback.addkey_crypto(crypto_key);
})
.push(undefined, function (error) {
throw error;
});
}};
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Custom test substorage definition // Custom test substorage definition
...@@ -23,6 +62,14 @@ ...@@ -23,6 +62,14 @@
} }
jIO.addStorage('cryptstorage200', Storage200); jIO.addStorage('cryptstorage200', Storage200);
function Storagecallback(spec, utils) {
this._spec = spec;
this._utils = utils;
return this;
}
jIO.addStorage('Cryptstoragecallback', Storagecallback);
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// CryptStorage.constructor // CryptStorage.constructor
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -31,14 +78,29 @@ ...@@ -31,14 +78,29 @@
test("create substorage", function () { test("create substorage", function () {
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key, keyid: "key200",
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
equal(jio.__type, "crypt"); equal(jio.__type, "crypt");
equal(jio.__storage._keyid, "key200");
equal(jio.__storage._sub_storage.__type, "cryptstorage200"); equal(jio.__storage._sub_storage.__type, "cryptstorage200");
}); });
test("Test callback", function () {
var jio = jIO.createJIO({
type: "crypt",
keyid: "key200",
sub_storage: {
type: "Cryptstoragecallback"
}
}, callback);
deepEqual(jio.__storage._utils.callback(), true);
deepEqual(jio.__storage._sub_storage.__storage._utils.callback(), true);
});
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// CryptStorage.get // CryptStorage.get
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -49,7 +111,6 @@ ...@@ -49,7 +111,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -82,7 +143,6 @@ ...@@ -82,7 +143,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -115,7 +175,6 @@ ...@@ -115,7 +175,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -146,7 +205,6 @@ ...@@ -146,7 +205,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -174,7 +232,6 @@ ...@@ -174,7 +232,6 @@
test("hasCapacity return substorage value", function () { test("hasCapacity return substorage value", function () {
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -204,7 +261,6 @@ ...@@ -204,7 +261,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -237,7 +293,6 @@ ...@@ -237,7 +293,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -271,7 +326,6 @@ ...@@ -271,7 +326,6 @@
var jio = jIO.createJIO({ var jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key,
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); });
...@@ -301,13 +355,13 @@ ...@@ -301,13 +355,13 @@
setup: function () { setup: function () {
this.jio = jIO.createJIO({ this.jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key, keyid: "key200",
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); }, utils);
} }
}); });
test("return substorage getattachment", function () { test("return error if key is not type Cryptokey", function () {
var id = "/", var id = "/",
attachment = "stringattachment", attachment = "stringattachment",
blob = new Blob(['foo']); blob = new Blob(['foo']);
...@@ -322,64 +376,34 @@ ...@@ -322,64 +376,34 @@
expect(3); expect(3);
this.jio.getAttachment(id, attachment) this.jio.getAttachment(id, attachment)
.then(function (result) {
equal(result, blob, "Return substorage result");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("return substorage getattachment if decrypt fails", function () {
var id = "/",
attachment = "stringattachment",
blob = new Blob(['foo'], {type: 'application/x-jio-aes-gcm-encryption'});
Storage200.prototype.getAttachment = function (arg1, arg2) {
equal(arg1, id, "getAttachment 200 called");
equal(arg2, attachment, "getAttachment 200 called");
return blob;
};
stop();
expect(3);
this.jio.getAttachment(id, attachment)
.then(function (result) {
equal(result, blob, "Return substorage result");
})
.fail(function (error) { .fail(function (error) {
ok(false, error); equal(error.message, "key200 : TypeError : password is not type CRYPTOKEY", "get attachement error shown");
}) })
.always(function () { .always(function () {
start(); start();
}); });
}); });
test("return substorage getattachment if not data url", function () { test("return error if decrypt fails", function () {
var id = "/", var id = "/",
attachment = "stringattachment", attachment = "stringattachment",
blob = new Blob(['foo'], that,
{type: 'application/x-jio-aes-gcm-encryption'}); blob = new Blob(['foo']); //non crypted file
Storage200.prototype.getAttachment = function (arg1, arg2) { Storage200.prototype.getAttachment = function () {
equal(arg1, id, "getAttachment 200 called");
equal(arg2, attachment, "getAttachment 200 called");
return blob; return blob;
}; };
stop(); stop();
expect(3); expect(1);
that = this;
this.jio.getAttachment(id, attachment) that.jio.getAttachment(id, attachment)
.then(function (result) { .fail(function () {
equal(result, blob, "Return substorage result"); return that.jio.getAttachment(id, attachment)
}) .push(undefined, function (error) {
.fail(function (error) { equal(error.message, "key200 : OperationError : Failed to decrypt due to incorrect password or data",
ok(false, error); "returned error : incorrect password or incrypted data");
});
}) })
.always(function () { .always(function () {
start(); start();
...@@ -389,11 +413,14 @@ ...@@ -389,11 +413,14 @@
test("decrypt blob from aes-gcm", function () { test("decrypt blob from aes-gcm", function () {
var id = "/", var id = "/",
attachment = "stringattachment", attachment = "stringattachment",
that,
value = "azertyuio\npàç_è-('é&", value = "azertyuio\npàç_è-('é&",
tocheck = "data:application/x-jio-aes-gcm-encryption;base64" + tocheck = "data:application/x-jio-aes-gcm-encryption" +
",+p/Ho+KgGHZC2zDLMbQQS2tXcsy0g+Ho41VZnlPEkXdmG9zm36c8iLCkv" + ";base64,6RxBftHGvMYG+ymk2e2viIhtdIcbui7+4UH57S0bl" +
"lanyWCN510NK4hj1EgWQ6WrLS5pCmA/yeAWh+HyfPkYKDRHVBl6+Hxd53I" + "D6fqrrWTcgzx/SZjXdzYQyK7a1pe2tM9msrPDyZrreN+b+rU9S" +
"TmiWQ6Vix2jaIQg==", "YodEKW/XgSkcQj9n+V77KT/qsQymLb1K3widtxA==",
blob = jIO.util.dataURItoBlob(tocheck); blob = jIO.util.dataURItoBlob(tocheck);
...@@ -401,32 +428,36 @@ ...@@ -401,32 +428,36 @@
Storage200.prototype.getAttachment = function (arg1, arg2) { Storage200.prototype.getAttachment = function (arg1, arg2) {
equal(arg1, id, "getAttachment 200 called"); equal(arg1, id, "getAttachment 200 called");
equal(arg2, attachment, "getAttachment 200 called"); equal(arg2, attachment, "getAttachment 200 called");
window.m = new Date().getTime();
return blob; return blob;
}; };
stop(); stop();
expect(6); expect(9);
this.jio.getAttachment(id, attachment) that = this;
.then(function (result) { that.jio.getAttachment(id, attachment)
ok(result !== blob, "Does not return substorage result"); .fail(function () {
ok(result instanceof Blob, "Data is Blob"); return that.jio.getAttachment(id, attachment)
deepEqual(result.type, "text/plain;charset=utf-8", .push(function (result) {
"Check mimetype"); ok(true, "Decryption time = " + (new Date().getTime() - window.m) + " milliseconde");
ok(result !== blob, "Does not return substorage result");
return jIO.util.readBlobAsText(result); ok(result instanceof Blob, "Data is Blob");
}) deepEqual(result.type, "text/plain;charset=utf-8",
.then(function (result) { "Check mimetype");
equal(result.target.result, value, "Attachment correctly fetched"); return jIO.util.readBlobAsText(result);
}) })
.fail(function (error) { .push(function (result) {
ok(false, error); equal(result.target.result, value, "Attachment correctly fetched");
return result;
});
}) })
.always(function () { .always(function () {
start(); start();
}); });
}); });
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// CryptStorage.putAttachment // CryptStorage.putAttachment
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
...@@ -434,9 +465,9 @@ ...@@ -434,9 +465,9 @@
setup: function () { setup: function () {
this.jio = jIO.createJIO({ this.jio = jIO.createJIO({
type: "crypt", type: "crypt",
key: key, keyid: "key200",
sub_storage: {type : "cryptstorage200"} sub_storage: {type : "cryptstorage200"}
}); }, utils);
} }
}); });
...@@ -445,8 +476,19 @@ ...@@ -445,8 +476,19 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return crypto.subtle.importKey("jwk", key, return convertKey(userkey);
"AES-GCM", false, ["decrypt"]); })
.push(function (key) {
return window.crypto.subtle.deriveKey({
"name": "PBKDF2",
"salt": key.Salt,
"iterations": 1000,
//we can add iteration number but slow CPU will freez
"hash": "SHA-256"
}, key.CryptoKey, {
"name": "AES-GCM",
"length": 256
}, false, ["encrypt", "decrypt"]);
}) })
.push(function (res) { .push(function (res) {
decryptKey = res; decryptKey = res;
...@@ -460,11 +502,10 @@ ...@@ -460,11 +502,10 @@
coded = coded.target.result; coded = coded.target.result;
iv = new Uint8Array(coded.slice(0, 12)); iv = new Uint8Array(coded.slice(0, 12));
return crypto.subtle.decrypt({name : "AES-GCM", iv : iv}, return crypto.subtle.decrypt({name: "AES-GCM", iv: iv},
decryptKey, coded.slice(12)); decryptKey, coded.slice(12));
}) })
.push(function (arr) { .push(function (arr) {
arr = String.fromCharCode.apply(null, new Uint8Array(arr)); arr = String.fromCharCode.apply(null, new Uint8Array(arr));
equal( equal(
arr, arr,
...@@ -477,6 +518,7 @@ ...@@ -477,6 +518,7 @@
test("crypt blob to aes-gcm", function () { test("crypt blob to aes-gcm", function () {
var id = "/", var id = "/",
that,
attachment = "stringattachment", attachment = "stringattachment",
value = "azertyuio\npàç_è-('é&", value = "azertyuio\npàç_è-('é&",
blob = new Blob([value], blob = new Blob([value],
...@@ -492,15 +534,16 @@ ...@@ -492,15 +534,16 @@
return decodeAES(arg3); return decodeAES(arg3);
}; };
stop(); stop();
expect(7); expect(7);
that = this;
this.jio.putAttachment(id, attachment, blob) this.jio.putAttachment(id, attachment, blob)
.then(function (result) { .fail(function () {
equal(result, "ok", "Return substorage result"); return that.jio.putAttachment(id, attachment, blob)
}) .push(function (result) {
.fail(function (error) { equal(result, "ok", "Return substorage result");
ok(false, error); });
}) })
.always(function () { .always(function () {
start(); start();
......
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