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 });