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

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6 // A very thin wrapper around nsICryptoHash. It's not strictly
     7 // necessary, but makes the code a bit cleaner and gives us the
     8 // opportunity to verify that our implementations give the results that
     9 // we expect, for example if we have to interoperate with a server.
    10 //
    11 // The digest* methods reset the state of the hasher, so it's
    12 // necessary to call init() explicitly after them.
    13 //
    14 // Works only in Firefox 1.5+.
    15 //
    16 // IMPORTANT NOTE: Due to https://bugzilla.mozilla.org/show_bug.cgi?id=321024
    17 // you cannot use the cryptohasher before app-startup. The symptom of doing
    18 // so is a segfault in NSS.
    20 /**
    21  * Instantiate a new hasher. You must explicitly call init() before use!
    22  */
    23 function G_CryptoHasher() {
    24   this.debugZone = "cryptohasher";
    25   this.hasher_ = null;
    26 }
    28 G_CryptoHasher.algorithms = {
    29   MD2: Ci.nsICryptoHash.MD2,
    30   MD5: Ci.nsICryptoHash.MD5,
    31   SHA1: Ci.nsICryptoHash.SHA1,
    32   SHA256: Ci.nsICryptoHash.SHA256,
    33   SHA384: Ci.nsICryptoHash.SHA384,
    34   SHA512: Ci.nsICryptoHash.SHA512,
    35 };
    37 /**
    38  * Initialize the hasher. This function must be called after every call
    39  * to one of the digest* methods.
    40  *
    41  * @param algorithm Constant from G_CryptoHasher.algorithms specifying the
    42  *                  algorithm this hasher will use
    43  */ 
    44 G_CryptoHasher.prototype.init = function(algorithm) {
    45   var validAlgorithm = false;
    46   for (var alg in G_CryptoHasher.algorithms)
    47     if (algorithm == G_CryptoHasher.algorithms[alg])
    48       validAlgorithm = true;
    50   if (!validAlgorithm)
    51     throw new Error("Invalid algorithm: " + algorithm);
    53   this.hasher_ = Cc["@mozilla.org/security/hash;1"]
    54                  .createInstance(Ci.nsICryptoHash);
    55   this.hasher_.init(algorithm);
    56 }
    58 /**
    59  * Update the hash's internal state with input given in a string. Can be
    60  * called multiple times for incrementeal hash updates.
    61  *
    62  * @param input String containing data to hash.
    63  */ 
    64 G_CryptoHasher.prototype.updateFromString = function(input) {
    65   if (!this.hasher_)
    66     throw new Error("You must initialize the hasher first!");
    68   var stream = Cc['@mozilla.org/io/string-input-stream;1']
    69                .createInstance(Ci.nsIStringInputStream);
    70   stream.setData(input, input.length);
    71   this.updateFromStream(stream);
    72 }
    74 /**
    75  * Update the hash's internal state with input given in an array. Can be
    76  * called multiple times for incremental hash updates.
    77  *
    78  * @param input Array containing data to hash.
    79  */ 
    80 G_CryptoHasher.prototype.updateFromArray = function(input) {
    81   if (!this.hasher_)
    82     throw new Error("You must initialize the hasher first!");
    84   this.hasher_.update(input, input.length);
    85 }
    87 /**
    88  * Update the hash's internal state with input given in a stream. Can be
    89  * called multiple times from incremental hash updates.
    90  */
    91 G_CryptoHasher.prototype.updateFromStream = function(stream) {
    92   if (!this.hasher_)
    93     throw new Error("You must initialize the hasher first!");
    95   if (stream.available())
    96     this.hasher_.updateFromStream(stream, stream.available());
    97 }
    99 /**
   100  * @returns The hash value as a string (sequence of 8-bit values)
   101  */ 
   102 G_CryptoHasher.prototype.digestRaw = function() {
   103   var digest = this.hasher_.finish(false /* not b64 encoded */);
   104   this.hasher_ = null;
   105   return digest;
   106 }
   108 /**
   109  * @returns The hash value as a base64-encoded string
   110  */ 
   111 G_CryptoHasher.prototype.digestBase64 = function() {
   112   var digest = this.hasher_.finish(true /* b64 encoded */);
   113   this.hasher_ = null;
   114   return digest;
   115 }
   117 /**
   118  * @returns The hash value as a hex-encoded string
   119  */ 
   120 G_CryptoHasher.prototype.digestHex = function() {
   121   var raw = this.digestRaw();
   122   return this.toHex_(raw);
   123 }
   125 /**
   126  * Converts a sequence of values to a hex-encoded string. The input is a
   127  * a string, so you can stick 16-bit values in each character.
   128  *
   129  * @param str String to conver to hex. (Often this is just a sequence of
   130  *            16-bit values)
   131  *
   132  * @returns String containing the hex representation of the input
   133  */ 
   134 G_CryptoHasher.prototype.toHex_ = function(str) {
   135   var hexchars = '0123456789ABCDEF';
   136   var hexrep = new Array(str.length * 2);
   138   for (var i = 0; i < str.length; ++i) {
   139     hexrep[i * 2] = hexchars.charAt((str.charCodeAt(i) >> 4) & 15);
   140     hexrep[i * 2 + 1] = hexchars.charAt(str.charCodeAt(i) & 15);
   141   }
   142   return hexrep.join('');
   143 }
   145 #ifdef DEBUG
   146 /**
   147  * Lame unittest function
   148  */
   149 function TEST_G_CryptoHasher() {
   150   if (G_GDEBUG) {
   151     var z = "cryptohasher UNITTEST";
   152     G_debugService.enableZone(z);
   154     G_Debug(z, "Starting");
   156     var md5 = function(str) {
   157       var hasher = new G_CryptoHasher();
   158       hasher.init(G_CryptoHasher.algorithms.MD5);
   159       hasher.updateFromString(str);
   160       return hasher.digestHex().toLowerCase();
   161     };
   163     // test vectors from: http://www.faqs.org/rfcs/rfc1321.html
   164     var vectors = {"": "d41d8cd98f00b204e9800998ecf8427e",
   165                    "a": "0cc175b9c0f1b6a831c399e269772661",
   166                    "abc": "900150983cd24fb0d6963f7d28e17f72",
   167                    "message digest": "f96b697d7cb7938d525a2f31aaf161d0",
   168                    "abcdefghijklmnopqrstuvwxyz": "c3fcd3d76192e4007dfb496cca67e13b",
   169                    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789": "d174ab98d277d9f5a5611c2c9f419d9f",
   170                    "12345678901234567890123456789012345678901234567890123456789012345678901234567890": "57edf4a22be3c955ac49da2e2107b67a"};
   172     G_Debug(z, "PASSED");
   173   }
   174 }
   175 #endif

mercurial