1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/url-classifier/content/moz/cryptohasher.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,175 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 + 1.9 +// A very thin wrapper around nsICryptoHash. It's not strictly 1.10 +// necessary, but makes the code a bit cleaner and gives us the 1.11 +// opportunity to verify that our implementations give the results that 1.12 +// we expect, for example if we have to interoperate with a server. 1.13 +// 1.14 +// The digest* methods reset the state of the hasher, so it's 1.15 +// necessary to call init() explicitly after them. 1.16 +// 1.17 +// Works only in Firefox 1.5+. 1.18 +// 1.19 +// IMPORTANT NOTE: Due to https://bugzilla.mozilla.org/show_bug.cgi?id=321024 1.20 +// you cannot use the cryptohasher before app-startup. The symptom of doing 1.21 +// so is a segfault in NSS. 1.22 + 1.23 +/** 1.24 + * Instantiate a new hasher. You must explicitly call init() before use! 1.25 + */ 1.26 +function G_CryptoHasher() { 1.27 + this.debugZone = "cryptohasher"; 1.28 + this.hasher_ = null; 1.29 +} 1.30 + 1.31 +G_CryptoHasher.algorithms = { 1.32 + MD2: Ci.nsICryptoHash.MD2, 1.33 + MD5: Ci.nsICryptoHash.MD5, 1.34 + SHA1: Ci.nsICryptoHash.SHA1, 1.35 + SHA256: Ci.nsICryptoHash.SHA256, 1.36 + SHA384: Ci.nsICryptoHash.SHA384, 1.37 + SHA512: Ci.nsICryptoHash.SHA512, 1.38 +}; 1.39 + 1.40 +/** 1.41 + * Initialize the hasher. This function must be called after every call 1.42 + * to one of the digest* methods. 1.43 + * 1.44 + * @param algorithm Constant from G_CryptoHasher.algorithms specifying the 1.45 + * algorithm this hasher will use 1.46 + */ 1.47 +G_CryptoHasher.prototype.init = function(algorithm) { 1.48 + var validAlgorithm = false; 1.49 + for (var alg in G_CryptoHasher.algorithms) 1.50 + if (algorithm == G_CryptoHasher.algorithms[alg]) 1.51 + validAlgorithm = true; 1.52 + 1.53 + if (!validAlgorithm) 1.54 + throw new Error("Invalid algorithm: " + algorithm); 1.55 + 1.56 + this.hasher_ = Cc["@mozilla.org/security/hash;1"] 1.57 + .createInstance(Ci.nsICryptoHash); 1.58 + this.hasher_.init(algorithm); 1.59 +} 1.60 + 1.61 +/** 1.62 + * Update the hash's internal state with input given in a string. Can be 1.63 + * called multiple times for incrementeal hash updates. 1.64 + * 1.65 + * @param input String containing data to hash. 1.66 + */ 1.67 +G_CryptoHasher.prototype.updateFromString = function(input) { 1.68 + if (!this.hasher_) 1.69 + throw new Error("You must initialize the hasher first!"); 1.70 + 1.71 + var stream = Cc['@mozilla.org/io/string-input-stream;1'] 1.72 + .createInstance(Ci.nsIStringInputStream); 1.73 + stream.setData(input, input.length); 1.74 + this.updateFromStream(stream); 1.75 +} 1.76 + 1.77 +/** 1.78 + * Update the hash's internal state with input given in an array. Can be 1.79 + * called multiple times for incremental hash updates. 1.80 + * 1.81 + * @param input Array containing data to hash. 1.82 + */ 1.83 +G_CryptoHasher.prototype.updateFromArray = function(input) { 1.84 + if (!this.hasher_) 1.85 + throw new Error("You must initialize the hasher first!"); 1.86 + 1.87 + this.hasher_.update(input, input.length); 1.88 +} 1.89 + 1.90 +/** 1.91 + * Update the hash's internal state with input given in a stream. Can be 1.92 + * called multiple times from incremental hash updates. 1.93 + */ 1.94 +G_CryptoHasher.prototype.updateFromStream = function(stream) { 1.95 + if (!this.hasher_) 1.96 + throw new Error("You must initialize the hasher first!"); 1.97 + 1.98 + if (stream.available()) 1.99 + this.hasher_.updateFromStream(stream, stream.available()); 1.100 +} 1.101 + 1.102 +/** 1.103 + * @returns The hash value as a string (sequence of 8-bit values) 1.104 + */ 1.105 +G_CryptoHasher.prototype.digestRaw = function() { 1.106 + var digest = this.hasher_.finish(false /* not b64 encoded */); 1.107 + this.hasher_ = null; 1.108 + return digest; 1.109 +} 1.110 + 1.111 +/** 1.112 + * @returns The hash value as a base64-encoded string 1.113 + */ 1.114 +G_CryptoHasher.prototype.digestBase64 = function() { 1.115 + var digest = this.hasher_.finish(true /* b64 encoded */); 1.116 + this.hasher_ = null; 1.117 + return digest; 1.118 +} 1.119 + 1.120 +/** 1.121 + * @returns The hash value as a hex-encoded string 1.122 + */ 1.123 +G_CryptoHasher.prototype.digestHex = function() { 1.124 + var raw = this.digestRaw(); 1.125 + return this.toHex_(raw); 1.126 +} 1.127 + 1.128 +/** 1.129 + * Converts a sequence of values to a hex-encoded string. The input is a 1.130 + * a string, so you can stick 16-bit values in each character. 1.131 + * 1.132 + * @param str String to conver to hex. (Often this is just a sequence of 1.133 + * 16-bit values) 1.134 + * 1.135 + * @returns String containing the hex representation of the input 1.136 + */ 1.137 +G_CryptoHasher.prototype.toHex_ = function(str) { 1.138 + var hexchars = '0123456789ABCDEF'; 1.139 + var hexrep = new Array(str.length * 2); 1.140 + 1.141 + for (var i = 0; i < str.length; ++i) { 1.142 + hexrep[i * 2] = hexchars.charAt((str.charCodeAt(i) >> 4) & 15); 1.143 + hexrep[i * 2 + 1] = hexchars.charAt(str.charCodeAt(i) & 15); 1.144 + } 1.145 + return hexrep.join(''); 1.146 +} 1.147 + 1.148 +#ifdef DEBUG 1.149 +/** 1.150 + * Lame unittest function 1.151 + */ 1.152 +function TEST_G_CryptoHasher() { 1.153 + if (G_GDEBUG) { 1.154 + var z = "cryptohasher UNITTEST"; 1.155 + G_debugService.enableZone(z); 1.156 + 1.157 + G_Debug(z, "Starting"); 1.158 + 1.159 + var md5 = function(str) { 1.160 + var hasher = new G_CryptoHasher(); 1.161 + hasher.init(G_CryptoHasher.algorithms.MD5); 1.162 + hasher.updateFromString(str); 1.163 + return hasher.digestHex().toLowerCase(); 1.164 + }; 1.165 + 1.166 + // test vectors from: http://www.faqs.org/rfcs/rfc1321.html 1.167 + var vectors = {"": "d41d8cd98f00b204e9800998ecf8427e", 1.168 + "a": "0cc175b9c0f1b6a831c399e269772661", 1.169 + "abc": "900150983cd24fb0d6963f7d28e17f72", 1.170 + "message digest": "f96b697d7cb7938d525a2f31aaf161d0", 1.171 + "abcdefghijklmnopqrstuvwxyz": "c3fcd3d76192e4007dfb496cca67e13b", 1.172 + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789": "d174ab98d277d9f5a5611c2c9f419d9f", 1.173 + "12345678901234567890123456789012345678901234567890123456789012345678901234567890": "57edf4a22be3c955ac49da2e2107b67a"}; 1.174 + 1.175 + G_Debug(z, "PASSED"); 1.176 + } 1.177 +} 1.178 +#endif