From d395807c98da774dface949756ac4930ec4ef207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Tue, 27 Jan 2015 21:10:55 +0100 Subject: [PATCH] Add Chrome addon --- chrome_addon/background.js | 17 ++ chrome_addon/gpass_icon.png | Bin 0 -> 2125 bytes chrome_addon/lib/hmac.js | 46 +++++ chrome_addon/lib/jsaes.js | 291 ++++++++++++++++++++++++++ chrome_addon/lib/jssha256.js | 261 +++++++++++++++++++++++ chrome_addon/lib/main.js | 388 +++++++++++++++++++++++++++++++++++ chrome_addon/lib/parseuri.js | 32 +++ chrome_addon/lib/pkdbf2.js | 51 +++++ chrome_addon/manifest.json | 30 +++ chrome_addon/options.html | 18 ++ chrome_addon/options.js | 31 +++ 11 files changed, 1165 insertions(+) create mode 100644 chrome_addon/background.js create mode 100644 chrome_addon/gpass_icon.png create mode 100644 chrome_addon/lib/hmac.js create mode 100644 chrome_addon/lib/jsaes.js create mode 100644 chrome_addon/lib/jssha256.js create mode 100644 chrome_addon/lib/main.js create mode 100644 chrome_addon/lib/parseuri.js create mode 100644 chrome_addon/lib/pkdbf2.js create mode 100644 chrome_addon/manifest.json create mode 100644 chrome_addon/options.html create mode 100644 chrome_addon/options.js diff --git a/chrome_addon/background.js b/chrome_addon/background.js new file mode 100644 index 0000000..aff02cb --- /dev/null +++ b/chrome_addon/background.js @@ -0,0 +1,17 @@ +chrome.runtime.onMessage.addListener( + function(request, sender, sendResponse) { + + if (request.type == "notification") + { + options = { + type: "basic", + title : "gPass", + message : request.options.message, + iconUrl:chrome.extension.getURL("gpass_icon.png") + }; + + chrome.notifications.create("gPass", options, function(){}); + + window.setTimeout(function() {chrome.notifications.clear("gPass", function(){})}, 2000); + } + }); diff --git a/chrome_addon/gpass_icon.png b/chrome_addon/gpass_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d78a7b3b8c5e443b1c60f6d99081ccd8a865d141 GIT binary patch literal 2125 zcmV-T2(tHyP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00*^6L_t(|+U;9yP*m3$e$Kh~ zvI~o_EP_$0g83j0m>BD1(l(k}of-|1nU1Ob$kH_821x}91IKt?9d zb31ty*Fx|OW`k%nJetPg^`=77#JaHtprC*+nGyi>dF5rVE~8X4!|an|uH=-R$Uz8f(lJgXIB^O%J!A-r@Bzxblv-au{&O-oLu>$zYxAvfSpb-FrkbV>`|09+b(}c}_O|^N=;Y7uh z03evq^L4e>RTf3G3U5zAcJ|PBRRtC-P{-{9hWrH3&>-ZWDvYhaFAH3}o}AT00#N;~ z^&#iJAH7!Q+EuVnQN$=21f(Q@h0oiv#)rQGKm)_>eY$vkSKy)QDr^7s=A2Ll06^6- z>-BZ3`?s8H7IG{T6a`?A2z5gGlMir3ul2q8$TtQv60!M&GXMbAm1yk9 zLG$G$w|US0;hprCR@|o*W@IuB0GtD00sw&skdnm|xt<;hbal$M(;tfVg9nVNxAz&l z0kkDD--H8j0t_s~0E*uQ7=t=1D4=#O0W)Ov6dq>4 zkS}2I?5^UrI{-q!9P0yyg^n0v-FhGhMo0>1UN7060Vah201G<7_*U54M^wJoc&qV@IB#zN3=A`XBQy(yx&V)O@}>#w z_?3S6H#_xblAT}D0Wb_Qg41wN2P8swA{3znIDiYS65C(U-@qh9@&O2h84v;>JRY-% zmnVgV9LK6Ne!ad#d&Kqt1avtH0ELU;fhd{=5P-YxQnDX^()m`R=RKZEFC0zR>_E!4imPg$I3v<|c6#z@W_mpwSE%Q3A1^2atr>*(qCX zuK|OD(g*{9xKrHwU!Owd>#0DxHBarmQd>S#DEPup4qfiXT{#DmaiK0pbIU`K~+cxS)Snat$W z$p%2-0xU?0NE)C3sI9YbzDXRYIc~iSz-xN|Xp|3-!%c0h4^RR8?U;p{Cf=VYyQj0T!hV3INNNsQBU5)PH{e z3C9)y?rFh*fIhMfQg{}K&;|_d67h}F5CWA)&5r8h#?MZ^pFAr(8Ew!q&9DXp0DO5p!@@-^ zu%ax_0W`Nr^Of!TmgALHqun*Y*W4sX8!^!`1}t8zBHAmp{R4#WJUZ~)Uyhg+m?n|8 zbC;{tCq1OccqLvZ5B2IMOyh7p{-kqz zYloYx2!Dup?YFKPFyvsm$Fk+h_fDP8BoW-aMIPE)k$xG#JlrTTXD%;!_wO0~KIx%D zM>D(t3UQ;w-S?;~%67XBdpztO+`!?)Ow7bg{J-LVb~4s|9m$*800000NkvXXu0mjf Dp$XKG literal 0 HcmV?d00001 diff --git a/chrome_addon/lib/hmac.js b/chrome_addon/lib/hmac.js new file mode 100644 index 0000000..e8af667 --- /dev/null +++ b/chrome_addon/lib/hmac.js @@ -0,0 +1,46 @@ +/* + 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 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/chrome_addon/lib/jsaes.js b/chrome_addon/lib/jsaes.js new file mode 100644 index 0000000..5bc5d38 --- /dev/null +++ b/chrome_addon/lib/jsaes.js @@ -0,0 +1,291 @@ +/* + * 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 +aes = { + init : function (myKey){ + AES_Init(); + var key = string2Bin(myKey); + AES_ExpandKey(key); + return key; + }, + + encrypt : function ( inputStr,key ) { + var block = string2Bin(inputStr); + AES_Encrypt(block, key); + var data=bin2String(block); + return data; + }, + + decrypt : function ( inputStr,key ) { + block = string2Bin(inputStr); + AES_Decrypt(block, key); + var data=bin2String(block); + return data; + }, + + 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/chrome_addon/lib/main.js b/chrome_addon/lib/main.js new file mode 100644 index 0000000..9383dd0 --- /dev/null +++ b/chrome_addon/lib/main.js @@ -0,0 +1,388 @@ +/* + Copyright (C) 2013-2014 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 DEBUG = false; +var default_preferences = {"pkdbf2_level": 1000, + "account_url": "http://gpass-demo.soutade.fr/demo"}; +var preferences = {}; +var protocol_version = 3; +var pkdbf2_level; + +SERVER = {OK : 0, FAILED : 1, RESTART_REQUEST : 2}; + +// http://stackoverflow.com/questions/3745666/how-to-convert-from-hex-to-ascii-in-javascript +function hex2a(hex) { + var str = ''; + for (var i = 0; i < hex.length; i += 2) + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + return str; +} + +function a2hex(str) { + var hex = ''; + for (var i = 0; i < str.length; i++) + { + var c = str.charCodeAt(i).toString(16); + if (c.length == 1) c = "0" + c; + hex += c; + } + return hex; +} + +function debug(s) +{ + if (DEBUG) + console.log(s); +} + +function notify(text, data) +{ + chrome.extension.sendMessage({type: "notification", options:{"message":text}}, function(response){alert(response);}); +} + +function getPref(key) +{ + if (key in preferences) + return preferences[key]; + else + return default_preferences[key]; +} + +function setPref(key, value) +{ + chrome.storage.local.set({key:value}, null); +} + +function generate_request(domain, login, mkey) +{ + var v = "@@" + domain + ";" + login; + debug("will encrypt " + v); + debug("with " + a2hex(mkey)); + var enc = aes.encryptLongString(v, aes.init(mkey)); + aes.finish(); + debug("res " + a2hex(enc)); + + return enc; +} + +function ask_server(form, field, logins, domain, wdomain, mkey, salt, submit) +{ + var a, b; + + mkey = pkdbf2(mkey, salt, pkdbf2_level, 256/8); + + keys = ""; + for(a=0, b=logins.length; a protocol_version) + { + notify("Protocol version not supported, please upgrade your addon", + "Protocol version not supported, please upgrade your addon"); + ret = SERVER.FAILED; + } + else + { + switch (server_protocol_version) + { + case 2: + server_pkdbf2_level = 1000; + break; + case 3: + // Version 3 : nothing special to do + break; + } + } + break; + case "pass": + ciphered_password = params[1]; + break; + case "pkdbf2_level": + server_pkdbf2_level = parseInt(params[1].match(/\d+/)[0], 10); + if (server_pkdbf2_level != NaN && + server_pkdbf2_level != pkdbf2_level && + server_pkdbf2_level >= 1000) // Minimum level for PKDBF2 ! + { + debug("New pkdbf2 level " + server_pkdbf2_level); + pkdbf2_level = server_pkdbf2_level; + setPref("pkdbf2_level", pkdbf2_level); + ret = SERVER.RESTART_REQUEST; + } + break; + case "": + break; + default: + debug("Unknown command " + params[0]); + + notify("Error : It seems that it's not a gPass server", + this.responseText); + ret = SERVER.FAILED; + break; + } + } + + if (ret != SERVER.OK) + return; + + if (ciphered_password != "") + { + debug("Ciphered password : " + ciphered_password); + clear_password = aes.decryptLongString(hex2a(ciphered_password), aes.init(mkey)); + aes.finish(); + // Remove trailing \0 and salt + clear_password = clear_password.replace(/\0*$/, ""); + clear_password = clear_password.substr(0, clear_password.length-3); + debug("Clear password " + clear_password); + field.value = clear_password; + // Remove gPass event listener and submit again with clear password + if (submit) + { + form.removeEventListener("submit", on_sumbit, true); + form.submit(); + } + else + { + notify("Password successfully replaced", + "Password successfully replaced"); + } + } + else + { + debug("No password found"); + + ret = SERVER.FAILED; + + notify("No password found in database", + "No password found in database"); + } + }, false); + gPassRequest.addEventListener("error", function(evt) { + debug("error"); + ret = false; + notify("Error", + "Error"); + }, false); + debug("connect to " + getPref("account_url")); + gPassRequest.open("POST", getPref("account_url"), true); + gPassRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); + gPassRequest.send(keys); + + return ret; +} + +function wildcard_domain(domain) +{ + var parts = domain.split("."); + + if (parts.length >= 3) + { + // Seems to be a two level root domain (ie zzz.xxx.co.uk ...) + if (parts[parts.length-2].lenght <= 3) + { + if (parts.length > 3) + return "*" + "." + parts[parts.length-3] + "." + parts[parts.length-2] + "." + parts[parts.length-1]; + } + // Standard root domain (zzz.xxx.com) + else + return "*" + "." + parts[parts.length-2] + "." + parts[parts.length-1]; + } + // Simple xxx.com + else if (parts.length == 2) + return "*" + "." + parts[0] + "." + parts[1]; + + return ""; +} + +function on_sumbit(e) +{ + var form = this; + var fields = form.getElementsByTagName("input"); + + var domain = parseURI.parseUri(form.ownerDocument.baseURI); + domain = domain["host"]; + var wdomain = wildcard_domain(domain); + + var salt = parseURI.parseUri(getPref("account_url")); + salt = salt["host"] + salt["path"]; + + debug("salt " + salt); + + var user = null; + var all_logins = new Array(); + + // Get all && + for (var i=0; i + for (var i=0; i +// MIT License + +parseURI = { + + parseUri : function (str) { + var o = { + strictMode: false, + key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + }}, + m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), + uri = {}, + i = 14; + + while (i--) uri[o.key[i]] = m[i] || ""; + + uri[o.q.name] = {}; + uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { + if ($1) uri[o.q.name][$1] = $2; + }); + + return uri; + } +}; diff --git a/chrome_addon/lib/pkdbf2.js b/chrome_addon/lib/pkdbf2.js new file mode 100644 index 0000000..278c4d2 --- /dev/null +++ b/chrome_addon/lib/pkdbf2.js @@ -0,0 +1,51 @@ +/* + 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 + + + gPass + + + + Account URL URL of your gPass account
+ WARNING It should be a valid HTTPS URL because doesn't like mixed content (https/http) with a recognized certificate. Of not, requests will silentely failed. If you have an auto-signed certificate, add it to trusted ones.
+
+ PKDBF2 level Number of iterations used to derivate master key
+
+ + + + + diff --git a/chrome_addon/options.js b/chrome_addon/options.js new file mode 100644 index 0000000..381e756 --- /dev/null +++ b/chrome_addon/options.js @@ -0,0 +1,31 @@ +var default_preferences = {"pkdbf2_level": 1000, + "account_url": "http://gpass-demo.soutade.fr/demo"}; + +function save() { + var account_url = document.getElementById('account_url').value; + var pkdbf2 = document.getElementById('pkdbf2').value; + + chrome.storage.local.set({ + 'account_url': account_url, + 'pkdbf2': pkdbf2, + }, function() { + alert('Saved'); + }); +} + +chrome.storage.local.get(null, function(prefs) { + if (!prefs.hasOwnProperty("account_url")) + account_url = default_preferences['account_url']; + else + account_url = prefs['account_url']; + + if (!prefs.hasOwnProperty("pkdbf2_level")) + pkdbf2 = default_preferences['pkdbf2_level']; + else + pkdbf2 = prefs['pkdbf2_level']; + + document.getElementById('account_url').value = account_url; + document.getElementById('pkdbf2').value = pkdbf2; +}); + +document.getElementById('save').addEventListener("click", save);