+/*\r
+ Copyright (c) 2008, Adobe Systems Incorporated\r
+ All rights reserved.\r
+\r
+ Redistribution and use in source and binary forms, with or without \r
+ modification, are permitted provided that the following conditions are\r
+ met:\r
+\r
+ * Redistributions of source code must retain the above copyright notice, \r
+ this list of conditions and the following disclaimer.\r
+ \r
+ * Redistributions in binary form must reproduce the above copyright\r
+ notice, this list of conditions and the following disclaimer in the \r
+ documentation and/or other materials provided with the distribution.\r
+ \r
+ * Neither the name of Adobe Systems Incorporated nor the names of its \r
+ contributors may be used to endorse or promote products derived from \r
+ this software without specific prior written permission.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS\r
+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR \r
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*/\r
+\r
+package com.adobe.crypto\r
+{\r
+ import com.adobe.utils.IntUtil;\r
+ import flash.utils.ByteArray;\r
+ import mx.utils.Base64Encoder;\r
+ \r
+ /**\r
+ * US Secure Hash Algorithm 1 (SHA1)\r
+ *\r
+ * Implementation based on algorithm description at \r
+ * http://www.faqs.org/rfcs/rfc3174.html\r
+ */\r
+ public class SHA1\r
+ {\r
+ public static var digest:ByteArray;\r
+ \r
+ /**\r
+ * Performs the SHA1 hash algorithm on a string.\r
+ *\r
+ * @param s The string to hash\r
+ * @return A string containing the hash value of s\r
+ * @langversion ActionScript 3.0\r
+ * @playerversion 9.0\r
+ * @tiptext\r
+ */\r
+ public static function hash( s:String ):String\r
+ {\r
+ var blocks:Array = createBlocksFromString( s );\r
+ var byteArray:ByteArray = hashBlocks( blocks );\r
+ \r
+ return IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true );\r
+ }\r
+ \r
+ /**\r
+ * Performs the SHA1 hash algorithm on a ByteArray.\r
+ *\r
+ * @param data The ByteArray data to hash\r
+ * @return A string containing the hash value of data\r
+ * @langversion ActionScript 3.0\r
+ * @playerversion 9.0\r
+ */\r
+ public static function hashBytes( data:ByteArray ):String\r
+ {\r
+ var blocks:Array = SHA1.createBlocksFromByteArray( data );\r
+ var byteArray:ByteArray = hashBlocks(blocks);\r
+ \r
+ return IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true )\r
+ + IntUtil.toHex( byteArray.readInt(), true );\r
+ }\r
+ \r
+ /**\r
+ * Performs the SHA1 hash algorithm on a string, then does\r
+ * Base64 encoding on the result.\r
+ *\r
+ * @param s The string to hash\r
+ * @return The base64 encoded hash value of s\r
+ * @langversion ActionScript 3.0\r
+ * @playerversion 9.0\r
+ * @tiptext\r
+ */\r
+ public static function hashToBase64( s:String ):String\r
+ {\r
+ var blocks:Array = SHA1.createBlocksFromString( s );\r
+ var byteArray:ByteArray = hashBlocks(blocks);\r
+\r
+ // ByteArray.toString() returns the contents as a UTF-8 string,\r
+ // which we can't use because certain byte sequences might trigger\r
+ // a UTF-8 conversion. Instead, we convert the bytes to characters\r
+ // one by one.\r
+ var charsInByteArray:String = "";\r
+ byteArray.position = 0;\r
+ for (var j:int = 0; j < byteArray.length; j++)\r
+ {\r
+ var byte:uint = byteArray.readUnsignedByte();\r
+ charsInByteArray += String.fromCharCode(byte);\r
+ }\r
+\r
+ var encoder:Base64Encoder = new Base64Encoder();\r
+ encoder.encode(charsInByteArray);\r
+ return encoder.flush();\r
+ }\r
+ \r
+ private static function hashBlocks( blocks:Array ):ByteArray\r
+ {\r
+ // initialize the h's\r
+ var h0:int = 0x67452301;\r
+ var h1:int = 0xefcdab89;\r
+ var h2:int = 0x98badcfe;\r
+ var h3:int = 0x10325476;\r
+ var h4:int = 0xc3d2e1f0;\r
+ \r
+ var len:int = blocks.length;\r
+ var w:Array = new Array( 80 );\r
+ \r
+ // loop over all of the blocks\r
+ for ( var i:int = 0; i < len; i += 16 ) {\r
+ \r
+ // 6.1.c\r
+ var a:int = h0;\r
+ var b:int = h1;\r
+ var c:int = h2;\r
+ var d:int = h3;\r
+ var e:int = h4;\r
+ \r
+ // 80 steps to process each block\r
+ // TODO: unroll for faster execution, or 4 loops of\r
+ // 20 each to avoid the k and f function calls\r
+ for ( var t:int = 0; t < 80; t++ ) {\r
+ \r
+ if ( t < 16 ) {\r
+ // 6.1.a\r
+ w[ t ] = blocks[ i + t ];\r
+ } else {\r
+ // 6.1.b\r
+ w[ t ] = IntUtil.rol( w[ t - 3 ] ^ w[ t - 8 ] ^ w[ t - 14 ] ^ w[ t - 16 ], 1 );\r
+ }\r
+ \r
+ // 6.1.d\r
+ var temp:int = IntUtil.rol( a, 5 ) + f( t, b, c, d ) + e + int( w[ t ] ) + k( t );\r
+ \r
+ e = d;\r
+ d = c;\r
+ c = IntUtil.rol( b, 30 );\r
+ b = a;\r
+ a = temp;\r
+ }\r
+ \r
+ // 6.1.e\r
+ h0 += a;\r
+ h1 += b;\r
+ h2 += c;\r
+ h3 += d;\r
+ h4 += e; \r
+ }\r
+ \r
+ var byteArray:ByteArray = new ByteArray();\r
+ byteArray.writeInt(h0);\r
+ byteArray.writeInt(h1);\r
+ byteArray.writeInt(h2);\r
+ byteArray.writeInt(h3);\r
+ byteArray.writeInt(h4);\r
+ byteArray.position = 0;\r
+ \r
+ digest = new ByteArray();\r
+ digest.writeBytes(byteArray);\r
+ digest.position = 0;\r
+ return byteArray;\r
+ }\r
+\r
+ /**\r
+ * Performs the logical function based on t\r
+ */\r
+ private static function f( t:int, b:int, c:int, d:int ):int {\r
+ if ( t < 20 ) {\r
+ return ( b & c ) | ( ~b & d );\r
+ } else if ( t < 40 ) {\r
+ return b ^ c ^ d;\r
+ } else if ( t < 60 ) {\r
+ return ( b & c ) | ( b & d ) | ( c & d );\r
+ }\r
+ return b ^ c ^ d;\r
+ }\r
+ \r
+ /**\r
+ * Determines the constant value based on t\r
+ */\r
+ private static function k( t:int ):int {\r
+ if ( t < 20 ) {\r
+ return 0x5a827999;\r
+ } else if ( t < 40 ) {\r
+ return 0x6ed9eba1;\r
+ } else if ( t < 60 ) {\r
+ return 0x8f1bbcdc;\r
+ }\r
+ return 0xca62c1d6;\r
+ }\r
+ \r
+ /**\r
+ * Converts a ByteArray to a sequence of 16-word blocks\r
+ * that we'll do the processing on. Appends padding\r
+ * and length in the process.\r
+ *\r
+ * @param data The data to split into blocks\r
+ * @return An array containing the blocks into which data was split\r
+ */\r
+ private static function createBlocksFromByteArray( data:ByteArray ):Array\r
+ {\r
+ var oldPosition:int = data.position;\r
+ data.position = 0;\r
+ \r
+ var blocks:Array = new Array();\r
+ var len:int = data.length * 8;\r
+ var mask:int = 0xFF; // ignore hi byte of characters > 0xFF\r
+ for( var i:int = 0; i < len; i += 8 )\r
+ {\r
+ blocks[ i >> 5 ] |= ( data.readByte() & mask ) << ( 24 - i % 32 );\r
+ }\r
+ \r
+ // append padding and length\r
+ blocks[ len >> 5 ] |= 0x80 << ( 24 - len % 32 );\r
+ blocks[ ( ( ( len + 64 ) >> 9 ) << 4 ) + 15 ] = len;\r
+ \r
+ data.position = oldPosition;\r
+ \r
+ return blocks;\r
+ }\r
+ \r
+ /**\r
+ * Converts a string to a sequence of 16-word blocks\r
+ * that we'll do the processing on. Appends padding\r
+ * and length in the process.\r
+ *\r
+ * @param s The string to split into blocks\r
+ * @return An array containing the blocks that s was split into.\r
+ */\r
+ private static function createBlocksFromString( s:String ):Array\r
+ {\r
+ var blocks:Array = new Array();\r
+ var len:int = s.length * 8;\r
+ var mask:int = 0xFF; // ignore hi byte of characters > 0xFF\r
+ for( var i:int = 0; i < len; i += 8 ) {\r
+ blocks[ i >> 5 ] |= ( s.charCodeAt( i / 8 ) & mask ) << ( 24 - i % 32 );\r
+ }\r
+ \r
+ // append padding and length\r
+ blocks[ len >> 5 ] |= 0x80 << ( 24 - len % 32 );\r
+ blocks[ ( ( ( len + 64 ) >> 9 ) << 4 ) + 15 ] = len;\r
+ return blocks;\r
+ }\r
+ \r
+ }\r
+}\r