Michael Bradley, Jr. - Hash-0.06

Documentation | Source

Name

Hash - provides MD5, SHA-1, SHA-256, SHA-512, and RIPEMD-160 cryptographic hash algorithms for JavaScript. Adapted from Paul Johnston's BSD-licensed cryptography library.

SYNOPSIS

Node.js example:

    require('joose')
    require('joosex-namespace-depended')
    require('hash')

    // define some text you wish to hash

    var text = 'Some amazing text.'

    // hash it using MD5

    var hash = Hash.md5(text) // => '8dc6e489042b35c41f38319f1702e829'

    // hash it with SHA-1

    hash2 = Hash.sha1(text) // => '5fa88652f6cfe865a6b2bed2d2e658d7e12d5ea8'

    // hash it with SHA-256

    hash3 = Hash.sha256(text) // => 'b291f7ca30c306cc5e96ce8b046e5656c05b7621eb848ed4b180fb3b25b19d8d'

    // hash it with SHA-512

    hash4 = Hash.sha512(text) // => '2e74135091d583c0a2b0db5c4a0902fc3b75ec2b6b5c27fea1fb77e2cb0e14ed7922cc5f618b90f2511cc711a287d8881e76dea1697c5a4e788d78e52df53efc'

    // hash it with RIPEMD-160

    hash5 = Hash.rmd160(text) // => 'bfda47b1b4574be552617212c80ad29687596193'

DESCRIPTION

Hash is a small collection of Joose3 classes which provide cryptographic hash algorithms for string types, implemented as static methods.

The module is usable both server-side with node.js and in a browser environment. Extenstive testing has been conducted against large collections of UTF-8 and ASCII encoded strings to better ensure the reliability of these implementations. Canonical hashes were generated with Linux userland utilities, for comparison.

INSTALLATION

For node.js, npm provides the simplest install:

    npm install hash

If you've not yet installed Joose3 or JooseX.Namespace.Depended: npm install joose joosex-namespace-depended.

METHODS

The hash sum calculators are available as static methods in the Hash.MD5, Hash.SHA1, Hash.SHA256, Hash.SHA512, and Hash.RIPEMD160 classes:

    Hash.MD5.hex_md5('text')
    Hash.SHA1.hex_sha1('text')
    Hash.SHA256.hex_sha256('text')
    Hash.SHA512.hex_sha512('text')
    Hash.RIPEMD160.hex_rmd160('text')

    -or, for convenience-

    Hash.md5('text')
    Hash.sha1('text')
    Hash.sha256('text')
    Hash.sha512('text')
    Hash.rmd160('text')

Performance considerations

It should be noted that md5() is somewhat less CPU intensive than the other methods. Keep this in mind if you'll be hashing message payloads in a high-throughput scenario where latency is a concern.

Hashing JSON

If you intend to hash over JSON objects, remember object-key order is not guaranteed; therefore it's not sufficient to JSON.stringify() an object and hash over that string. You would need first to serialize the object and any child objects into a collection of arrays, sorted lexographically (recursively) by key name.

An "object to array" helper method, Hash.oTa(), is provided for this purpose.

Hash.oTa() -- helper method

    var ob1 = { key1 : "Some value", key2 : { A : "one", B : [0,1,2] }, key3 : 5 }

    var ob2 = { key1 : "Some value", key3 : 5, key2 : { B : [0,1,2], A : "one" } }

    var oTa_ob1 = JSON.stringify(Hash.oTa(ob1))
    var oTa_ob2 = JSON.stringify(Hash.oTa(ob2))

    var compare = function(one, two) { if (one == two) { return true } else { return false } }

    compare(Hash.md5(JSON.stringify(ob1)), Hash.md5(JSON.stringify(ob2))) // => false

    compare(Hash.md5(oTa_ob1), Hash.md5(oTa_ob2)) // => true

