From cef1194ad0780c607ac77a650f71aebb2f357e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Mon, 17 Apr 2017 20:37:26 +0200 Subject: [PATCH] Add new encryption scheme in server part. --- server/_user | 3 +- server/conf.php | 7 + server/functions.php | 6 +- server/index.php | 1 + server/resources/gpass.js | 76 ++++++--- server/resources/hmac.js | 46 ------ server/resources/jsaes.js | 291 ----------------------------------- server/resources/jssha256.js | 261 ------------------------------- server/resources/misc.js | 88 +++++++++-- server/resources/pkdbf2.js | 51 ------ 10 files changed, 144 insertions(+), 686 deletions(-) delete mode 100644 server/resources/hmac.js delete mode 100644 server/resources/jsaes.js delete mode 100644 server/resources/jssha256.js delete mode 100644 server/resources/pkdbf2.js diff --git a/server/_user b/server/_user index ec1f3d5..10a1288 100644 --- a/server/_user +++ b/server/_user @@ -44,7 +44,7 @@ function load_database() // Brute force ?? $db->close(); return null; - } + } $db->query("UPDATE conf SET last_access_time=$usec"); $db->close(); $db = new SQLite3("./gpass.bdd", SQLITE3_OPEN_READONLY); @@ -79,6 +79,7 @@ for ($i=0; $i<$MAX_PASSWORDS_PER_REQUEST && isset($_POST["k$i"]); $i++) $result->finalize(); if (isset($row["password"])) { + echo "matched_key=" . $i . "\n"; echo "pass=" . $row["password"] . "\n"; break; } diff --git a/server/conf.php b/server/conf.php index cd8a9d4..ba7e75d 100644 --- a/server/conf.php +++ b/server/conf.php @@ -80,4 +80,11 @@ $REQUESTS_MIN_DELAY=1000; Clear master keys and reset passwords after 15 minutes of inactivity */ $CLEAR_TIME=15*60*1000; + +/* + The first crypto schema use an AES-ECB process to encrypt logins. + It's used until version 0.7. + Since version 0.8, we use AES-CBC + SHA256. + */ +$CRYPTO_V1_COMPATIBLE=1; ?> \ No newline at end of file diff --git a/server/functions.php b/server/functions.php index dfab88c..bff0b03 100755 --- a/server/functions.php +++ b/server/functions.php @@ -20,11 +20,13 @@ /* login is stored as : - @@url;login + url;login + 16 bytes padding * \0 + sha256(url;login + padding)[8:24] Password is salted (3 random characters) and encrypted - All is encrypted with AES256 and key : PKDBF2(hmac_sha256, master key, url, 1000) + All is encrypted with AES256-CBC and key PBKDF2(hmac_sha256, master key, server url, 1000) + level is server configurable + iv is PBKDF2(hmac_sha256, server url, master key, 1000)[0:16] */ $MAX_ENTRY_LEN = 512; $USERS_PATH = "./users/"; diff --git a/server/index.php b/server/index.php index abd4d83..d94dafd 100644 --- a/server/index.php +++ b/server/index.php @@ -79,6 +79,7 @@ else diff --git a/server/resources/gpass.js b/server/resources/gpass.js index 271958b..c3b6ea4 100755 --- a/server/resources/gpass.js +++ b/server/resources/gpass.js @@ -119,16 +119,18 @@ function a2hex(str) { return hex; } -function derive_mkey(user, mkey) +async function derive_mkey(user, mkey) { url = url_domain(document.URL) + "/" + user; - return pbkdf2(mkey, url, pbkdf2_level, 256/8); + global_iv = simple_pbkdf2(url, mkey, pbkdf2_level); + return crypto_pbkdf2(mkey, url, pbkdf2_level); } var passwords; var current_user = ""; var current_mkey = ""; var clearTimer = null; +var global_iv = null; function PasswordEntry (ciphered_login, ciphered_password, salt, shadow_login) { this.ciphered_login = ciphered_login; @@ -165,13 +167,19 @@ function PasswordEntry (ciphered_login, ciphered_password, salt, shadow_login) { if (masterkey == null || this.clear_url == "" || this.clear_login == "") return false; - ciphered_login = "@@" + this.clear_url + ";" + this.clear_login; + var ciphered_login = this.clear_url + ";" + this.clear_login; + while ((ciphered_login.length % 16)) + ciphered_login += "\0"; + var computed_hash = await digest(ciphered_login); + ciphered_login += computed_hash.slice(8, 24); + var iv = await global_iv; + iv = iv.slice(0, 16); // Add salt - ciphered_password = this.clear_password + generate_random(3, false); + var ciphered_password = generate_random(3, false) + this.clear_password ; - this.ciphered_login = a2hex(await encrypt(masterkey, ciphered_login)); - this.ciphered_password = a2hex(await encrypt(masterkey, ciphered_password)); + this.ciphered_login = a2hex(await encrypt_cbc(masterkey, iv, ciphered_login)); + this.ciphered_password = a2hex(await encrypt_cbc(masterkey, iv, ciphered_password)); this.unciphered = true; this.masterkey = masterkey; @@ -188,25 +196,53 @@ function PasswordEntry (ciphered_login, ciphered_password, salt, shadow_login) { if (masterkey == this.masterkey) return (this.unciphered == true); - login = await decrypt(masterkey, hex2a(this.ciphered_login)); - login = login.replace(/\0*$/, ""); - if (login.indexOf("@@") != 0) + var old = false; + var iv = await global_iv; + iv = iv.slice(0, 16); + var login = await decrypt_cbc(masterkey, iv, hex2a(this.ciphered_login)); + + var computed_digest = await digest(login.slice(0, login.length-16)) + computed_digest = computed_digest.slice(8, 24); + + if (login.indexOf(computed_digest) == login.length-16) { - return false; + login = login.slice(0, login.length-16).replace(/\0*$/, ""); } - // Remove @@ - login = login.substring(2); + else if (CRYPTO_V1_COMPATIBLE) + { + login = await decrypt_ecb(masterkey, hex2a(this.ciphered_login)); + if (login.indexOf("@@") != 0) + { + return false; + } + login = login.replace(/\0*$/, ""); + // Remove @@ + login = login.substring(2); + old = true; + } + else + return false; + infos = login.split(";"); this.clear_url = infos[0]; this.clear_login = infos[1]; - this.clear_password = await decrypt(masterkey, hex2a(this.ciphered_password)); + if (old) + { + this.clear_password = await decrypt_ecb(masterkey, hex2a(this.ciphered_password)); + // Remove salt + this.clear_password = this.clear_password.replace(/\0*$/, ""); + this.clear_password = this.clear_password.substr(0, this.clear_password.length-3); + } + else + { + this.clear_password = await decrypt_cbc(masterkey, iv, hex2a(this.ciphered_password)); + // Remove salt + this.clear_password = this.clear_password.replace(/\0*$/, ""); + this.clear_password = this.clear_password.substr(3, this.clear_password.length); + } this.unciphered = true; this.masterkey = masterkey; - // Remove salt - this.clear_password = this.clear_password.replace(/\0*$/, ""); - this.clear_password = this.clear_password.substr(0, this.clear_password.length-3); - return true; } @@ -222,7 +258,7 @@ function PasswordEntry (ciphered_login, ciphered_password, salt, shadow_login) { this.shadow_login_to_access_token = async function(masterkey) { - this.access_token = await encrypt(masterkey, hex2a(this.shadow_login)); + this.access_token = await encrypt_ecb(masterkey, hex2a(this.shadow_login)); this.access_token = a2hex(this.access_token); } @@ -857,11 +893,14 @@ async function update_masterkey() return; oldmkey = derive_mkey(current_user, oldmkey); + old_global_iv = global_iv; current_mkey = derive_mkey(current_user, newmkey); + new_global_iv = global_iv; var found = 0; for(i=0; i. -*/ - -function hmac256(key, message) { - var ipad = ""; - var opad = ""; - - if (key.length > 512/8) - { - key = digest256(key); - } - - for(i=0; i<512/8; i++) - { - if (i >= key.length) - { - ipad += String.fromCharCode(0x36); - opad += String.fromCharCode(0x5c); - } - else - { - ipad += String.fromCharCode(key.charCodeAt(i) ^ 0x36); - opad += String.fromCharCode(key.charCodeAt(i) ^ 0x5c); - } - } - - result = digest256(opad + digest256(ipad + message)); - - return result; -} diff --git a/server/resources/jsaes.js b/server/resources/jsaes.js deleted file mode 100644 index e340a81..0000000 --- a/server/resources/jsaes.js +++ /dev/null @@ -1,291 +0,0 @@ -/* - * jsaes version 0.1 - Copyright 2006 B. Poettering - * - * This program 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 2 of the - * License, or (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -/* - * http://point-at-infinity.org/jsaes/ - * - * This is a javascript implementation of the AES block cipher. Key lengths - * of 128, 192 and 256 bits are supported. - * - * The well-functioning of the encryption/decryption routines has been - * verified for different key lengths with the test vectors given in - * FIPS-197, Appendix C. - * - * The following code example enciphers the plaintext block '00 11 22 .. EE FF' - * with the 256 bit key '00 01 02 .. 1E 1F'. - * - * AES_Init(); - * - * var block = new Array(16); - * for(var i = 0; i < 16; i++) - * block[i] = 0x11 * i; - * - * var key = new Array(32); - * for(var i = 0; i < 32; i++) - * key[i] = i; - * - * AES_ExpandKey(key); - * AES_Encrypt(block, key); - * - * AES_Done(); - * - * Report bugs to: jsaes AT point-at-infinity.org - * - */ - -/******************************************************************************/ - -/* - AES_Init: initialize the tables needed at runtime. Call this function - before the (first) key expansion. -*/ - -function AES_Init() { - AES_Sbox_Inv = new Array(256); - for(var i = 0; i < 256; i++) - AES_Sbox_Inv[AES_Sbox[i]] = i; - - AES_ShiftRowTab_Inv = new Array(16); - for(var i = 0; i < 16; i++) - AES_ShiftRowTab_Inv[AES_ShiftRowTab[i]] = i; - - AES_xtime = new Array(256); - for(var i = 0; i < 128; i++) { - AES_xtime[i] = i << 1; - AES_xtime[128 + i] = (i << 1) ^ 0x1b; - } -} - -/* - AES_Done: release memory reserved by AES_Init. Call this function after - the last encryption/decryption operation. -*/ - -function AES_Done() { - delete AES_Sbox_Inv; - delete AES_ShiftRowTab_Inv; - delete AES_xtime; -} - -/* - AES_ExpandKey: expand a cipher key. Depending on the desired encryption - strength of 128, 192 or 256 bits 'key' has to be a byte array of length - 16, 24 or 32, respectively. The key expansion is done "in place", meaning - that the array 'key' is modified. -*/ - -function AES_ExpandKey(key) { - var kl = key.length, ks, Rcon = 1; - switch (kl) { - case 16: ks = 16 * (10 + 1); break; - case 24: ks = 16 * (12 + 1); break; - case 32: ks = 16 * (14 + 1); break; - default: - alert("AES_ExpandKey: Only key lengths of 16, 24 or 32 bytes allowed!"); - } - for(var i = kl; i < ks; i += 4) { - var temp = key.slice(i - 4, i); - if (i % kl == 0) { - temp = new Array(AES_Sbox[temp[1]] ^ Rcon, AES_Sbox[temp[2]], - AES_Sbox[temp[3]], AES_Sbox[temp[0]]); - if ((Rcon <<= 1) >= 256) - Rcon ^= 0x11b; - } - else if ((kl > 24) && (i % kl == 16)) - temp = new Array(AES_Sbox[temp[0]], AES_Sbox[temp[1]], - AES_Sbox[temp[2]], AES_Sbox[temp[3]]); - for(var j = 0; j < 4; j++) - key[i + j] = key[i + j - kl] ^ temp[j]; - } -} - -/* - AES_Encrypt: encrypt the 16 byte array 'block' with the previously - expanded key 'key'. -*/ - -function AES_Encrypt(block, key) { - var l = key.length; - AES_AddRoundKey(block, key.slice(0, 16)); - for(var i = 16; i < l - 16; i += 16) { - AES_SubBytes(block, AES_Sbox); - AES_ShiftRows(block, AES_ShiftRowTab); - AES_MixColumns(block); - AES_AddRoundKey(block, key.slice(i, i + 16)); - } - AES_SubBytes(block, AES_Sbox); - AES_ShiftRows(block, AES_ShiftRowTab); - AES_AddRoundKey(block, key.slice(i, l)); -} - -/* - AES_Decrypt: decrypt the 16 byte array 'block' with the previously - expanded key 'key'. -*/ - -function AES_Decrypt(block, key) { - var l = key.length; - AES_AddRoundKey(block, key.slice(l - 16, l)); - AES_ShiftRows(block, AES_ShiftRowTab_Inv); - AES_SubBytes(block, AES_Sbox_Inv); - for(var i = l - 32; i >= 16; i -= 16) { - AES_AddRoundKey(block, key.slice(i, i + 16)); - AES_MixColumns_Inv(block); - AES_ShiftRows(block, AES_ShiftRowTab_Inv); - AES_SubBytes(block, AES_Sbox_Inv); - } - AES_AddRoundKey(block, key.slice(0, 16)); -} - -/******************************************************************************/ - -/* The following lookup tables and functions are for internal use only! */ - -AES_Sbox = new Array(99,124,119,123,242,107,111,197,48,1,103,43,254,215,171, - 118,202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,183,253, - 147,38,54,63,247,204,52,165,229,241,113,216,49,21,4,199,35,195,24,150,5,154, - 7,18,128,226,235,39,178,117,9,131,44,26,27,110,90,160,82,59,214,179,41,227, - 47,132,83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,208,239,170, - 251,67,77,51,133,69,249,2,127,80,60,159,168,81,163,64,143,146,157,56,245, - 188,182,218,33,16,255,243,210,205,12,19,236,95,151,68,23,196,167,126,61, - 100,93,25,115,96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,224, - 50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,231,200,55,109,141,213, - 78,169,108,86,244,234,101,122,174,8,186,120,37,46,28,166,180,198,232,221, - 116,31,75,189,139,138,112,62,181,102,72,3,246,14,97,53,87,185,134,193,29, - 158,225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,140,161, - 137,13,191,230,66,104,65,153,45,15,176,84,187,22); - -AES_ShiftRowTab = new Array(0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11); - -function AES_SubBytes(state, sbox) { - for(var i = 0; i < 16; i++) - state[i] = sbox[state[i]]; -} - -function AES_AddRoundKey(state, rkey) { - for(var i = 0; i < 16; i++) - state[i] ^= rkey[i]; -} - -function AES_ShiftRows(state, shifttab) { - var h = new Array().concat(state); - for(var i = 0; i < 16; i++) - state[i] = h[shifttab[i]]; -} - -function AES_MixColumns(state) { - for(var i = 0; i < 16; i += 4) { - var s0 = state[i + 0], s1 = state[i + 1]; - var s2 = state[i + 2], s3 = state[i + 3]; - var h = s0 ^ s1 ^ s2 ^ s3; - state[i + 0] ^= h ^ AES_xtime[s0 ^ s1]; - state[i + 1] ^= h ^ AES_xtime[s1 ^ s2]; - state[i + 2] ^= h ^ AES_xtime[s2 ^ s3]; - state[i + 3] ^= h ^ AES_xtime[s3 ^ s0]; - } -} - -function AES_MixColumns_Inv(state) { - for(var i = 0; i < 16; i += 4) { - var s0 = state[i + 0], s1 = state[i + 1]; - var s2 = state[i + 2], s3 = state[i + 3]; - var h = s0 ^ s1 ^ s2 ^ s3; - var xh = AES_xtime[h]; - var h1 = AES_xtime[AES_xtime[xh ^ s0 ^ s2]] ^ h; - var h2 = AES_xtime[AES_xtime[xh ^ s1 ^ s3]] ^ h; - state[i + 0] ^= h1 ^ AES_xtime[s0 ^ s1]; - state[i + 1] ^= h2 ^ AES_xtime[s1 ^ s2]; - state[i + 2] ^= h1 ^ AES_xtime[s2 ^ s3]; - state[i + 3] ^= h2 ^ AES_xtime[s3 ^ s0]; - } -} - -function bin2String (array) { - var result = ""; - for (var i = 0; i < array.length; i++) { - result += String.fromCharCode(parseInt(array[i], 2)); - } - return result; -} - -function string2Bin (str) { - var result = []; - for (var i = 0; i < str.length; i++) { - result.push(str.charCodeAt(i)); - } - while ((result.length % 16)) - result.push(0); - return result; -} - -function bin2String (array) { - return String.fromCharCode.apply(String, array); -} - -// http://osama-oransa.blogspot.fr/2012/03/using-aes-encrypting-in-java-script.html -function AES(a) { - this.init = function (myKey){ - AES_Init(); - var key = string2Bin(myKey); - AES_ExpandKey(key); - return key; - } - - this.encrypt = function ( inputStr,key ) { - var block = string2Bin(inputStr); - AES_Encrypt(block, key); - var data=bin2String(block); - return data; - } - - this.decrypt = function ( inputStr,key ) { - block = string2Bin(inputStr); - AES_Decrypt(block, key); - var data=bin2String(block); - return data; - } - - this.encryptLongString = function( myString,key ) { - if(myString.length>16){ - var data=''; - for(var i=0;i16){ - var data=''; - for(var i=0;i -* -* NOTE: This version is not tested thoroughly! -* -* Copyright (c) 2003, Christoph Bichlmeier -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* 1. Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* 2. Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* 3. Neither the name of the copyright holder nor the names of contributors -* may be used to endorse or promote products derived from this software -* without specific prior written permission. -* -* ====================================================================== -* -* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS -* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* SHA256 logical functions */ -function rotateRight(n,x) { - return ((x >>> n) | (x << (32 - n))); -} -function choice(x,y,z) { - return ((x & y) ^ (~x & z)); -} -function majority(x,y,z) { - return ((x & y) ^ (x & z) ^ (y & z)); -} -function sha256_Sigma0(x) { - return (rotateRight(2, x) ^ rotateRight(13, x) ^ rotateRight(22, x)); -} -function sha256_Sigma1(x) { - return (rotateRight(6, x) ^ rotateRight(11, x) ^ rotateRight(25, x)); -} -function sha256_sigma0(x) { - return (rotateRight(7, x) ^ rotateRight(18, x) ^ (x >>> 3)); -} -function sha256_sigma1(x) { - return (rotateRight(17, x) ^ rotateRight(19, x) ^ (x >>> 10)); -} -function sha256_expand(W, j) { - return (W[j&0x0f] += sha256_sigma1(W[(j+14)&0x0f]) + W[(j+9)&0x0f] + -sha256_sigma0(W[(j+1)&0x0f])); -} - -/* Hash constant words K: */ -var K256 = new Array( - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -); - -/* global arrays */ -var ihash, count, buffer; -var sha256_hex_digits = "0123456789abcdef"; - -/* Add 32-bit integers with 16-bit operations (bug in some JS-interpreters: -overflow) */ -function safe_add(x, y) -{ - var lsw = (x & 0xffff) + (y & 0xffff); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return (msw << 16) | (lsw & 0xffff); -} - -/* Initialise the SHA256 computation */ -function sha256_init() { - ihash = new Array(8); - count = new Array(2); - buffer = new Array(64); - count[0] = count[1] = 0; - ihash[0] = 0x6a09e667; - ihash[1] = 0xbb67ae85; - ihash[2] = 0x3c6ef372; - ihash[3] = 0xa54ff53a; - ihash[4] = 0x510e527f; - ihash[5] = 0x9b05688c; - ihash[6] = 0x1f83d9ab; - ihash[7] = 0x5be0cd19; -} - -/* Transform a 512-bit message block */ -function sha256_transform() { - var a, b, c, d, e, f, g, h, T1, T2; - var W = new Array(16); - - /* Initialize registers with the previous intermediate value */ - a = ihash[0]; - b = ihash[1]; - c = ihash[2]; - d = ihash[3]; - e = ihash[4]; - f = ihash[5]; - g = ihash[6]; - h = ihash[7]; - - /* make 32-bit words */ - for(var i=0; i<16; i++) - W[i] = ((buffer[(i<<2)+3]) | (buffer[(i<<2)+2] << 8) | (buffer[(i<<2)+1] -<< 16) | (buffer[i<<2] << 24)); - - for(var j=0; j<64; j++) { - T1 = h + sha256_Sigma1(e) + choice(e, f, g) + K256[j]; - if(j < 16) T1 += W[j]; - else T1 += sha256_expand(W, j); - T2 = sha256_Sigma0(a) + majority(a, b, c); - h = g; - g = f; - f = e; - e = safe_add(d, T1); - d = c; - c = b; - b = a; - a = safe_add(T1, T2); - } - - /* Compute the current intermediate hash value */ - ihash[0] += a; - ihash[1] += b; - ihash[2] += c; - ihash[3] += d; - ihash[4] += e; - ihash[5] += f; - ihash[6] += g; - ihash[7] += h; -} - -/* Read the next chunk of data and update the SHA256 computation */ -function sha256_update(data, inputLen) { - var i, index, curpos = 0; - /* Compute number of bytes mod 64 */ - index = ((count[0] >> 3) & 0x3f); - var remainder = (inputLen & 0x3f); - - /* Update number of bits */ - if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++; - count[1] += (inputLen >> 29); - - /* Transform as many times as possible */ - for(i=0; i+63> 3) & 0x3f); - buffer[index++] = 0x80; - if(index <= 56) { - for(var i=index; i<56; i++) - buffer[i] = 0; - } else { - for(var i=index; i<64; i++) - buffer[i] = 0; - sha256_transform(); - for(var i=0; i<56; i++) - buffer[i] = 0; - } - buffer[56] = (count[1] >>> 24) & 0xff; - buffer[57] = (count[1] >>> 16) & 0xff; - buffer[58] = (count[1] >>> 8) & 0xff; - buffer[59] = count[1] & 0xff; - buffer[60] = (count[0] >>> 24) & 0xff; - buffer[61] = (count[0] >>> 16) & 0xff; - buffer[62] = (count[0] >>> 8) & 0xff; - buffer[63] = count[0] & 0xff; - sha256_transform(); -} - -/* Split the internal hash values into an array of bytes */ -function sha256_encode_bytes() { - var j=0; - var output = new Array(32); - for(var i=0; i<8; i++) { - output[j++] = ((ihash[i] >>> 24) & 0xff); - output[j++] = ((ihash[i] >>> 16) & 0xff); - output[j++] = ((ihash[i] >>> 8) & 0xff); - output[j++] = (ihash[i] & 0xff); - } - return output; -} - -/* Get the internal hash as a hex string */ -function sha256_encode_hex() { - var output = new String(); - for(var i=0; i<8; i++) { - for(var j=28; j>=0; j-=4) - output += sha256_hex_digits.charAt((ihash[i] >>> j) & 0x0f); - } - return output; -} - -/* Get the internal hash as string */ -function sha256_encode() { - var output = new String(); - for(var i=0; i<8; i++) { - for(var j=3; j>=0; j--) - output += String.fromCharCode((ihash[i] >>> j*8) & 0xff); - } - return output; -} - -/* Main function: returns a hex string representing the SHA256 value of the - given data */ -function digest256 (data) { - sha256_init(); - sha256_update(data, data.length); - sha256_final(); - return sha256_encode(); - // return sha256_encode_hex(); -} - -/* test if the JS-interpreter is working properly */ -function sha256_self_test() -{ - return sha256_digest("message digest") == -"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"; -} - - diff --git a/server/resources/misc.js b/server/resources/misc.js index 65310b1..866d2b6 100644 --- a/server/resources/misc.js +++ b/server/resources/misc.js @@ -47,7 +47,7 @@ function str2ab(str) { return bufView; } -function pbkdf2(mkey, salt, level) +function crypto_pbkdf2(mkey, salt, level) { AESCBC = { name: "AES-CBC", @@ -76,19 +76,49 @@ function pbkdf2(mkey, salt, level) }); } -function _encrypt(mkey, data) +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){ + console.log("Error derive key " + err); + }); + }) + .catch(function(err) { + console.log("Error import key" + err); + }); +} + +function _encrypt(mkey, iv, data) { while ((data.length % 16)) data += "\0"; 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 + iv: iv }, mkey, data)}) .then(function(encrypted) { return ab2str(encrypted); @@ -100,22 +130,21 @@ function _encrypt(mkey, data) return promise; } -async function _decrypt(mkey, data) +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, ab2str(pkcs7_padding)); + 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: nulliv + iv: iv }, mkey, data)}) .then(function(decrypted) { return ab2str(decrypted); @@ -127,36 +156,63 @@ async function _decrypt(mkey, data) return promise; } -async function encrypt(mkey, data) +async function encrypt_ecb(mkey, data) { var result = ""; + 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, data.slice(0, 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, data); + res = await _encrypt(mkey, nulliv, data); result += res.slice(0, 16); return result; } -async function decrypt(mkey, data) +async function decrypt_ecb(mkey, data) { var result = ""; + 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, data.slice(0, 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, data); + res = await _decrypt(mkey, nulliv, data); result += res.slice(0, 16); return result; } + +async function encrypt_cbc(mkey, iv, 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) +{ + 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); + }); +} diff --git a/server/resources/pkdbf2.js b/server/resources/pkdbf2.js deleted file mode 100644 index 278c4d2..0000000 --- a/server/resources/pkdbf2.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright (C) 2013 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 . -*/ - -function pkdbf2 (password, salt, iterations, outlen) { - var result = ""; - var temp = ""; - var temp2 = ""; - var temp_res = ""; - var temp_res2 = ""; - - for (i=1; result.length < outlen; i++) - { - temp = hmac256(password, salt + - String.fromCharCode((i & 0xff000000) >> 24) + - String.fromCharCode((i & 0x00ff0000) >> 16) + - String.fromCharCode((i & 0x0000ff00) >> 8) + - String.fromCharCode((i & 0x000000ff) >> 0) - ); - temp_res = temp; - - for(a=1; a