Add Chrome addon
This commit is contained in:
		
							
								
								
									
										17
									
								
								chrome_addon/background.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								chrome_addon/background.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
| 	} | ||||
|     }); | ||||
							
								
								
									
										
											BIN
										
									
								
								chrome_addon/gpass_icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								chrome_addon/gpass_icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										46
									
								
								chrome_addon/lib/hmac.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								chrome_addon/lib/hmac.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
|  | ||||
| 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; | ||||
| } | ||||
							
								
								
									
										291
									
								
								chrome_addon/lib/jsaes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								chrome_addon/lib/jsaes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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;i<myString.length;i=i+16){ | ||||
| 		data+=this.encrypt(myString.substr(i,16),key); | ||||
| 	    } | ||||
| 	    return data; | ||||
| 	}else{ | ||||
| 	    return this.encrypt(myString,key); | ||||
| 	} | ||||
|     }, | ||||
|  | ||||
|     decryptLongString : function ( myString,key ) { | ||||
| 	if(myString.length>16){ | ||||
| 	    var data=''; | ||||
| 	    for(var i=0;i<myString.length;i=i+16){ | ||||
| 		data+=this.decrypt(myString.substr(i,16),key); | ||||
| 	    } | ||||
| 	    return data; | ||||
| 	}else{ | ||||
| 	    return this.decrypt(myString,key); | ||||
| 	} | ||||
|     }, | ||||
|  | ||||
|     finish : function(){ | ||||
| 	AES_Done(); | ||||
|     }, | ||||
| }; | ||||
							
								
								
									
										261
									
								
								chrome_addon/lib/jssha256.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								chrome_addon/lib/jssha256.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,261 @@ | ||||
