/** * TLSPRF * * An ActionScript 3 implementation of a pseudo-random generator * that follows the TLS specification * Copyright (c) 2007 Henri Torgemane * * See LICENSE.txt for full license information. */ package com.hurlant.crypto.prng { import flash.utils.ByteArray; import com.hurlant.crypto.hash.HMAC; import com.hurlant.crypto.hash.MD5; import com.hurlant.crypto.hash.SHA1; import com.hurlant.util.Memory; import com.hurlant.util.Hex; import flash.utils.IDataOutput; /** * There's "Random", and then there's TLS Random. * . * Still Pseudo-random, though. */ public class TLSPRF { // XXX WAY TOO MANY STRUCTURES HERE // seed private var seed:ByteArray; // P_MD5's secret private var s1:ByteArray; // P_SHA-1's secret private var s2:ByteArray; // HMAC_MD5's A private var a1:ByteArray; // HMAC_SHA1's A private var a2:ByteArray; // Pool for P_MD5 private var p1:ByteArray; // Pool for P_SHA1 private var p2:ByteArray; // Data for HMAC_MD5 private var d1:ByteArray; // Data for HMAC_SHA1 private var d2:ByteArray; private var hmac_md5:HMAC; private var hmac_sha1:HMAC; public function TLSPRF(secret:ByteArray, label:String, seed:ByteArray) { var l:int = Math.ceil(secret.length/2); var s1:ByteArray = new ByteArray; var s2:ByteArray = new ByteArray; s1.writeBytes(secret, 0, l); s2.writeBytes(secret, secret.length-l, l); var s:ByteArray = new ByteArray; s.writeUTFBytes(label); s.writeBytes(seed); this.seed = s; this.s1 = s1; this.s2 = s2; hmac_md5 = new HMAC(new MD5); hmac_sha1 = new HMAC(new SHA1); this.a1 = hmac_md5.compute(s1, this.seed); this.a2 = hmac_sha1.compute(s2, this.seed); p1 = new ByteArray; p2 = new ByteArray; d1 = new ByteArray; d2 = new ByteArray; d1.position = MD5.HASH_SIZE; d1.writeBytes(this.seed); d2.position = SHA1.HASH_SIZE; d2.writeBytes(this.seed); } // XXX HORRIBLY SLOW. REWRITE. public function nextBytes(buffer:IDataOutput, length:int):void { while (length--) { buffer.writeByte(nextByte()); } } public function nextByte():int { if (p1.bytesAvailable==0) { more_md5(); } if (p2.bytesAvailable==0) { more_sha1(); } return p1.readUnsignedByte()^p2.readUnsignedByte(); } public function dispose():void { seed = dba(seed); s1 = dba(s1); s2 = dba(s2); a1 = dba(a1); a2 = dba(a2); p1 = dba(p1); p2 = dba(p2); d1 = dba(d1); d2 = dba(d2); hmac_md5.dispose(); hmac_md5 = null; hmac_sha1.dispose(); hmac_sha1 = null; Memory.gc(); } public function toString():String { return "tls-prf"; } private function dba(ba:ByteArray):ByteArray { for (var i:uint=0;i