Use firefox integrated HMAC function
Correct bad PKDBF2 implementation New protocol version is 2
This commit is contained in:
		| @@ -1,42 +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 <http://www.gnu.org/licenses/>. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| var sha256 = require("jssha256").sha256; |  | ||||||
|  |  | ||||||
| exports.hmac = { |  | ||||||
|     hmac : function(key, message) { |  | ||||||
| 	var ipad = ""; |  | ||||||
| 	var opad = ""; |  | ||||||
|  |  | ||||||
| 	for(i=0; i<key.length; i++) |  | ||||||
| 	{ |  | ||||||
| 	    ipad += String.fromCharCode(key.charCodeAt(i) ^ 0x36); |  | ||||||
| 	    opad += String.fromCharCode(key.charCodeAt(i) ^ 0x5c); |  | ||||||
| 	} |  | ||||||
| 	while (ipad.length < 512/8) |  | ||||||
| 	{ |  | ||||||
| 	    ipad += String.fromCharCode(0x36); |  | ||||||
| 	    opad += String.fromCharCode(0x5c); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	result = sha256.digest(opad + sha256.digest(ipad + message)); |  | ||||||
|  |  | ||||||
| 	return result; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| @@ -1,252 +0,0 @@ | |||||||
| /* |  | ||||||
| * 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; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* Main function: returns a hex string representing the SHA256 value of the  |  | ||||||
| given data */ |  | ||||||
| exports.sha256 = { |  | ||||||
|     digest : function (data) { |  | ||||||
| 	sha256_init(); |  | ||||||
| 	sha256_update(data, data.length); |  | ||||||
| 	sha256_final(); |  | ||||||
|         return sha256_encode_hex(); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /* test if the JS-interpreter is working properly */ |  | ||||||
| function sha256_self_test() |  | ||||||
| { |  | ||||||
| 	return sha256_digest("message digest") ==  |  | ||||||
| "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -130,7 +130,7 @@ function on_sumbit(e) | |||||||
| 	    	r = this.responseText.split("\n"); | 	    	r = this.responseText.split("\n"); | ||||||
| 		debug("resp " + r); | 		debug("resp " + r); | ||||||
| 		protocol = r[0].split("="); | 		protocol = r[0].split("="); | ||||||
| 		if ((protocol.length == 2 && protocol[1] != "1" && protocol[1] != "gpass-1") || protocol.length != 2) | 		if ((protocol.length == 2 && protocol[1] != "gpass-2") || protocol.length != 2) | ||||||
| 		{ | 		{ | ||||||
| 		    ret = false; | 		    ret = false; | ||||||
| 		    if (protocol.length == 2 && protocol[1].startsWith("gpass")) | 		    if (protocol.length == 2 && protocol[1].startsWith("gpass")) | ||||||
| @@ -236,3 +236,15 @@ var httpRequestObserver = | |||||||
|  |  | ||||||
| var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); | var observerService = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); | ||||||
| observerService.addObserver(httpRequestObserver, "content-document-global-created", false); | observerService.addObserver(httpRequestObserver, "content-document-global-created", false); | ||||||
|  |  | ||||||
|  | function self_test() | ||||||
|  | { | ||||||
|  |     if((res = a2hex(hmac256("Jefe", "what do ya want for nothing?"))) != | ||||||
|  |        "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843") | ||||||
|  | 	console.log("HMAC256 failed " + res); | ||||||
|  |     if((res = a2hex(pkdbf2.pkdbf2("password", "salt", 4096, 256/8))) != | ||||||
|  |        "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a") | ||||||
|  | 	console.log("PKDBF2 failed " + res); | ||||||
|  |     else | ||||||
|  | 	console.log("All is OK ! " + mkey); | ||||||
|  | } | ||||||
| @@ -17,17 +17,30 @@ | |||||||
|   along with gPass.  If not, see <http://www.gnu.org/licenses/>. |   along with gPass.  If not, see <http://www.gnu.org/licenses/>. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| var hmac256 = require("hmac").hmac; | var {Cc, Ci} = require("chrome"); | ||||||
|  |  | ||||||
| // http://stackoverflow.com/questions/3745666/how-to-convert-from-hex-to-ascii-in-javascript | var hmac = Cc["@mozilla.org/security/hmac;1"] | ||||||
| function hex2a(hex) { |     .createInstance(Ci.nsICryptoHMAC); | ||||||
|     var str = ''; |  | ||||||
|     for (var i = 0; i < hex.length; i += 2) | function hmac_init(key) { | ||||||
|         str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); |     var keyObject = Cc["@mozilla.org/security/keyobjectfactory;1"] | ||||||
|     return str; |                 .getService(Ci.nsIKeyObjectFactory) | ||||||
|  |                 .keyFromString(Ci.nsIKeyObject.HMAC, key); | ||||||
|  |     hmac.init(hmac.SHA256, keyObject); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function hmac_digest(message) { | ||||||
|  |     var data = new Uint8Array(message.length); | ||||||
|  |     for(i=0; i<message.length; i++) | ||||||
|  | 	data[i] = message.charCodeAt(i); | ||||||
|  |     hmac.update(data, data.length); | ||||||
|  |     res = hmac.finish(false); | ||||||
|  |     hmac.reset(); | ||||||
|  |     return res; | ||||||
| } | } | ||||||
|  |  | ||||||
| exports.pkdbf2 = { | exports.pkdbf2 = { | ||||||
|  |      | ||||||
|     pkdbf2 : function(password, salt, iterations, outlen) { |     pkdbf2 : function(password, salt, iterations, outlen) { | ||||||
| 	var result = ""; | 	var result = ""; | ||||||
| 	var temp = ""; | 	var temp = ""; | ||||||
| @@ -35,19 +48,20 @@ exports.pkdbf2 = { | |||||||
| 	var temp_res = ""; | 	var temp_res = ""; | ||||||
| 	var temp_res2 = ""; | 	var temp_res2 = ""; | ||||||
| 	     | 	     | ||||||
|  | 	hmac_init(password); | ||||||
| 	for (i=1; result.length < outlen; i++) | 	for (i=1; result.length < outlen; i++) | ||||||
| 	{ | 	{ | ||||||
| 	    temp = hex2a(hmac256.hmac(salt +  | 	    temp = hmac_digest(salt +  | ||||||
| 	    		       String.fromCharCode((i & 0xff000000) >> 24) + | 	    		       String.fromCharCode((i & 0xff000000) >> 24) + | ||||||
| 	    		       String.fromCharCode((i & 0x00ff0000) >> 16) + | 	    		       String.fromCharCode((i & 0x00ff0000) >> 16) + | ||||||
| 	    		       String.fromCharCode((i & 0x0000ff00) >>  8) + | 	    		       String.fromCharCode((i & 0x0000ff00) >>  8) + | ||||||
| 				String.fromCharCode((i & 0x000000ff) >>  0), | 	    		       String.fromCharCode((i & 0x000000ff) >>  0) | ||||||
| 				      password)); | 			      ); | ||||||
| 	    temp_res = temp; | 	    temp_res = temp; | ||||||
| 	     | 	     | ||||||
| 	    for(a=1; a<iterations; a++) | 	    for(a=1; a<iterations; a++) | ||||||
| 	    { | 	    { | ||||||
| 		temp2 = hex2a(hmac256.hmac(temp, password)); | 		temp2 = hmac_digest(temp); | ||||||
| 		temp_res2 = ""; | 		temp_res2 = ""; | ||||||
| 		for(b = 0; b<temp_res.length; b++) | 		for(b = 0; b<temp_res.length; b++) | ||||||
| 		    temp_res2 += String.fromCharCode(temp_res.charCodeAt(b) ^ temp2.charCodeAt(b)); | 		    temp_res2 += String.fromCharCode(temp_res.charCodeAt(b) ^ temp2.charCodeAt(b)); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user