The object literals ob1 and ob2 contain equivalent data but do not have the same stringified value. But hashing over the stringified return values of Hash.oTa() for ob1, ob2 will calculate the same MD5 sum, and this is true for the other hash algorithms too.

At this time neither circular references nor functions as object-key values are supported by the oTa() helper method, as the standard JSON stringify() and parse() methods are employed in the helper.

GETTING HELP

This extension is supported via github issues tracker: http://github.com/michaelsbradleyjr/Hash/issues

For general Joose questions you can also visit #joose on irc.freenode.org or mailing list at: http://groups.google.com/group/joose-js

SEE ALSO

Web page of this module: http://github.com/michaelsbradleyjr/Hash/

General documentation for Joose: http://openjsan.org/go/?l=Joose

BUGS

All complex software has bugs lurking in it, and this module is no exception.

Please report any bugs through the web interface at http://github.com/michaelsbradleyjr/Hash/issues

AUTHORS

Michael Bradley, Jr. michaelsbradleyjr@gmail.com

COPYRIGHT AND LICENSE

This software is Copyright (c) 2010 by Michael Bradley, Jr..

This is free software, licensed under:

The MIT (X11) License

The MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Joose.Class('Hash', {
    
  /*VERSION*/VERSION : 0.06,

  use : [ 'Encode', 'Hash.MD5', 'Hash.SHA1', 'Hash.SHA256', 'Hash.SHA512', 'Hash.RIPEMD160' ],
    
  my : {
       
    methods : {

      md5 : function (str) {
        return Hash.MD5.hex_md5(str)
      },

      sha1 : function (str) {
        return Hash.SHA1.hex_sha1(str)
      },

      sha256 : function (str) {
        return Hash.SHA256.hex_sha256(str)
      },

      sha512 : function (str) {
        return Hash.SHA512.hex_sha512(str)
      },

      rmd160 : function (str) {
        return Hash.RIPEMD160.hex_rmd160(str)
      },

      oTa : function (obj, loop) {
        if (this.typeOf(obj) != 'object') { throw 'not an object' }
        if (loop) {
          var noCirc = obj
        }
        else {
          // on the first pass, check for circular structures in the input object
          var noCirc = JSON.parse(JSON.stringify(obj))
        }
        var thisClass = this
        var toArray = function (element, index) {
          switch (element[1]) {
            case 'object':
              return [element[0], 1, thisClass.oTa(noCirc[element[0]], true)]
            case 'array':
              return [element[0], thisClass.array_check_for_objects(noCirc[element[0]])]
            default:
              return [element[0], noCirc[element[0]]]
          }
        }
        var kt = this.keysAndTypes(noCirc, true)
        var tA = []
        return tA = Joose.A.map(kt, toArray)
      },

      typeOf : function (value) {
        var s = typeof value
        if (s === 'object') {
          if (value) {
            if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length')) && typeof value.splice === 'function') {
             s = 'array'
            }
          }
          else {
            s = 'null'
          }
        }
        return s
      },

      keys : function (obj) {
        if (this.typeOf(obj) != 'object') { throw 'not an object' }
        var keys = []
        for (var key in obj) {
          keys.push(key)
        }
        return keys
      },

      keysAndTypes : function (obj, sort) {
        if (sort) {
          var Keys = this.keys(obj).sort()
        }
        else {
          var Keys = this.keys(obj)
        }
        var thisClass = this
        var kAt = function (element, index) {
           return [element, thisClass.typeOf(obj[element])]
        }
        var kt = []
        return kt = Joose.A.map(Keys, kAt)
      },

      array_check_for_objects : function (a) {
        thisClass = this
        var expand = function (element, index) {
          switch (thisClass.typeOf(element)) {
            case 'object':
              return thisClaTarray(element, true)
            case 'array':
              return thisClass.array_check_for_objects(element)
            default:
              return element
          }
        }
        ea = []        
        return ea = Joose.A.map(a, expand)
      }

    }

  }

})