      1 // ==========================================================================
      2 // Project:   The M-Project - Mobile HTML5 Application Framework
      3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
      4 // Creator:   Dominik
      5 // Date:      11.11.2010
      6 // License:   Dual licensed under the MIT or GPL Version 2 licenses.
      7 //            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
      8 //            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
      9 // ==========================================================================
     10
     11 m_require('core/foundation/object.js');
     12
     13 /**
     14  * @class
     15  *
     16  * This prototype defines a hashing mechanism based on the SHA256 algorithm. You normally
     17  * don't call this object respectively its methods directly, but let M.Cypher handle
     18  * this.
     19  *
     20  * @extends M.Object
     21  */
     22 M.SHA256 = M.Object.extend(
     23 /** @scope M.SHA256.prototype */ {
     24
     25     /**
     26      * The type of this object.
     27      *
     28      * @type String
     29      */
     30     type: 'M.SHA256',
     31
     32     /**
     33      * Defines the bits per input character: 8 - ASCII, 16 - Unicode
     34      *
     35      * @type Number
     36      */
     37     chrsz: 8,
     38
     39     /**
     40      * Defines the hex output format: 0 - lowercase, 1 - uppercase
     41      *
     42      * @type Number
     43      */
     44     hexcase: 0,
     45
     46     /**
     47      * This method is called from the 'outside world', controls the hashing and
     48      * finally returns the hash value.
     49      *
     50      * @param {String} input The input string to be hashed.
     51      * @returns {String} The sha256 hashed string.
     52      */
     53     hash: function(input) {
     54         input = M.Cypher.utf8_encode(input);
     55         return this.binb2hex(this.core_sha256(this.str2binb(input), input.length * this.chrsz));
     56     },
     57
     58     /**
     59      * @private
     60      */
     61     safe_add: function(x, y) {
     62         var lsw = (x & 0xFFFF) + (y & 0xFFFF);
     63         var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
     64         return (msw << 16) | (lsw & 0xFFFF);
     65     },
     66
     67     /**
     68      * @private
     69      */
     70     S: function(X, n) {
     71         return ( X >>> n ) | (X << (32 - n));
     72     },
     73
     74     /**
     75      * @private
     76      */
     77     R: function(X, n) {
     78         return ( X >>> n );
     79     },
     80
     81     /**
     82      * @private
     83      */
     84     Ch: function(x, y, z) {
     85         return ((x & y) ^ ((~x) & z));
     86     },
     87
     88     /**
     89      * @private
     90      */
     91     Maj: function(x, y, z) {
     92         return ((x & y) ^ (x & z) ^ (y & z));
     93     },
     94
     95     /**
     96      * @private
     97      */
     98     Sigma0256: function(x) {
     99         return (this.S(x, 2) ^ this.S(x, 13) ^ this.S(x, 22));
    100     },
    101
    102     /**
    103      * @private
    104      */
    105     Sigma1256: function(x) {
    106         return (this.S(x, 6) ^ this.S(x, 11) ^ this.S(x, 25));
    107     },
    108
    109     /**
    110      * @private
    111      */
    112     Gamma0256: function(x) {
    113         return (this.S(x, 7) ^ this.S(x, 18) ^ this.R(x, 3));
    114     },
    115
    116     /**
    117      * @private
    118      */
    119     Gamma1256: function(x) {
    120         return (this.S(x, 17) ^ this.S(x, 19) ^ this.R(x, 10));
    121     },
    122
    123     /**
    124      * @private
    125      */
    126     core_sha256: function(m, l) {
    127         var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2);
    128         var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
    129         var W = new Array(64);
    130         var a, b, c, d, e, f, g, h, i, j;
    131         var T1, T2;
    132
    133         m[l >> 5] |= 0x80 << (24 - l % 32);
    134         m[((l + 64 >> 9) << 4) + 15] = l;
    135
    136         for (var i = 0; i < m.length; i += 16) {
    137             a = HASH[0];
    138             b = HASH[1];
    139             c = HASH[2];
    140             d = HASH[3];
    141             e = HASH[4];
    142             f = HASH[5];
    143             g = HASH[6];
    144             h = HASH[7];
    145
    146             for (var j = 0; j < 64; j++) {
    147                 if (j < 16) W[j] = m[j + i];
    148                 else W[j] = this.safe_add(this.safe_add(this.safe_add(this.Gamma1256(W[j - 2]), W[j - 7]), this.Gamma0256(W[j - 15])), W[j - 16]);
    149
    150                 T1 = this.safe_add(this.safe_add(this.safe_add(this.safe_add(h, this.Sigma1256(e)), this.Ch(e, f, g)), K[j]), W[j]);
    151                 T2 = this.safe_add(this.Sigma0256(a), this.Maj(a, b, c));
    152
    153                 h = g;
    154                 g = f;
    155                 f = e;
    156                 e = this.safe_add(d, T1);
    157                 d = c;
    158                 c = b;
    159                 b = a;
    160                 a = this.safe_add(T1, T2);
    161             }
    162
    163             HASH[0] = this.safe_add(a, HASH[0]);
    164             HASH[1] = this.safe_add(b, HASH[1]);
    165             HASH[2] = this.safe_add(c, HASH[2]);
    166             HASH[3] = this.safe_add(d, HASH[3]);
    167             HASH[4] = this.safe_add(e, HASH[4]);
    168             HASH[5] = this.safe_add(f, HASH[5]);
    169             HASH[6] = this.safe_add(g, HASH[6]);
    170             HASH[7] = this.safe_add(h, HASH[7]);
    171         }
    172         return HASH;
    173     },
    174
    175     /**
    176      * @private
    177      */
    178     str2binb: function(str) {
    179         var bin = Array();
    180         var mask = (1 << this.chrsz) - 1;
    181         for (var i = 0; i < str.length * this.chrsz; i += this.chrsz) {
    182             bin[i >> 5] |= (str.charCodeAt(i / this.chrsz) & mask) << (24 - i % 32);
    183         }
    184         return bin;
    185     },
    186
    187     /**
    188      * @private
    189      */
    190     binb2hex: function(binarray) {
    191         var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    192         var str = "";
    193         for (var i = 0; i < binarray.length * 4; i++) {
    194             str += hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8 + 4)) & 0xF) +
    195                     hex_tab.charAt((binarray[i >> 2] >> ((3 - i % 4) * 8  )) & 0xF);
    196         }
    197         return str;
    198     }
    199
    200 });