| /* | ||||
| * A JavaScript implementation of the SHA256 hash function. | ||||
| * | ||||
| * FILE:	sha256.js | ||||
| * VERSION:	0.8 | ||||
| * AUTHOR:	Christoph Bichlmeier <informatik@zombiearena.de> | ||||
| * | ||||
| * 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<inputLen; i+=64) { | ||||
|                 for(var j=index; j<64; j++) | ||||
| 			buffer[j] = data.charCodeAt(curpos++); | ||||
| 		sha256_transform(); | ||||
| 		index = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Buffer remaining input */ | ||||
| 	for(var j=0; j<remainder; j++) | ||||
| 		buffer[j] = data.charCodeAt(curpos++); | ||||
| } | ||||
|  | ||||
| /* Finish the computation by operations such as padding */ | ||||
| function sha256_final() { | ||||
| 	var index = ((count[0] >> 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"; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										388
									
								
								chrome_addon/lib/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								chrome_addon/lib/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
|  | ||||
| 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<logins.length; a++) | ||||
|     { | ||||
| 	enc = generate_request(domain, logins[a], mkey); | ||||
|  | ||||
| 	keys += (keys.length != 0) ? "&" : ""; | ||||
| 	keys += "k" + a + "=" + a2hex(enc); | ||||
|  | ||||
| 	if (wdomain != "") | ||||
| 	{ | ||||
| 	    enc = generate_request(wdomain, logins[a], mkey); | ||||
|  | ||||
| 	    keys += (keys.length != 0) ? "&" : ""; | ||||
| 	    keys += "k" + (b++) + "=" + a2hex(enc); | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     debug("Keys " + keys); | ||||
|  | ||||
|     var gPassRequest = new XMLHttpRequest(); | ||||
|  | ||||
|     var ret = SERVER.OK; | ||||
|  | ||||
|     // gPassRequest.addEventListener("progress", function(evt) { ; }, false); | ||||
|     gPassRequest.addEventListener("load", function(evt) {  | ||||
| 	var ciphered_password = ""; | ||||
| 	var server_pkdbf2_level = 0; | ||||
| 	var server_version = 0; | ||||
|  | ||||
| 	var r = this.responseText.split("\n"); | ||||
| 	debug("resp " + r); | ||||
|  | ||||
| 	for(var a=0; a<r.length; a++) | ||||
| 	{ | ||||
| 	    debug("Analyse " + r[a]); | ||||
|  | ||||
| 	    params = r[a].split("="); | ||||
| 	    if (params.length != 2 && params[0] != "<end>") | ||||
| 	    { | ||||
| 		notify("Error : It seems that it's not a gPass server", | ||||
| 		       this.responseText); | ||||
| 		ret = SERVER.FAILED; | ||||
| 		break; | ||||
| 	    } | ||||
|  | ||||
| 	    switch(params[0]) | ||||
| 	    { | ||||
| 	    case "protocol": | ||||
| 		debug("protocol : " + params[1]); | ||||
|  | ||||
| 		if (params[1].indexOf("gpass-") != 0) | ||||
| 		{ | ||||
| 		    notify("Error : It seems that it's not a gPass server", | ||||
| 			   this.responseText); | ||||
| 		    ret = SERVER.FAILED; | ||||
| 		    break; | ||||
| 		} | ||||
|  | ||||
| 		server_protocol_version = params[1].match(/\d+/)[0]; | ||||
| 		 | ||||
| 		if (server_protocol_version > 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 "<end>": | ||||
| 		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 <input type="text"> && <input type="email"> | ||||
|     for (var i=0; i<fields.length; i++) | ||||
|     { | ||||
| 	var field = fields[i]; | ||||
| 	if (field.getAttribute("type") == "text" || field.getAttribute("type") == "email") | ||||
| 	{ | ||||
| 	    if (field.hasAttribute("name") && field.value != "") | ||||
| 	    { | ||||
| 		name = field.getAttribute("name"); | ||||
| 		// Subset of common user field | ||||
| 		if      (name == "user")     user = field.value; | ||||
| 		else if (name == "usr")      user = field.value; | ||||
| 		else if (name == "username") user = field.value; | ||||
| 		else if (name == "login")    user = field.value; | ||||
| 		all_logins.push(field.value); | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     if (user != null) | ||||
| 	logins = new Array(user); | ||||
|     else | ||||
| 	logins = all_logins; | ||||
|  | ||||
|     // Look for <input type="password" value="@@..."> | ||||
|     for (var i=0; i<fields.length; i++) | ||||
|     { | ||||
| 	var field = fields[i]; | ||||
|  | ||||
| 	if (field.getAttribute("type") == "password") | ||||
| 	{ | ||||
| 	    debug(field.value); | ||||
| 	    password = field.value; | ||||
| 	    if (password.indexOf("@@") != 0 && password.indexOf("@_") != 0) | ||||
| 		continue; | ||||
|  | ||||
| 	    mkey = password.substring(2); | ||||
|  | ||||
| 	    e.preventDefault(); | ||||
|  | ||||
| 	    var ret = ask_server(form, field, logins, domain, wdomain, mkey, salt, (password.indexOf("@@") == 0)); | ||||
|  | ||||
| 	    switch(ret) | ||||
| 	    { | ||||
| 	    case SERVER.OK: | ||||
| 		break; | ||||
| 	    case SERVER.FAILED: | ||||
| 		if (logins !== all_logins) | ||||
| 		{ | ||||
| 		    ret = ask_server(form, field, all_logins, domain, wdomain, mkey, salt, (password.indexOf("@@") == 0)); | ||||
| 		    if (ret == SERVER.OK) | ||||
| 			break; | ||||
| 		} | ||||
| 		break; | ||||
| 	    case SERVER.RESTART_REQUEST: | ||||
| 		i = -1; // Restart loop | ||||
| 		break; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
| } | ||||
|  | ||||
| function document_loaded(doc) | ||||
| { | ||||
|     // If there is a password in the form, add a "submit" listener | ||||
|     for(var i=0; i<doc.forms.length; i++) | ||||
|     { | ||||
| 	var form = doc.forms[i]; | ||||
| 	var fields = form.getElementsByTagName("input"); | ||||
| 	for (a=0; a<fields.length; a++) | ||||
| 	{ | ||||
| 	    var field = fields[a]; | ||||
| 	    if (field.getAttribute("type") == "password") | ||||
| 	    { | ||||
| 		form.addEventListener("submit", on_sumbit); | ||||
| 		break; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| } | ||||
|  | ||||
| function init(prefs) | ||||
| { | ||||
|     for (k in prefs) | ||||
| 	preferences[k] = prefs[k]; | ||||
|     pkdbf2_level = getPref("pkdbf2_level"); | ||||
|     document_loaded(document); | ||||
| } | ||||
|  | ||||
| // First, load preferences | ||||
| chrome.storage.local.get(null, init); | ||||
|  | ||||
| function self_test() | ||||
| { | ||||
|     if((res = a2hex(pkdbf2("password", "salt", 4096, 256/8))) != | ||||
|        "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a") | ||||
| 	console.log("PKDBF2 failed " + res); | ||||
|     else | ||||
| 	console.log("All is OK ! "); | ||||
| } | ||||
|  | ||||
| // self_test(); | ||||
							
								
								
									
										32
									
								
								chrome_addon/lib/parseuri.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								chrome_addon/lib/parseuri.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // parseUri 1.2.2 | ||||
| // (c) Steven Levithan <stevenlevithan.com> | ||||
| // 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; | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										51
									
								
								chrome_addon/lib/pkdbf2.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								chrome_addon/lib/pkdbf2.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <http://www.gnu.org/licenses/>. | ||||
| */ | ||||
|  | ||||
| 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<iterations; a++) | ||||
| 	{ | ||||
| 	    temp2 = hmac256(password, temp); | ||||
| 	    temp_res2 = ""; | ||||
| 	    for(b = 0; b<temp_res.length; b++) | ||||
| 		temp_res2 += String.fromCharCode(temp_res.charCodeAt(b) ^ temp2.charCodeAt(b)); | ||||
| 	    temp_res = temp_res2; | ||||
| 	    temp = temp2; | ||||
| 	} | ||||
|  | ||||
| 	result += temp_res; | ||||
|     } | ||||
|  | ||||
|     return result.substr(0, outlen); | ||||
| } | ||||
							
								
								
									
										30
									
								
								chrome_addon/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								chrome_addon/manifest.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| { | ||||
|     "manifest_version": 2, | ||||
|  | ||||
|     "name": "gpass", | ||||
|     "version": "0.6", | ||||
|     "description": "gPass : global password manager", | ||||
|  | ||||
|     "content_scripts": [ | ||||
| 	{ | ||||
| 	    "matches": ["https://*/*", "http://*/*"], | ||||
| 	    "js": ["lib/parseuri.js", "lib/jsaes.js", "lib/jssha256.js", "lib/hmac.js", "lib/pkdbf2.js", "lib/main.js"], | ||||
| 	    "run_at" : "document_idle", | ||||
| 	    "all_frames" : true | ||||
| 	} | ||||
|     ], | ||||
|  | ||||
|     "background": { | ||||
| 	"persistent": false, | ||||
| 	"scripts": ["background.js"] | ||||
|     }, | ||||
|  | ||||
|     "options_page": "options.html", | ||||
|  | ||||
|     "permissions": [ | ||||
| 	"https://*/", | ||||
| 	"http://*/", | ||||
| 	"notifications", | ||||
| 	"storage" | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										18
									
								
								chrome_addon/options.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								chrome_addon/options.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|   <head> | ||||
|     <title>gPass</title> | ||||
|   </head> | ||||
|   <body> | ||||
|  | ||||
|     <b>Account URL</b> URL of your gPass account <input id="account_url" type="text"/><br /> | ||||
|     <b>WARNING</b> 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.<br/> | ||||
|     <br/> | ||||
|     <b>PKDBF2 level</b> Number of iterations used to derivate master key <input id="pkdbf2" type="number"/><br /> | ||||
|     <br/> | ||||
|     <input type="button" id="save" value="Save"/> | ||||
|  | ||||
|     <script type="text/javascript" src="options.js"> | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
							
								
								
									
										31
									
								
								chrome_addon/options.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								chrome_addon/options.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
		Reference in New Issue
	
	Block a user