Commit 0b8bd163 authored by amrani's avatar amrani

adding friedly user password to cryptostorage

parent d963b0a5
......@@ -75,6 +75,7 @@ module.exports = function (grunt) {
indent: 2,
maxerr: 3,
predef: [
'DataView',
'define',
'exports',
'require',
......
......@@ -12,20 +12,17 @@
/*
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
let suppose the key choseen is "Hwm0jPAmQC" then :
return new RSVP.Queue()
.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({
type: "crypt",
key: json_key,
key: "Hwm0jPAmQC",
sub_storage: {storage_definition}
});
});
......@@ -43,22 +40,142 @@
var MIME_TYPE = "application/x-jio-aes-gcm-encryption";
//used unibabel.js for converting function
function hexToBuffer(hex) {
// Xxxx use Uint8Array or ArrayBuffer or DataView
var i,
byteLen = hex.length / 2,
arr,
j = 0;
if (byteLen !== parseInt(byteLen, 10)) {
throw new Error("Invalid hex length '" + hex.length + "'");
}
arr = new Uint8Array(byteLen);
for (i = 0; i < byteLen; i += 1) {
arr[i] = parseInt(hex[j] + hex[j + 1], 16);
j += 2;
}
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._jsonKey = true;
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) {
return new RSVP.Queue()
.push(function () {
return crypto.subtle.importKey("jwk", that._key,
"AES-GCM", false,
["encrypt", "decrypt"]);
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({
"name": "PBKDF2",
"salt": hexToBuffer("6f0904840608c09ae18c131542fbd1bd"),
"iterations": 1000,
//we can add iteration number but slow CPU will freez
"hash": "SHA-256"
}, key, {
"name": "AES-GCM",
"length": 256
}, false, ["encrypt", "decrypt"]);
})
.push(function (res) {
that._key = res;
that._jsonKey = false;
that._userkey = false;
return;
});
}
......@@ -97,10 +214,10 @@
CryptStorage.prototype.putAttachment = function (id, name, blob) {
var initializaton_vector = crypto.getRandomValues(new Uint8Array(12)),
that = this;
if (that._key !== null) {
return new RSVP.Queue()
.push(function () {
if (that._jsonKey === true) {
if (that._userkey === true) {
return convertKey(that);
}
return;
......@@ -114,26 +231,30 @@
buf = new ArrayBuffer(strLen),
bufView = new Uint8Array(buf),
i;
dataURL = dataURL.target.result;
for (i = 0; i < strLen; i += 1) {
bufView[i] = dataURL.charCodeAt(i);
}
return crypto.subtle.encrypt({
name : "AES-GCM",
iv : initializaton_vector
name: "AES-GCM",
iv: initializaton_vector
},
that._key, buf);
})
.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);
});
} //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) {
var that = this;
if (that._key !== null) {
return that._sub_storage.getAttachment(id, name)
.push(function (blob) {
if (blob.type !== MIME_TYPE) {
......@@ -141,7 +262,7 @@
}
return new RSVP.Queue()
.push(function () {
if (that._jsonKey === true) {
if (that._userkey === true) {
return convertKey(that);
}
return;
......@@ -151,14 +272,13 @@
})
.push(function (coded) {
var initializaton_vector;
coded = coded.target.result;
initializaton_vector = new Uint8Array(coded.slice(0, 12));
return new RSVP.Queue()
.push(function () {
return crypto.subtle.decrypt({
name : "AES-GCM",
iv : initializaton_vector
name: "AES-GCM",
iv: initializaton_vector
},
that._key, coded.slice(12));
})
......@@ -175,6 +295,10 @@
});
});
});
}
//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 () {
......
......@@ -255,12 +255,15 @@
})
.push(function (evt) {
if (evt.target.response instanceof Blob) {
return evt.target.response;
//create a new blob with type AES-GCM to decrypt back
var cryptblob = new Blob([evt.target.response],
{type: "application/x-jio-aes-gcm-encryption"});
return cryptblob;
}
return new Blob(
[evt.target.responseText],
{"type": evt.target.getResponseHeader('Content-Type') ||
"application/octet-stream"}
{"type": "application/x-jio-aes-gcm-encryption"}
// evt.target.getResponseHeader('Content-Type') ||
);
}, function (error) {
if (error.target !== undefined && error.target.status === 409) {
......
......@@ -11,9 +11,15 @@
equal = QUnit.equal,
throws = QUnit.throws,
module = QUnit.module,
key = {"alg": "A256GCM", "ext": true,
"k": "seeaLzpu8dHG07bO2ANH2GywbTqs_zrs4Vq8zmtYeE4",
"key_ops": ["encrypt", "decrypt"], "kty": "oct"};
key = "password",
key_generated_by_password = {
"alg": "A256GCM",
"ext": true,
"k": "wBHHU4Es8IqMCnH03Jxhc1ZTQN7hzo6GkCNnbA_0kjI",
"key_ops": ["encrypt", "decrypt"],
"kty": "oct"
};
/////////////////////////////////////////////////////////////////
// Custom test substorage definition
......@@ -362,8 +368,7 @@
test("return substorage getattachment if not data url", function () {
var id = "/",
attachment = "stringattachment",
blob = new Blob(['foo'],
{type: 'application/x-jio-aes-gcm-encryption'});
blob = new Blob(['foo'], {type: 'application/x-jio-aes-gcm-encryption'});
Storage200.prototype.getAttachment = function (arg1, arg2) {
equal(arg1, id, "getAttachment 200 called");
......@@ -390,10 +395,12 @@
var id = "/",
attachment = "stringattachment",
value = "azertyuio\npàç_è-('é&",
tocheck = "data:application/x-jio-aes-gcm-encryption;base64" +
",+p/Ho+KgGHZC2zDLMbQQS2tXcsy0g+Ho41VZnlPEkXdmG9zm36c8iLCkv" +
"lanyWCN510NK4hj1EgWQ6WrLS5pCmA/yeAWh+HyfPkYKDRHVBl6+Hxd53I" +
"TmiWQ6Vix2jaIQg==",
tocheck = "data:application/x-jio-aes-gcm-encryption" +
";base64,2lHQ9xpJJ9qd81DxZEyd1LICtaV3XD+I2d5cp137L4NQC" +
"vdkasBaFkPUE5XiY88g5z0oN9dcDASfChmvgqrkDExKS+zVglvVVs" +
"CyECYorZ5fwgMCWAL5vUNCCaqhFVFyng==",
blob = jIO.util.dataURItoBlob(tocheck);
......@@ -427,6 +434,7 @@
});
});
/////////////////////////////////////////////////////////////////
// CryptStorage.putAttachment
/////////////////////////////////////////////////////////////////
......@@ -445,7 +453,7 @@
return new RSVP.Queue()
.push(function () {
return crypto.subtle.importKey("jwk", key,
return crypto.subtle.importKey("jwk", key_generated_by_password,
"AES-GCM", false, ["decrypt"]);
})
.push(function (res) {
......@@ -460,11 +468,10 @@
coded = coded.target.result;
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));
})
.push(function (arr) {
arr = String.fromCharCode.apply(null, new Uint8Array(arr));
equal(
arr,
......@@ -492,6 +499,7 @@
return decodeAES(arg3);
};
stop();
expect(7);
......
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