142 lines
3.4 KiB
ActionScript
142 lines
3.4 KiB
ActionScript
/**
|
|
* 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<ba.length;i++) {
|
|
ba[i]=0;
|
|
}
|
|
ba.length=0;
|
|
return null;
|
|
}
|
|
private function more_md5():void {
|
|
d1.position=0;
|
|
d1.writeBytes(a1);
|
|
var p:int = p1.position;
|
|
var more:ByteArray = hmac_md5.compute(s1, d1);
|
|
a1 = hmac_md5.compute(s1, a1);
|
|
p1.writeBytes(more);
|
|
p1.position=p;
|
|
}
|
|
private function more_sha1():void {
|
|
d2.position=0;
|
|
d2.writeBytes(a2);
|
|
var p:int = p2.position;
|
|
var more:ByteArray = hmac_sha1.compute(s2, d2);
|
|
a2 = hmac_sha1.compute(s2, a2);
|
|
p2.writeBytes(more);
|
|
p2.position=p;
|
|
}
|
|
|
|
}
|
|
} |