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