/* Copyright (C) 2013-2017 Grégory Soutadé This file is part of gPass. gPass is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. gPass is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with gPass. If not, see . */ var default_preferences = {"pbkdf2_level": 1000, "account_url": "https://gpass-demo.soutade.fr/demo"}; var browser = browser || chrome; var crypto = crypto || window.crypto; function notify(text, data) { browser.runtime.sendMessage({type: "notification", options:{"message":text}}); } // https://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers function ab2str(buf) { return String.fromCharCode.apply(null, new Uint8Array(buf)); } // https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String function str2ab2(str) { var chars = [] for (var i=0, strLen=str.length; i < strLen; i++) { chars.push(str.charCodeAt(i)); } return new Uint8Array(chars); } function str2ab(str) { var buf = new ArrayBuffer(str.length); // 2 bytes for each char // var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char var bufView = new Uint8Array(buf); for (var i=0, strLen=str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return bufView; } function returnResult(result) { return result;} function onError(error) { console.error(error); } function pbkdf2(mkey, salt, level) { debug("Process pbkdf2 with " + mkey); AESCBC = { name: "AES-CBC", length: 256, } level=1000; var key = str2ab(mkey); return crypto.subtle.importKey("raw", key, {name: "PBKDF2"}, false, ["deriveBits", "deriveKey"]) .then(function(key){ //sha-256 return crypto.subtle.deriveKey({ name: "PBKDF2", salt: str2ab(salt), iterations: level, hash: "SHA-256", }, key, AESCBC, false, ["encrypt", "decrypt", "unwrapKey", "wrapKey"]) .then(function(key) { return key; }) .catch(function(err){ console.log("Error derive key " + err); }); }) .catch(function(err) { console.log("Error import key" + err); }); } function _encrypt(mkey, data) { while ((data.length % 16)) data += "\0"; debug("Encrypt " + data); data = str2ab(data); nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); promise = mkey.then(function(mkey){ return crypto.subtle.encrypt({ name: "AES-CBC", iv: nulliv }, mkey, data)}) .then(function(encrypted) { return ab2str(encrypted); }) .catch(function(encryption) { console.log("Encryption rejected " + encryption); }); return promise; } async function _decrypt(mkey, data) { while ((data.length % 16)) data += "\0"; pkcs7_padding = new Uint8Array([16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]); pkcs7_padding = await _encrypt(mkey, ab2str(pkcs7_padding)); debug("Decrypt " + data); data = str2ab(data + pkcs7_padding); nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); promise = mkey.then(function(mkey){ return crypto.subtle.decrypt({ name: "AES-CBC", iv: nulliv }, mkey, data)}) .then(function(decrypted) { return ab2str(decrypted); }) .catch(function(decryption) { console.log("Decryption rejected " + decryption); }); return promise; } async function encrypt(mkey, data) { var result = ""; while (data.length > 16) { res = await _encrypt(mkey, data.slice(0, 16)); // Remove PKCS7 padding result += res.slice(0, 16); data = data.slice(16); } res = await _encrypt(mkey, data); result += res.slice(0, 16); return result; } async function decrypt(mkey, data) { var result = ""; while (data.length > 16) { res = await _decrypt(mkey, data.slice(0, 16)); // Remove PKCS7 padding result += res.slice(0, 16); data = data.slice(16); } res = await _decrypt(mkey, data); result += res.slice(0, 16); return result; }