| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package mx.utils |
| { |
| import flash.utils.ByteArray; |
| |
| /** |
| * Implementation of SHA-256 hash algorithm as described in |
| * Federal Information Processing Standards Publication 180-2 |
| * at http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class SHA256 |
| { |
| /** |
| * Identifies this hash is of type "SHA-256". |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static const TYPE_ID:String = "SHA-256"; |
| |
| private static var k:Array = |
| [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, |
| 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, |
| 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, |
| 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 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]; |
| |
| |
| /** |
| * Computes the digest of a message using the SHA-256 hash algorithm. |
| * |
| * @param byteArray - the message, may not be null. |
| * |
| * return String - 64 character hexidecimal representation of the digest. |
| * |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static function computeDigest(byteArray:ByteArray):String |
| { |
| // Preprocessing |
| |
| // 0. Set the ByteArray's position to zero |
| var originalPosition:uint = byteArray.position; |
| byteArray.position = 0; |
| |
| // 1. Pad the message |
| var paddingLength:int = byteArray.length % 64; |
| |
| paddingLength = 64 - paddingLength; |
| |
| if (paddingLength < (1 + 8)) |
| { |
| paddingLength += 64; // need to pad a partial block plus a full block |
| } |
| |
| var messagePadding:Array = new Array(paddingLength); |
| var n:int = (byteArray.length + paddingLength) / 64; // number of message blocks |
| |
| var messageLengthBits:uint = byteArray.length * 8; |
| messagePadding[0] = 128; |
| |
| // put message size in last 32 bits of the message padding |
| var i:int; |
| |
| for (i = 1; i < paddingLength - 8; i++) |
| { |
| messagePadding[i] = 0; |
| } |
| |
| var lastIndex:int = messagePadding.length - 1; // last index of messagePadding |
| for (i = 0; i < 4; i++) |
| { |
| messagePadding[lastIndex - i] = (messageLengthBits >> (i << 3)) & 0xff; |
| } |
| |
| |
| // 2. Set initial hash H(0) |
| var h0:uint = 0x6a09e667; |
| var h1:uint = 0xbb67ae85; |
| var h2:uint = 0x3c6ef372; |
| var h3:uint = 0xa54ff53a; |
| var h4:uint = 0x510e527f; |
| var h5:uint = 0x9b05688c; |
| var h6:uint = 0x1f83d9ab; |
| var h7:uint = 0x5be0cd19; |
| |
| var a:uint; |
| var b:uint; |
| var c:uint; |
| var d:uint; |
| var e:uint; |
| var f:uint; |
| var g:uint; |
| var h:uint; |
| |
| // Hash computation |
| // for all message blocks |
| var m:ByteArray = new ByteArray(); // message block; 16 32-bit words or 64 bytes |
| var w:Array = new Array(64); // message schedule, 64 32-bit words |
| var paddingStart:uint = 0; // index to start padding message |
| var paddingSize:uint = 0; // amount of padding to copy to message |
| var j:uint; |
| var t1:uint; // temporary storage in hash loop |
| var t2:uint; // temporary storage in hash loop |
| var t:uint; |
| var msgIndex:uint; |
| var wt2:uint; // w[t - 2] |
| var wt15:uint; // w[t -15] |
| |
| //var messageSchTime:int = 0; |
| //var hashTime:int = 0; |
| //var startTime:int; |
| //var endTime:int; |
| |
| for (i = 0; i < n; i++) |
| { |
| // get the next message block of 512 bits or 64 bytes. |
| getMessageBlock(byteArray, m); |
| |
| // append pass to end of last message block |
| if (i == (n - 2) && messagePadding.length > 64) |
| { |
| // pad end of message before last block |
| paddingStart = 64 - (messagePadding.length % 64); |
| paddingSize = 64 - paddingStart; |
| for (j = 0; j < paddingSize; j++) |
| { |
| m[j + paddingStart] = messagePadding[j]; |
| } |
| |
| } |
| else if (i == n - 1) |
| { |
| var prevPaddingSize:int = paddingSize; |
| if (messagePadding.length > 64) |
| { |
| paddingStart = 0; |
| paddingSize = 64; |
| } |
| else |
| { |
| paddingStart = 64 - messagePadding.length; |
| paddingSize = messagePadding.length; |
| } |
| |
| for (j = 0; j < paddingSize; j++) |
| { |
| m[j + paddingStart] = messagePadding[j + prevPaddingSize]; |
| } |
| } |
| |
| // prepare the message schedule, w |
| //startTime= getTimer(); |
| for (t = 0; t < 64; t++) |
| { |
| if (t < 16) |
| { |
| msgIndex = t << 2; |
| w[t] = int((m[msgIndex] << 24) | |
| (m[msgIndex + 1] << 16) | |
| (m[msgIndex + 2] << 8) | |
| m[msgIndex + 3]); |
| } |
| else |
| { |
| // inline functions to boost performance. keep orginal code for reference. |
| // w[t] = divisor1(w[t - 2]) + uint(w[t - 7]) + divisor0(w[t - 15]) + uint(w[t - 16]); |
| wt2 = w[t -2]; |
| wt15 = w[t-15]; |
| w[t] = int(int((((wt2 >>> 17) | (wt2 << 15)) ^ ((wt2 >>> 19) | (wt2 << 13)) ^ (wt2 >>> 10))) + // divisor1(w[t - 2]) |
| int(w[t - 7]) + |
| int((((wt15 >>> 7) | (wt15 << 25)) ^ ((wt15 >>> 18) | (wt15 << 14)) ^ (wt15 >>> 3))) + // divisor0(w[t - 15]) |
| int(w[t - 16])); |
| } |
| } |
| |
| //endTime= getTimer(); |
| //messageSchTime += endTime - startTime; |
| |
| //startTime= getTimer(); |
| |
| a = h0; |
| b = h1; |
| c = h2; |
| d = h3; |
| e = h4; |
| f = h5; |
| g = h6; |
| h = h7; |
| |
| for (t = 0; t < 64; t++) |
| { |
| // inline functions to boost performance. keep orginal code for reference. |
| //t1 = h + sum1(e) + Ch(e, f, g) + uint(k[t]) + uint(w[t]); |
| //t2 = sum0(a) + Maj(a, b, c); |
| t1 = h + |
| int((((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7)))) + // sum1(e) |
| int(((e & f) ^ (~e & g))) + // Ch(e, f, g) |
| int(k[t]) + |
| int(w[t]); |
| t2 = int((((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10)))) + // sum0(a) |
| int(((a & b) ^ (a & c) ^ (b & c))); // Maj(a, b, c) |
| |
| h = g; |
| g = f; |
| f = e; |
| e = d + t1; |
| d = c; |
| c = b; |
| b = a; |
| a = t1 + t2; |
| |
| //trace("t = " + t + " a = " + uint(a).toString(16) + " b = " + uint(b).toString(16) + |
| // " c = " + uint(c).toString(16) + " d = " + uint(d).toString(16) + "\n"); |
| //trace("t = " + t + " e = " + uint(e).toString(16) + " f = " + uint(f).toString(16) + |
| // " g = " + uint(g).toString(16) + " h = " + uint(h).toString(16) + "\n"); |
| |
| } |
| |
| h0 += a; |
| h1 += b; |
| h2 += c; |
| h3 += d; |
| h4 += e; |
| h5 += f; |
| h6 += g; |
| h7 += h; |
| |
| //endTime= getTimer(); |
| //hashTime += endTime - startTime; |
| |
| } |
| |
| // Reset the ByteArray's position to where it was previously |
| byteArray.position = originalPosition; |
| |
| //trace("messageSchTime = " + messageSchTime); |
| //trace("hashTime = " + hashTime); |
| |
| // final digest is h1 | h2 | h3 | h4 | h5 | h6 | h7 |
| // convert H(i) variables to hex strings and concatinate |
| return toHex(h0) + toHex(h1) + |
| toHex(h2) + toHex(h3) + |
| toHex(h4) + toHex(h5) + |
| toHex(h6) + toHex(h7); |
| } |
| |
| |
| /** |
| * get the next n bytes of the message from the byteArray and move it to the message block. |
| * |
| * @param byteArray - message |
| * @param m - message block (output) |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| private static function getMessageBlock(byteArray:ByteArray, m:ByteArray):void |
| { |
| byteArray.readBytes(m, 0, Math.min(byteArray.bytesAvailable, 64)); |
| |
| // for (var i:int; i < length && (i + startingIndex) < byteArray.length; i++) |
| // { |
| // m[i] = byteArray[i + startingIndex]; |
| // } |
| } |
| |
| private static function toHex(n:uint):String |
| { |
| var s:String = n.toString(16); |
| |
| if (s.length < 8) |
| { |
| // add leading zeros |
| var zeros:String = "0"; |
| var count:int = 8 - s.length; |
| for (var i:int = 1; i < count; i++) |
| { |
| zeros = zeros.concat("0"); |
| } |
| |
| return zeros + s; |
| } |
| |
| return s; |
| } |
| |
| // The below functions are defined in Federal Information |
| // Processing Standards Publication 180-2 |
| // at |
| // http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf |
| |
| /* The functions have been inlined to boost performance. They are |
| kept here for reference. |
| |
| private static function Ch(x:uint, y:uint, z:uint):uint |
| { |
| return (x & y) ^ (~x & z); |
| } |
| |
| private static function Maj(x:uint, y:uint, z:uint):uint |
| { |
| return (x & y) ^ (x & z) ^ (y & z); |
| } |
| |
| private static function sum0(x:uint):uint |
| { |
| return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10)); |
| //return rotr(2, x) ^ rotr(13, x) ^ rotr(22, x); |
| } |
| |
| private static function sum1(x:uint):uint |
| { |
| return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7)); |
| // return rotr(6, x) ^ rotr(11, x) ^ rotr(25, x); |
| } |
| |
| private static function divisor0(x:uint):uint |
| { |
| return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3); |
| // return rotr(7, x) ^ rotr(18, x) ^ shr(3, x); |
| } |
| |
| private static function divisor1(x:uint):uint |
| { |
| return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10); |
| // return rotr(17, x) ^ rotr(19, x) ^ shr(10, x); |
| } |
| |
| private static function rotr(n:uint, x:uint):uint |
| { |
| return (x >>> n) | (x << 32 - n); |
| } |
| |
| private static function shr(n:uint, x:uint):uint |
| { |
| return x >>> n; |
| } |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| } |
| } |