toolkit/components/url-classifier/content/moz/cryptohasher.js

changeset 0
6474c204b198
     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

mercurial