/* 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", "crypto_v1_compatible": true}; var browser = browser || chrome; var crypto = crypto || window.crypto; function notify(text, data) { browser.runtime.sendMessage({type: "notification", options:{"message":text}}); } function block_url(url) { debug("Block URL " + url); browser.runtime.sendMessage({type: "block_url", options:{"url":url}}); } // 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); // 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 crypto_pbkdf2(mkey, salt, level) { AESCBC = { name: "AES-CBC", length: 256, } 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){ debug("Error derive key " + err); }); }) .catch(function(err) { debug("Error import key" + err); }); } function simple_pbkdf2(mkey, salt, level) { AESCBC = { name: "AES-CBC", length: 256, } 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, true, ["unwrapKey", "wrapKey"]) .then(function(key) { return crypto.subtle.exportKey("raw", key) .then(function (key) { return ab2str(key); }); }) .catch(function(err){ debug("Error derive key " + err); }); }) .catch(function(err) { debug("Error import key" + err); }); } function _encrypt(mkey, iv, data) { while ((data.length % 16)) data += "\0"; data = str2ab(data); promise = mkey.then(function(mkey){ return crypto.subtle.encrypt({ name: "AES-CBC", iv: iv }, mkey, data)}) .then(function(encrypted) { return ab2str(encrypted); }) .catch(function(encryption) { debug("Encryption rejected " + encryption); }); return promise; } async function _decrypt(mkey, iv, data) { while ((data.length % 16)) data += "\0"; nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, nulliv, ab2str(pkcs7_padding)); 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: iv }, mkey, data)}) .then(function(decrypted) { return ab2str(decrypted); }) .catch(function(decryption) { debug("Decryption rejected " + decryption); }); return promise; } async function encrypt_ecb(mkey, data) { var result = ""; debug("Encrypt ECB " + data); nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); while (data.length > 16) { res = await _encrypt(mkey, nulliv, data.slice(0, 16)); // Remove PKCS7 padding result += res.slice(0, 16); data = data.slice(16); } res = await _encrypt(mkey, nulliv, data); result += res.slice(0, 16); return result; } async function decrypt_ecb(mkey, data) { var result = ""; debug("Decrypt ECB " + data); nulliv = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); while (data.length > 16) { res = await _decrypt(mkey, nulliv, data.slice(0, 16)); // Remove PKCS7 padding result += res.slice(0, 16); data = data.slice(16); } res = await _decrypt(mkey, nulliv, data); result += res.slice(0, 16); return result; } async function encrypt_cbc(mkey, iv, data) { debug("Encrypt CBC " + data); var result = await _encrypt(mkey, str2ab(iv), data); // Remove PKCS7 padding return result.slice(0, result.length-16); } async function decrypt_cbc(mkey, iv, data) { debug("Decrypt CBC " + data); var result = await _decrypt(mkey, str2ab(iv), data); // Remove PKCS7 padding return result.slice(0, result.length-16); } async function digest(data) { return crypto.subtle.digest("SHA-256", str2ab(data)).then(function (hash) { return ab2str(hash); }); }