2   Copyright (c) 2008, Adobe Systems Incorporated
 
   5   Redistribution and use in source and binary forms, with or without 
 
   6   modification, are permitted provided that the following conditions are
 
   9   * Redistributions of source code must retain the above copyright notice, 
 
  10     this list of conditions and the following disclaimer.
 
  12   * Redistributions in binary form must reproduce the above copyright
 
  13     notice, this list of conditions and the following disclaimer in the 
 
  14     documentation and/or other materials provided with the distribution.
 
  16   * Neither the name of Adobe Systems Incorporated nor the names of its 
 
  17     contributors may be used to endorse or promote products derived from 
 
  18     this software without specific prior written permission.
 
  20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
  21   IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
  22   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
  23   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 
  24   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
  25   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
  26   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
  27   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
  28   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
  29   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
  30   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  33 package com.adobe.crypto
 
  35         import com.adobe.utils.IntUtil;
 
  36         import flash.utils.ByteArray;
 
  37         import mx.utils.Base64Encoder;
 
  40          * The SHA-224 algorithm
 
  42          * @see http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
 
  46                 public static var digest:ByteArray;
 
  49                  *  Performs the SHA224 hash algorithm on a string.
 
  51                  *  @param s            The string to hash
 
  52                  *  @return                     A string containing the hash value of s
 
  53                  *  @langversion        ActionScript 3.0
 
  57                 public static function hash( s:String ):String {
 
  58                         var blocks:Array = createBlocksFromString( s );
 
  59                         var byteArray:ByteArray = hashBlocks( blocks );
 
  60                         return IntUtil.toHex( byteArray.readInt(), true )
 
  61                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  62                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  63                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  64                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  65                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  66                                         + IntUtil.toHex( byteArray.readInt(), true );
 
  70                  *  Performs the SHA224 hash algorithm on a ByteArray.
 
  72                  *  @param data         The ByteArray data to hash
 
  73                  *  @return                     A string containing the hash value of data
 
  74                  *  @langversion        ActionScript 3.0
 
  77                 public static function hashBytes( data:ByteArray ):String
 
  79                         var blocks:Array = createBlocksFromByteArray( data );
 
  80                         var byteArray:ByteArray = hashBlocks(blocks);
 
  81                         return IntUtil.toHex( byteArray.readInt(), true )
 
  82                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  83                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  84                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  85                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  86                                         + IntUtil.toHex( byteArray.readInt(), true )
 
  87                                         + IntUtil.toHex( byteArray.readInt(), true );
 
  91                  *  Performs the SHA224 hash algorithm on a string, then does
 
  92                  *  Base64 encoding on the result.
 
  94                  *  @param s            The string to hash
 
  95                  *  @return                     The base64 encoded hash value of s
 
  96                  *  @langversion        ActionScript 3.0
 
 100                 public static function hashToBase64( s:String ):String
 
 102                         var blocks:Array = createBlocksFromString( s );
 
 103                         var byteArray:ByteArray = hashBlocks(blocks);
 
 105                         // ByteArray.toString() returns the contents as a UTF-8 string,
 
 106                         // which we can't use because certain byte sequences might trigger
 
 107                         // a UTF-8 conversion.  Instead, we convert the bytes to characters
 
 109                         var charsInByteArray:String = "";
 
 110                         byteArray.position = 0;
 
 111                         for (var j:int = 0; j < byteArray.length; j++)
 
 113                                 var byte:uint = byteArray.readUnsignedByte();
 
 114                                 charsInByteArray += String.fromCharCode(byte);
 
 117                         var encoder:Base64Encoder = new Base64Encoder();
 
 118                         encoder.encode(charsInByteArray);
 
 119                         return encoder.flush();
 
 122                 private static function hashBlocks( blocks:Array ):ByteArray {
 
 123                         var h0:int = 0xc1059ed8;
 
 124                         var h1:int = 0x367cd507;
 
 125                         var h2:int = 0x3070dd17;
 
 126                         var h3:int = 0xf70e5939;
 
 127                         var h4:int = 0xffc00b31;
 
 128                         var h5:int = 0x68581511;
 
 129                         var h6:int = 0x64f98fa7;
 
 130                         var h7:int = 0xbefa4fa4;
 
 132                         var k:Array = new 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);
 
 134                         var len:int = blocks.length;
 
 135                         var w:Array = new Array();
 
 137                         // loop over all of the blocks
 
 138                         for ( var i:int = 0; i < len; i += 16 ) {
 
 149                                 for(var t:int = 0; t < 64; t++) {
 
 152                                                 w[t] = blocks[ i + t ];
 
 153                                                 if(isNaN(w[t])) { w[t] = 0; }
 
 155                                                 var ws0:int = IntUtil.ror(w[t-15], 7) ^ IntUtil.ror(w[t-15], 18) ^ (w[t-15] >>> 3);
 
 156                                                 var ws1:int = IntUtil.ror(w[t-2], 17) ^ IntUtil.ror(w[t-2], 19) ^ (w[t-2] >>> 10);
 
 157                                                 w[t] = w[t-16] + ws0 + w[t-7] + ws1;
 
 160                                         var s0:int = IntUtil.ror(a, 2) ^ IntUtil.ror(a, 13) ^ IntUtil.ror(a, 22);
 
 161                                         var maj:int = (a & b) ^ (a & c) ^ (b & c);
 
 162                                         var t2:int = s0 + maj;
 
 163                                         var s1:int = IntUtil.ror(e, 6) ^ IntUtil.ror(e, 11) ^ IntUtil.ror(e, 25);
 
 164                                         var ch:int = (e & f) ^ ((~e) & g);
 
 165                                         var t1:int = h + s1 + ch + k[t] + w[t];
 
 177                                 //Add this chunk's hash to result so far:
 
 188                         var byteArray:ByteArray = new ByteArray();
 
 189                         byteArray.writeInt(h0);
 
 190                         byteArray.writeInt(h1);
 
 191                         byteArray.writeInt(h2);
 
 192                         byteArray.writeInt(h3);
 
 193                         byteArray.writeInt(h4);
 
 194                         byteArray.writeInt(h5);
 
 195                         byteArray.writeInt(h6);
 
 196                         byteArray.position = 0;
 
 198                         digest = new ByteArray();
 
 199                         digest.writeBytes(byteArray);
 
 205                  *  Converts a ByteArray to a sequence of 16-word blocks
 
 206                  *  that we'll do the processing on.  Appends padding
 
 207                  *  and length in the process.
 
 209                  *  @param data         The data to split into blocks
 
 210                  *  @return                     An array containing the blocks into which data was split
 
 212                 private static function createBlocksFromByteArray( data:ByteArray ):Array
 
 214                         var oldPosition:int = data.position;
 
 217                         var blocks:Array = new Array();
 
 218                         var len:int = data.length * 8;
 
 219                         var mask:int = 0xFF; // ignore hi byte of characters > 0xFF
 
 220                         for( var i:int = 0; i < len; i += 8 )
 
 222                                 blocks[ i >> 5 ] |= ( data.readByte() & mask ) << ( 24 - i % 32 );
 
 225                         // append padding and length
 
 226                         blocks[ len >> 5 ] |= 0x80 << ( 24 - len % 32 );
 
 227                         blocks[ ( ( ( len + 64 ) >> 9 ) << 4 ) + 15 ] = len;
 
 229                         data.position = oldPosition;
 
 235                  *  Converts a string to a sequence of 16-word blocks
 
 236                  *  that we'll do the processing on.  Appends padding
 
 237                  *  and length in the process.
 
 239                  *  @param s    The string to split into blocks
 
 240                  *  @return             An array containing the blocks that s was split into.
 
 242                 private static function createBlocksFromString( s:String ):Array
 
 244                         var blocks:Array = new Array();
 
 245                         var len:int = s.length * 8;
 
 246                         var mask:int = 0xFF; // ignore hi byte of characters > 0xFF
 
 247                         for( var i:int = 0; i < len; i += 8 ) {
 
 248                                 blocks[ i >> 5 ] |= ( s.charCodeAt( i / 8 ) & mask ) << ( 24 - i % 32 );
 
 251                         // append padding and length
 
 252                         blocks[ len >> 5 ] |= 0x80 << ( 24 - len % 32 );
 
 253                         blocks[ ( ( ( len + 64 ) >> 9 ) << 4 ) + 15 ] = len;