Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / toolkit / components / url-classifier / content / moz / cryptohasher.js
blob692c09262e041fec7ee65d9cef2cddefcd06a99a
1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
12 # License.
14 # The Original Code is Google Safe Browsing.
16 # The Initial Developer of the Original Code is Google Inc.
17 # Portions created by the Initial Developer are Copyright (C) 2006
18 # the Initial Developer. All Rights Reserved.
20 # Contributor(s):
21 #   Fritz Schneider <fritz@google.com> (original author)
23 # Alternatively, the contents of this file may be used under the terms of
24 # either the GNU General Public License Version 2 or later (the "GPL"), or
25 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 # in which case the provisions of the GPL or the LGPL are applicable instead
27 # of those above. If you wish to allow use of your version of this file only
28 # under the terms of either the GPL or the LGPL, and not to allow others to
29 # use your version of this file under the terms of the MPL, indicate your
30 # decision by deleting the provisions above and replace them with the notice
31 # and other provisions required by the GPL or the LGPL. If you do not delete
32 # the provisions above, a recipient may use your version of this file under
33 # the terms of any one of the MPL, the GPL or the LGPL.
35 # ***** END LICENSE BLOCK *****
38 // A very thin wrapper around nsICryptoHash. It's not strictly
39 // necessary, but makes the code a bit cleaner and gives us the
40 // opportunity to verify that our implementations give the results that
41 // we expect, for example if we have to interoperate with a server.
43 // The digest* methods reset the state of the hasher, so it's
44 // necessary to call init() explicitly after them.
46 // Works only in Firefox 1.5+.
48 // IMPORTANT NOTE: Due to https://bugzilla.mozilla.org/show_bug.cgi?id=321024
49 // you cannot use the cryptohasher before app-startup. The symptom of doing
50 // so is a segfault in NSS.
52 /**
53  * Instantiate a new hasher. You must explicitly call init() before use!
54  */
55 function G_CryptoHasher() {
56   this.debugZone = "cryptohasher";
57   this.hasher_ = null;
60 G_CryptoHasher.algorithms = {
61   MD2: Ci.nsICryptoHash.MD2,
62   MD5: Ci.nsICryptoHash.MD5,
63   SHA1: Ci.nsICryptoHash.SHA1,
64   SHA256: Ci.nsICryptoHash.SHA256,
65   SHA384: Ci.nsICryptoHash.SHA384,
66   SHA512: Ci.nsICryptoHash.SHA512,
69 /**
70  * Initialize the hasher. This function must be called after every call
71  * to one of the digest* methods.
72  *
73  * @param algorithm Constant from G_CryptoHasher.algorithms specifying the
74  *                  algorithm this hasher will use
75  */ 
76 G_CryptoHasher.prototype.init = function(algorithm) {
77   var validAlgorithm = false;
78   for (var alg in G_CryptoHasher.algorithms)
79     if (algorithm == G_CryptoHasher.algorithms[alg])
80       validAlgorithm = true;
82   if (!validAlgorithm)
83     throw new Error("Invalid algorithm: " + algorithm);
85   this.hasher_ = Cc["@mozilla.org/security/hash;1"]
86                  .createInstance(Ci.nsICryptoHash);
87   this.hasher_.init(algorithm);
90 /**
91  * Update the hash's internal state with input given in a string. Can be
92  * called multiple times for incrementeal hash updates.
93  *
94  * @param input String containing data to hash.
95  */ 
96 G_CryptoHasher.prototype.updateFromString = function(input) {
97   if (!this.hasher_)
98     throw new Error("You must initialize the hasher first!");
100   var stream = Cc['@mozilla.org/io/string-input-stream;1']
101                .createInstance(Ci.nsIStringInputStream);
102   stream.setData(input, input.length);
103   this.updateFromStream(stream);
107  * Update the hash's internal state with input given in an array. Can be
108  * called multiple times for incremental hash updates.
110  * @param input Array containing data to hash.
111  */ 
112 G_CryptoHasher.prototype.updateFromArray = function(input) {
113   if (!this.hasher_)
114     throw new Error("You must initialize the hasher first!");
116   this.hasher_.update(input, input.length);
120  * Update the hash's internal state with input given in a stream. Can be
121  * called multiple times from incremental hash updates.
122  */
123 G_CryptoHasher.prototype.updateFromStream = function(stream) {
124   if (!this.hasher_)
125     throw new Error("You must initialize the hasher first!");
127   if (stream.available())
128     this.hasher_.updateFromStream(stream, stream.available());
132  * @returns The hash value as a string (sequence of 8-bit values)
133  */ 
134 G_CryptoHasher.prototype.digestRaw = function() {
135   var digest = this.hasher_.finish(false /* not b64 encoded */);
136   this.hasher_ = null;
137   return digest;
141  * @returns The hash value as a base64-encoded string
142  */ 
143 G_CryptoHasher.prototype.digestBase64 = function() {
144   var digest = this.hasher_.finish(true /* b64 encoded */);
145   this.hasher_ = null;
146   return digest;
150  * @returns The hash value as a hex-encoded string
151  */ 
152 G_CryptoHasher.prototype.digestHex = function() {
153   var raw = this.digestRaw();
154   return this.toHex_(raw);
158  * Converts a sequence of values to a hex-encoded string. The input is a
159  * a string, so you can stick 16-bit values in each character.
161  * @param str String to conver to hex. (Often this is just a sequence of
162  *            16-bit values)
164  * @returns String containing the hex representation of the input
165  */ 
166 G_CryptoHasher.prototype.toHex_ = function(str) {
167   var hexchars = '0123456789ABCDEF';
168   var hexrep = new Array(str.length * 2);
170   for (var i = 0; i < str.length; ++i) {
171     hexrep[i * 2] = hexchars.charAt((str.charCodeAt(i) >> 4) & 15);
172     hexrep[i * 2 + 1] = hexchars.charAt(str.charCodeAt(i) & 15);
173   }
174   return hexrep.join('');
177 #ifdef DEBUG
179  * Lame unittest function
180  */
181 function TEST_G_CryptoHasher() {
182   if (G_GDEBUG) {
183     var z = "cryptohasher UNITTEST";
184     G_debugService.enableZone(z);
186     G_Debug(z, "Starting");
188     var md5 = function(str) {
189       var hasher = new G_CryptoHasher();
190       hasher.init(G_CryptoHasher.algorithms.MD5);
191       hasher.updateFromString(str);
192       return hasher.digestHex().toLowerCase();
193     };
195     // test vectors from: http://www.faqs.org/rfcs/rfc1321.html
196     var vectors = {"": "d41d8cd98f00b204e9800998ecf8427e",
197                    "a": "0cc175b9c0f1b6a831c399e269772661",
198                    "abc": "900150983cd24fb0d6963f7d28e17f72",
199                    "message digest": "f96b697d7cb7938d525a2f31aaf161d0",
200                    "abcdefghijklmnopqrstuvwxyz": "c3fcd3d76192e4007dfb496cca67e13b",
201                    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789": "d174ab98d277d9f5a5611c2c9f419d9f",
202                    "12345678901234567890123456789012345678901234567890123456789012345678901234567890": "57edf4a22be3c955ac49da2e2107b67a"};
203                    
204     G_Debug(z, "PASSED");
205   }
207 #endif