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