Commit 0e486e1b authored by Joel Martin's avatar Joel Martin

Import as3crypto_patch: ffda6e9cd8b1d74f45472c676afda8360ae1e5aa

as3crypto is actionscript 3 crypto library with TLS engine support.

From: http://github.com/lyokato/as3crypto_patched

Which was forked from: http://code.google.com/p/as3crypto/
parent 7b99f70b
This software is covered under the following copyright:
/*
* Copyright (c) 2007 Henri Torgemane
* All Rights Reserved.
*
* BigInteger, RSA, Random and ARC4 are derivative works of the jsbn library
* (http://www-cs-students.stanford.edu/~tjw/jsbn/)
* The jsbn library is Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
*
* MD5, SHA1, and SHA256 are derivative works (http://pajhome.org.uk/crypt/md5/)
* Those are Copyright (c) 1998-2002 Paul Johnston & Contributors (paj@pajhome.org.uk)
*
* SHA256 is a derivative work of jsSHA2 (http://anmar.eu.org/projects/jssha2/)
* jsSHA2 is Copyright (c) 2003-2004 Angel Marin (anmar@gmx.net)
*
* AESKey is a derivative work of aestable.c (http://www.geocities.com/malbrain/aestable_c.html)
* aestable.c is Copyright (c) Karl Malbrain (malbrain@yahoo.com)
*
* BlowFishKey, DESKey and TripeDESKey are derivative works of the Bouncy Castle Crypto Package (http://www.bouncycastle.org)
* Those are Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
*
* Base64 is copyright (c) 2006 Steve Webster (http://dynamicflash.com/goodies/base64)
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer. Redistributions in binary form must
* reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of the author nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior written permission.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
Address all questions regarding this license to:
Henri Torgemane
henri_torgemane@yahoo.com
Additionally, the MD5 algorithm is covered by the following notice:
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
*
* License to copy and use this software is granted provided that it
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
* Algorithm" in all material mentioning or referencing this software
* or this function.
*
* License is also granted to make and use derivative works provided
* that such works are identified as "derived from the RSA Data
* Security, Inc. MD5 Message-Digest Algorithm" in all material
* mentioning or referencing the derived work.
*
* RSA Data Security, Inc. makes no representations concerning either
* the merchantability of this software or the suitability of this
* software for any particular purpose. It is provided "as is"
* without express or implied warranty of any kind.
*
* These notices must be retained in any copies of any part of this
* documentation and/or software.
*/
= DESCRIPTION
as3crypto 1.3 has some bugs, at r28(latest version of original svn-repository),
many of them are fixed, but there are another bugs around a new ASN1 parser.
so I copied some features from r28 to 1.3
version, and fixed them to be built without error.
and added build-swc.xml
= LICENSE
See LICENCE.txt,
require 'rubygems'
require 'airake'
ENV["AIRAKE_ROOT"] = File.dirname(__FILE__)
ENV["AIRAKE_ENV"] = "development"
# Aliases
task :test => [ "air:test" ] do; end
task :compile => [ "air:compile" ] do; end
task :package => [ "air:package" ] do; end
task :certificate => [ "air:certificate" ] do; end
task :adl => [ "air:adl" ] do; end
task :docs => [ "air:docs" ] do; end
task :clean => [ "air:clean" ] do; end
task :acompc => [ "air:acompc" ] do; end
\ No newline at end of file
---
mxml_path: src/As3crypto.mxml
appxml_path: src/As3crypto-app.xml
src_dirs: [ 'src' ]
lib_dir: lib
air_path: bin/As3crypto.air
swf_path: bin/As3crypto.swf
assets: src/assets
certificate: cert.pfx
development:
debug: true
test:
swf_path: bin/Test.swf
mxml_path: test/Test.mxml
appxml_path: test/Test-app.xml
src_dirs: [ 'src', 'test' ]
debug: true
\ No newline at end of file
<!--
To build as3crypto.swc, use
compc -load-config=build-swc.xml
If you need Flash Player 9 support, change the path below to something more
appropriate for your SDK and/or Player version
-->
<flex-config>
<benchmark>true</benchmark>
<compiler>
<external-library-path>
<path-element>${flexlib}/libs/player/10.0/playerglobal.swc</path-element>
</external-library-path>
<source-path>
<path-element>./src</path-element>
</source-path>
</compiler>
<include-classes>
<class>com.hurlant.crypto.Crypto</class>
<class>com.hurlant.crypto.cert.MozillaRootCertificates</class>
<class>com.hurlant.crypto.cert.X509Certificate</class>
<class>com.hurlant.crypto.cert.X509CertificateCollection</class>
<class>com.hurlant.crypto.hash.HMAC</class>
<class>com.hurlant.crypto.hash.IHMAC</class>
<class>com.hurlant.crypto.hash.IHash</class>
<class>com.hurlant.crypto.hash.MAC</class>
<class>com.hurlant.crypto.hash.MD2</class>
<class>com.hurlant.crypto.hash.MD5</class>
<class>com.hurlant.crypto.hash.SHA1</class>
<class>com.hurlant.crypto.hash.SHA224</class>
<class>com.hurlant.crypto.hash.SHA256</class>
<class>com.hurlant.crypto.hash.SHABase</class>
<class>com.hurlant.crypto.prng.ARC4</class>
<class>com.hurlant.crypto.prng.IPRNG</class>
<class>com.hurlant.crypto.prng.Random</class>
<class>com.hurlant.crypto.prng.TLSPRF</class>
<class>com.hurlant.crypto.rsa.RSAKey</class>
<class>com.hurlant.crypto.symmetric.AESKey</class>
<class>com.hurlant.crypto.symmetric.BlowFishKey</class>
<class>com.hurlant.crypto.symmetric.CBCMode</class>
<class>com.hurlant.crypto.symmetric.CFB8Mode</class>
<class>com.hurlant.crypto.symmetric.CFBMode</class>
<class>com.hurlant.crypto.symmetric.CTRMode</class>
<class>com.hurlant.crypto.symmetric.DESKey</class>
<class>com.hurlant.crypto.symmetric.ECBMode</class>
<class>com.hurlant.crypto.symmetric.ICipher</class>
<class>com.hurlant.crypto.symmetric.IMode</class>
<class>com.hurlant.crypto.symmetric.IPad</class>
<class>com.hurlant.crypto.symmetric.IStreamCipher</class>
<class>com.hurlant.crypto.symmetric.ISymmetricKey</class>
<class>com.hurlant.crypto.symmetric.IVMode</class>
<class>com.hurlant.crypto.symmetric.NullPad</class>
<class>com.hurlant.crypto.symmetric.OFBMode</class>
<class>com.hurlant.crypto.symmetric.PKCS5</class>
<class>com.hurlant.crypto.symmetric.SimpleIVMode</class>
<class>com.hurlant.crypto.symmetric.TLSPad</class>
<class>com.hurlant.crypto.symmetric.SSLPad</class>
<class>com.hurlant.crypto.symmetric.TripleDESKey</class>
<class>com.hurlant.crypto.symmetric.XTeaKey</class>
<class>com.hurlant.crypto.tls.BulkCiphers</class>
<class>com.hurlant.crypto.tls.CipherSuites</class>
<class>com.hurlant.crypto.tls.KeyExchanges</class>
<class>com.hurlant.crypto.tls.MACs</class>
<class>com.hurlant.crypto.tls.TLSConfig</class>
<class>com.hurlant.crypto.tls.IConnectionState</class>
<class>com.hurlant.crypto.tls.TLSConnectionState</class>
<class>com.hurlant.crypto.tls.SSLConnectionState</class>
<class>com.hurlant.crypto.tls.TLSEngine</class>
<class>com.hurlant.crypto.tls.TLSError</class>
<class>com.hurlant.crypto.tls.TLSSocketEvent</class>
<class>com.hurlant.crypto.tls.TLSEvent</class>
<class>com.hurlant.crypto.tls.SSLEvent</class>
<class>com.hurlant.crypto.tls.ISecurityParameters</class>
<class>com.hurlant.crypto.tls.TLSSecurityParameters</class>
<class>com.hurlant.crypto.tls.SSLSecurityParameters</class>
<class>com.hurlant.crypto.tls.TLSSocket</class>
<class>com.hurlant.util.ArrayUtil</class>
<class>com.hurlant.util.Base64</class>
<class>com.hurlant.util.Hex</class>
<class>com.hurlant.util.Memory</class>
<class>com.hurlant.util.der.ByteString</class>
<class>com.hurlant.util.der.DER</class>
<class>com.hurlant.util.der.IAsn1Type</class>
<class>com.hurlant.util.der.Integer</class>
<class>com.hurlant.util.der.OID</class>
<class>com.hurlant.util.der.ObjectIdentifier</class>
<class>com.hurlant.util.der.PEM</class>
<class>com.hurlant.util.der.PrintableString</class>
<class>com.hurlant.util.der.Sequence</class>
<class>com.hurlant.util.der.Set</class>
<class>com.hurlant.util.der.Type</class>
<class>com.hurlant.util.der.UTCTime</class>
<class>com.hurlant.math.BarrettReduction</class>
<class>com.hurlant.math.BigInteger</class>
<class>com.hurlant.math.ClassicReduction</class>
<class>com.hurlant.math.IReduction</class>
<class>com.hurlant.math.MontgomeryReduction</class>
<class>com.hurlant.math.NullReduction</class>
<class>com.hurlant.math.bi_internal</class>
</include-classes>
<metadata>
<creator>Henri Torgemane</creator>
<description>http://crypto.hurlant.com/</description>
<language>EN</language>
<title>AS3 Cryptography Library</title>
</metadata>
<output>bin/as3crypto_patched.swc</output>
</flex-config>
#!/usr/bin/env ruby
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
begin
require 'rubigen'
rescue LoadError
require 'rubygems'
require 'rubigen'
end
require 'rubigen/scripts/destroy'
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
RubiGen::Base.use_component_sources! [:air, :airake, :test_unit]
RubiGen::Scripts::Destroy.new.run(ARGV)
#!/usr/bin/env ruby
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
begin
require 'rubigen'
rescue LoadError
require 'rubygems'
require 'rubigen'
end
require 'rubigen/scripts/generate'
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
RubiGen::Base.use_component_sources! [:air, :airake, :test_unit]
RubiGen::Scripts::Generate.new.run(ARGV)
/**
* Crypto
*
* An abstraction layer to instanciate our crypto algorithms
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto
{
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.MAC;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.hash.MD2;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.crypto.hash.SHA224;
import com.hurlant.crypto.hash.SHA256;
import com.hurlant.crypto.prng.ARC4;
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.BlowFishKey;
import com.hurlant.crypto.symmetric.CBCMode;
import com.hurlant.crypto.symmetric.CFB8Mode;
import com.hurlant.crypto.symmetric.CFBMode;
import com.hurlant.crypto.symmetric.CTRMode;
import com.hurlant.crypto.symmetric.DESKey;
import com.hurlant.crypto.symmetric.ECBMode;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IMode;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ISymmetricKey;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.crypto.symmetric.OFBMode;
import com.hurlant.crypto.symmetric.PKCS5;
import com.hurlant.crypto.symmetric.SimpleIVMode;
import com.hurlant.crypto.symmetric.TripleDESKey;
import com.hurlant.crypto.symmetric.XTeaKey;
import com.hurlant.util.Base64;
import flash.utils.ByteArray;
/**
* A class to make it easy to use the rest of the framework.
* As a side-effect, using this class will cause most of the framework
* to be linked into your application, which is not always what you want.
*
* If you want to optimize your download size, don't use this class.
* (But feel free to read it to get ideas on how to get the algorithm you want.)
*/
public class Crypto
{
private var b64:Base64; // we don't use it, but we want the swc to include it, so cheap trick.
public function Crypto(){
}
/**
* Things that should work, among others:
* "aes"
* "aes-128-ecb"
* "aes-128-cbc"
* "aes-128-cfb"
* "aes-128-cfb8"
* "aes-128-ofb"
* "aes-192-cfb"
* "aes-256-ofb"
* "blowfish-cbc"
* "des-ecb"
* "xtea"
* "xtea-ecb"
* "xtea-cbc"
* "xtea-cfb"
* "xtea-cfb8"
* "xtea-ofb"
* "rc4"
* "simple-aes-cbc"
*/
public static function getCipher(name:String, key:ByteArray, pad:IPad=null):ICipher {
// split name into an array.
var keys:Array = name.split("-");
switch (keys[0]) {
/**
* "simple" is a special case. It means:
* "If using an IV mode, prepend the IV to the ciphertext"
*/
case "simple":
keys.shift();
name = keys.join("-");
var cipher:ICipher = getCipher(name, key, pad);
if (cipher is IVMode) {
return new SimpleIVMode(cipher as IVMode);
} else {
return cipher;
}
/**
* we support both "aes-128" and "aes128"
* Technically, you could use "aes192-128", but you'd
* only be hurting yourself.
*/
case "aes":
case "aes128":
case "aes192":
case "aes256":
keys.shift();
if (key.length*8==keys[0]) {
// support for "aes-128-..." and such.
keys.shift();
}
return getMode(keys[0], new AESKey(key), pad);
break;
case "bf":
case "blowfish":
keys.shift();
return getMode(keys[0], new BlowFishKey(key), pad);
/**
* des-ede and des-ede3 are both equivalent to des3.
* the choice between 2tdes and 3tdes is made based
* on the length of the key provided.
*/
case "des":
keys.shift();
if (keys[0]!="ede" && keys[0]!="ede3") {
return getMode(keys[0], new DESKey(key), pad);
}
if (keys.length==1) {
keys.push("ecb"); // default mode for 2tdes and 3tdes with openssl enc
}
// fall-through to triple des
case "3des":
case "des3":
keys.shift();
return getMode(keys[0], new TripleDESKey(key), pad);
case "xtea":
keys.shift();
return getMode(keys[0], new XTeaKey(key), pad);
break;
/**
* Technically, you could say "rc4-128" or whatever,
* but really, the length of the key is what counts here.
*/
case "rc4":
keys.shift();
return new ARC4(key);
break;
}
return null;
}
/**
* Returns the size of a key for a given cipher identifier.
*/
public static function getKeySize(name:String):uint {
var keys:Array = name.split("-");
switch (keys[0]) {
case "simple":
keys.shift();
return getKeySize(keys.join("-"));
case "aes128":
return 16;
case "aes192":
return 24;
case "aes256":
return 32;
case "aes":
keys.shift();
return parseInt(keys[0])/8;
case "bf":
case "blowfish":
return 16;
case "des":
keys.shift();
switch (keys[0]) {
case "ede":
return 16;
case "ede3":
return 24;
default:
return 8;
}
case "3des":
case "des3":
return 24;
case "xtea":
return 8;
case "rc4":
if (parseInt(keys[1])>0) {
return parseInt(keys[1])/8;
}
return 16; // why not.
}
return 0; // unknown;
}
private static function getMode(name:String, alg:ISymmetricKey, padding:IPad=null):IMode {
switch (name) {
case "ecb":
return new ECBMode(alg, padding);
case "cfb":
return new CFBMode(alg, padding);
case "cfb8":
return new CFB8Mode(alg, padding);
case "ofb":
return new OFBMode(alg, padding);
case "ctr":
return new CTRMode(alg, padding);
case "cbc":
default:
return new CBCMode(alg, padding);
}
}
/**
* Things that should work:
* "md5"
* "sha"
* "sha1"
* "sha224"
* "sha256"
*/
public static function getHash(name:String):IHash {
switch(name) {
case "md2":
return new MD2;
case "md5":
return new MD5;
case "sha": // let's hope you didn't mean sha-0
case "sha1":
return new SHA1;
case "sha224":
return new SHA224;
case "sha256":
return new SHA256;
}
return null;
}
/**
* Things that should work:
* "sha1"
* "md5-64"
* "hmac-md5-96"
* "hmac-sha1-128"
* "hmac-sha256-192"
* etc.
*/
public static function getHMAC(name:String):HMAC {
var keys:Array = name.split("-");
if (keys[0]=="hmac") keys.shift();
var bits:uint = 0;
if (keys.length>1) {
bits = parseInt(keys[1]);
}
return new HMAC(getHash(keys[0]), bits);
}
public static function getMAC(name:String):MAC {
var keys:Array = name.split("-");
if (keys[0]=="mac") keys.shift();
var bits:uint = 0;
if (keys.length > 1) {
bits = parseInt(keys[1]);
}
return new MAC(getHash(keys[0]), bits);
}
public static function getPad(name:String):IPad {
switch(name) {
case "null":
return new NullPad;
case "pkcs5":
default:
return new PKCS5;
}
}
/** mostly useless.
*/
public static function getRSA(E:String, M:String):RSAKey {
return RSAKey.parsePublicKey(M,E);
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* X509Certificate
*
* A representation for a X509 Certificate, with
* methods to parse, verify and sign it.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.cert {
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.hash.MD2;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.util.ArrayUtil;
import com.hurlant.util.Base64;
import com.hurlant.util.der.ByteString;
import com.hurlant.util.der.DER;
import com.hurlant.util.der.OID;
import com.hurlant.util.der.ObjectIdentifier;
import com.hurlant.util.der.PEM;
import com.hurlant.util.der.PrintableString;
import com.hurlant.util.der.Sequence;
import com.hurlant.util.der.Type;
import flash.utils.ByteArray;
public class X509Certificate {
private var _loaded:Boolean;
private var _param:*;
private var _obj:Object;
public function X509Certificate(p:*) {
_loaded = false;
_param = p;
// lazy initialization, to avoid unnecessary parsing of every builtin CA at start-up.
}
private function load():void {
if (_loaded) return;
var p:* = _param;
var b:ByteArray;
if (p is String) {
b = PEM.readCertIntoArray(p as String);
} else if (p is ByteArray) {
b = p;
}
if (b!=null) {
_obj = DER.parse(b, Type.TLS_CERT);
_loaded = true;
} else {
throw new Error("Invalid x509 Certificate parameter: "+p);
}
}
public function isSigned(store:X509CertificateCollection, CAs:X509CertificateCollection, time:Date=null):Boolean {
load();
// check timestamps first. cheapest.
if (time==null) {
time = new Date;
}
var notBefore:Date = getNotBefore();
var notAfter:Date = getNotAfter();
if (time.getTime()<notBefore.getTime()) return false; // cert isn't born yet.
if (time.getTime()>notAfter.getTime()) return false; // cert died of old age.
// check signature.
var subject:String = getIssuerPrincipal();
// try from CA first, since they're treated better.
var parent:X509Certificate = CAs.getCertificate(subject);
var parentIsAuthoritative:Boolean = false;
if (parent == null) {
parent = store.getCertificate(subject);
if (parent == null) {
return false; // issuer not found
}
} else {
parentIsAuthoritative = true;
}
if (parent == this) { // pathological case. avoid infinite loop
return false; // isSigned() returns false if we're self-signed.
}
if (!(parentIsAuthoritative&&parent.isSelfSigned(time)) &&
!parent.isSigned(store, CAs, time)) {
return false;
}
var key:RSAKey = parent.getPublicKey();
return verifyCertificate(key);
}
public function isSelfSigned(time:Date):Boolean {
load();
var key:RSAKey = getPublicKey();
return verifyCertificate(key);
}
private function verifyCertificate(key:RSAKey):Boolean {
var algo:String = getAlgorithmIdentifier();
var hash:IHash;
var oid:String;
switch (algo) {
case OID.SHA1_WITH_RSA_ENCRYPTION:
hash = new SHA1;
oid = OID.SHA1_ALGORITHM;
break;
case OID.MD2_WITH_RSA_ENCRYPTION:
hash = new MD2;
oid = OID.MD2_ALGORITHM;
break;
case OID.MD5_WITH_RSA_ENCRYPTION:
hash = new MD5;
oid = OID.MD5_ALGORITHM;
break;
default:
return false;
}
var data:ByteArray = _obj.signedCertificate_bin;
var buf:ByteArray = new ByteArray;
key.verify(_obj.encrypted, buf, _obj.encrypted.length);
buf.position=0;
data = hash.hash(data);
var obj:Object = DER.parse(buf, Type.RSA_SIGNATURE);
if (obj.algorithm.algorithmId.toString() != oid) {
return false; // wrong algorithm
}
if (!ArrayUtil.equals(obj.hash, data)) {
return false; // hashes don't match
}
return true;
}
/**
* This isn't used anywhere so far.
* It would become useful if we started to offer facilities
* to generate and sign X509 certificates.
*
* @param key
* @param algo
* @return
*
*/
private function signCertificate(key:RSAKey, algo:String):ByteArray {
var hash:IHash;
var oid:String;
switch (algo) {
case OID.SHA1_WITH_RSA_ENCRYPTION:
hash = new SHA1;
oid = OID.SHA1_ALGORITHM;
break;
case OID.MD2_WITH_RSA_ENCRYPTION:
hash = new MD2;
oid = OID.MD2_ALGORITHM;
break;
case OID.MD5_WITH_RSA_ENCRYPTION:
hash = new MD5;
oid = OID.MD5_ALGORITHM;
break;
default:
return null
}
var data:ByteArray = _obj.signedCertificate_bin;
data = hash.hash(data);
var seq1:Sequence = new Sequence;
seq1[0] = new Sequence;
seq1[0][0] = new ObjectIdentifier(0,0, oid);
seq1[0][1] = null;
seq1[1] = new ByteString;
seq1[1].writeBytes(data);
data = seq1.toDER();
var buf:ByteArray = new ByteArray;
key.sign(data, buf, data.length);
return buf;
}
public function getPublicKey():RSAKey {
load();
var pk:ByteArray = _obj.signedCertificate.subjectPublicKeyInfo.subjectPublicKey as ByteArray;
pk.position = 0;
var rsaKey:Object = DER.parse(pk, [{name:"N"},{name:"E"}]);
return new RSAKey(rsaKey.N, rsaKey.E.valueOf());
}
/**
* Returns a subject principal, as an opaque base64 string.
* This is only used as a hash key for known certificates.
*
* Note that this assumes X509 DER-encoded certificates are uniquely encoded,
* as we look for exact matches between Issuer and Subject fields.
*
*/
public function getSubjectPrincipal():String {
load();
return Base64.encodeByteArray(_obj.signedCertificate.subject_bin);
}
/**
* Returns an issuer principal, as an opaque base64 string.
* This is only used to quickly find matching parent certificates.
*
* Note that this assumes X509 DER-encoded certificates are uniquely encoded,
* as we look for exact matches between Issuer and Subject fields.
*
*/
public function getIssuerPrincipal():String {
load();
return Base64.encodeByteArray(_obj.signedCertificate.issuer_bin);
}
public function getAlgorithmIdentifier():String {
return _obj.algorithmIdentifier.algorithmId.toString();
}
public function getNotBefore():Date {
return _obj.signedCertificate.validity.notBefore.date;
}
public function getNotAfter():Date {
return _obj.signedCertificate.validity.notAfter.date;
}
public function getCommonName():String {
var subject:Sequence = _obj.signedCertificate.subject;
return (subject.findAttributeValue(OID.COMMON_NAME) as PrintableString).getString();
}
}
}
\ No newline at end of file
/**
* X509CertificateCollection
*
* A class to store and index X509 Certificates by Subject.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.cert {
public class X509CertificateCollection {
private var _map:Object;
public function X509CertificateCollection() {
_map = {};
}
/**
* Mostly meant for built-in CA loading.
* This entry-point allows to index CAs without parsing them.
*
* @param name A friendly name. not currently used
* @param subject base64 DER encoded Subject principal for the Cert
* @param pem PEM encoded certificate data
*
*/
public function addPEMCertificate(name:String, subject:String, pem:String):void {
_map[subject] = new X509Certificate(pem);
}
/**
* Adds a X509 certificate to the collection.
* This call will force the certificate to be parsed.
*
* @param cert A X509 certificate
*
*/
public function addCertificate(cert:X509Certificate):void {
var subject:String = cert.getSubjectPrincipal();
_map[subject] = cert;
}
/**
* Returns a X509 Certificate present in the collection, given
* a base64 DER encoded X500 Subject principal
*
* @param subject A Base64 DER-encoded Subject principal
* @return A matching certificate, or null.
*
*/
public function getCertificate(subject:String):X509Certificate {
return _map[subject];
}
}
}
\ No newline at end of file
K 25
svn:wc:ra_dav:version-url
V 60
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash
END
MAC.as
K 25
svn:wc:ra_dav:version-url
V 67
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/MAC.as
END
IHMAC.as
K 25
svn:wc:ra_dav:version-url
V 69
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/IHMAC.as
END
MD2.as
K 25
svn:wc:ra_dav:version-url
V 67
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/MD2.as
END
SHA224.as
K 25
svn:wc:ra_dav:version-url
V 69
/svn/!svn/ver/3/trunk/as3crypto/src/com/hurlant/crypto/hash/SHA224.as
END
MD5.as
K 25
svn:wc:ra_dav:version-url
V 67
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/MD5.as
END
SHABase.as
K 25
svn:wc:ra_dav:version-url
V 71
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/SHABase.as
END
SHA256.as
K 25
svn:wc:ra_dav:version-url
V 70
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/SHA256.as
END
HMAC.as
K 25
svn:wc:ra_dav:version-url
V 68
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/HMAC.as
END
IHash.as
K 25
svn:wc:ra_dav:version-url
V 69
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/IHash.as
END
SHA1.as
K 25
svn:wc:ra_dav:version-url
V 68
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/hash/SHA1.as
END
10
dir
28
http://as3crypto.googlecode.com/svn/trunk/as3crypto/src/com/hurlant/crypto/hash
http://as3crypto.googlecode.com/svn
2009-06-04T23:35:21.192697Z
28
sh0rtwave
395c722c-794e-0410-9327-f1aa524df581
MAC.as
file
2009-11-07T06:59:45.000000Z
0bedba9be73ae40adeb26ca35c8237f4
2009-06-04T23:35:21.192697Z
28
sh0rtwave
has-props
3559
IHMAC.as
file
2009-11-07T06:59:45.000000Z
dac8b7d8c849fe11f90ec290aa5dedf0
2009-06-04T23:35:21.192697Z
28
sh0rtwave
has-props
599
MD2.as
file
2009-11-07T06:59:45.000000Z
73bf759d445a65186512066a103dbb45
2009-06-04T23:35:21.192697Z
28
sh0rtwave
3811
SHA224.as
file
2009-11-07T06:59:45.000000Z
026d3e96099de7100c1d49012720d6f9
2008-06-22T05:51:59.360556Z
3
henrit
604
MD5.as
file
2009-11-07T06:59:45.000000Z
60211f6583ee826e2a17ad03605aa7b4
2009-06-04T23:35:21.192697Z
28
sh0rtwave
6965
SHABase.as
file
2009-11-07T06:59:45.000000Z
aa1101bf874f26cd364cf16fb7dff6c7
2009-06-04T23:35:21.192697Z
28
sh0rtwave
1495
SHA256.as
file
2009-11-07T06:59:45.000000Z
c14bc0555970db81a87f5d2b60e4288c
2009-06-04T23:35:21.192697Z
28
sh0rtwave
3459
HMAC.as
file
2009-11-07T06:59:45.000000Z
c96c9bc0e0b64eed7e2d8c27dc29c561
2009-06-04T23:35:21.192697Z
28
sh0rtwave
2132
IHash.as
file
2009-11-07T06:59:45.000000Z
71f45750c456debd7ef1f74e6db9dc23
2009-06-04T23:35:21.192697Z
28
sh0rtwave
445
SHA1.as
file
2009-11-07T06:59:45.000000Z
ba97b95bebda5bdd3fe2063e9c7e21cd
2009-06-04T23:35:21.192697Z
28
sh0rtwave
2642
/**
* HMAC
*
* An ActionScript 3 implementation of HMAC, Keyed-Hashing for Message
* Authentication, as defined by RFC-2104
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
public class HMAC implements IHMAC
{
private var hash:IHash;
private var bits:uint;
/**
* Create a HMAC object, using a Hash function, and
* optionally a number of bits to return.
* The HMAC will be truncated to that size if needed.
*/
public function HMAC(hash:IHash, bits:uint=0) {
this.hash = hash;
this.bits = bits;
}
public function getHashSize():uint {
if (bits!=0) {
return bits/8;
} else {
return hash.getHashSize();
}
}
/**
* Compute a HMAC using a key and some data.
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
*/
public function compute(key:ByteArray, data:ByteArray):ByteArray {
var hashKey:ByteArray;
if (key.length>hash.getInputSize()) {
hashKey = hash.hash(key);
} else {
hashKey = new ByteArray;
hashKey.writeBytes(key);
}
while (hashKey.length<hash.getInputSize()) {
hashKey[hashKey.length]=0;
}
var innerKey:ByteArray = new ByteArray;
var outerKey:ByteArray = new ByteArray;
for (var i:uint=0;i<hashKey.length;i++) {
innerKey[i] = hashKey[i] ^ 0x36;
outerKey[i] = hashKey[i] ^ 0x5c;
}
// inner + data
innerKey.position = hashKey.length;
innerKey.writeBytes(data);
var innerHash:ByteArray = hash.hash(innerKey);
// outer + innerHash
outerKey.position = hashKey.length;
outerKey.writeBytes(innerHash);
var outerHash:ByteArray = hash.hash(outerKey);
if (bits>0 && bits<8*outerHash.length) {
outerHash.length = bits/8;
}
return outerHash;
}
public function dispose():void {
hash = null;
bits = 0;
}
public function toString():String {
return "hmac-"+(bits>0?bits+"-":"")+hash.toString();
}
}
}
\ No newline at end of file
/**
* HMAC
*
* An ActionScript 3 interface for HMAC & MAC
* implementations.
*
* Loosely copyrighted by Bobby Parker
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
public interface IHMAC
{
function getHashSize():uint;
/**
* Compute a HMAC using a key and some data.
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
*/
function compute(key:ByteArray, data:ByteArray):ByteArray;
function dispose():void;
function toString():String;
}
}
\ No newline at end of file
/**
* IHash
*
* An interface for each hash function to implement
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
public interface IHash
{
function getInputSize():uint;
function getHashSize():uint;
function hash(src:ByteArray):ByteArray;
function toString():String;
function getPadSize():int;
}
}
\ No newline at end of file
/**
* MAC
*
* An ActionScript 3 implementation of MAC, Message Authentication Code
* for use with SSL 3.0.
* Loosely copyrighted by Bobby Parker.
* As3crypto copyrighted by Henri Torgemane.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
public class MAC implements IHMAC
{
private var hash:IHash;
private var bits:uint;
private var pad_1:ByteArray;
private var pad_2:ByteArray;
private var innerHash:ByteArray;
private var outerHash:ByteArray;
private var outerKey:ByteArray;
private var innerKey:ByteArray;
/**
* Create a MAC object (for SSL 3.0 ) and
* optionally a number of bits to return.
* The MAC will be truncated to that size if needed.
*/
public function MAC(hash:IHash, bits:uint=0) {
this.hash = hash;
this.bits = bits;
innerHash = new ByteArray();
outerHash = new ByteArray();
innerKey = new ByteArray();
outerKey = new ByteArray();
if (hash != null) {
var pad_size:int = hash.getPadSize();
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < pad_size; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
}
public function setPadSize(pad_size:int) : void { }
public function getHashSize():uint {
if (bits!=0) {
return bits/8;
} else {
return hash.getHashSize();
}
}
/**
* Compute a MAC using a key and some data.
*
*/
public function compute(key:ByteArray, data:ByteArray):ByteArray {
// take that incoming key and do hash(key + pad_2 + hash(key + pad_1 + sequence + length + record)
// note that data = (sequence + type + length + record)
if (pad_1 == null) {
var pad_size:int = hash.getPadSize();
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < pad_size; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
// Do some preliminary checking on stuff
/*
if (key.length > hash.getInputSize()) {
hashKey = hash.hash(key);
} else {
hashKey = new ByteArray;
hashKey.writeBytes(key);
}
while (hashKey.length < hash.getInputSize() ) {
hashKey[hashKey.length] = 0;
} */
// Henri's conventions work just fine here..
innerKey.length = 0;
outerKey.length = 0;
// trace("MAC Key: " + Hex.fromArray(key));
// trace("Key Length: " + key.length);
// trace("Pad_1 : " + Hex.fromArray(pad_1));
// inner hash calc
innerKey.writeBytes(key);
innerKey.writeBytes(pad_1);
innerKey.writeBytes(data);
// trace("MAC Inner Key: " + Hex.fromArray(innerKey));
innerHash = hash.hash(innerKey);
// trace("MAC Inner Hash: " + Hex.fromArray(innerHash));
// outer hash calc
outerKey.writeBytes(key);
outerKey.writeBytes(pad_2);
outerKey.writeBytes(innerHash);
// trace("MAC Outer Key: " + Hex.fromArray(outerKey));
outerHash = hash.hash(outerKey);
if (bits > 0 && bits < 8*outerHash.length) {
outerHash.length = bits/8;
}
// trace("MAC for record: " + Hex.fromArray(outerHash));
return outerHash;
}
public function dispose():void {
hash = null;
bits = 0;
}
public function toString():String {
return "mac-"+(bits>0?bits+"-":"")+hash.toString();
}
}
}
\ No newline at end of file
/**
* MD2
*
* An ActionScript 3 implementation of the RSA Data Security, Inc MD2 Message
* Digest Algorithm, as defined in RFC 1319
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*
* Excerpt from http://en.wikipedia.org/wiki/MD2:
* >
* > Rogier and Chauvaud (1997) described collisions of MD2's compression function,
* > although they were unable to extend the attack to the full MD2.
* >
* > In 2004, MD2 was shown to be vulnerable to a preimage attack with time
* > complexity equivalent to 2104 applications of the compression function
* > (Muller, 2004).
* > The author concludes, "MD2 can no longer be considered a secure one-way
* > hash function".
*
* also, this implementaton is quite slow.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
public class MD2 implements IHash
{
public static const HASH_SIZE:int = 16;
public var pad_size:int = 48; // probably will never get used, only here for SSL 3.0 support
private static const S:Array = [ // PI Digits
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,
98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,
30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,
190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,
169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,
128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,
255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,
79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,
69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,
27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,
44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,
106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,
242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 ];
public function getInputSize():uint
{
return 16;
}
public function getPadSize():int {
return pad_size;
}
public function getHashSize():uint
{
return HASH_SIZE;
}
public function hash(src:ByteArray):ByteArray
{
var savedLength:uint = src.length;
// 3.1 Step 1. Padding
var i:uint = (16-src.length%16) || 16;
do {
src[src.length]=i;
} while (src.length%16!=0);
// 3.2 Step 2. Checksum
var len:uint = src.length;
var checksum:ByteArray = new ByteArray;
var L:uint = 0;
for (i = 0;i<len;i+=16) {
for (var j:uint=0;j<16;j++) {
L = checksum[j] ^= S[src[i+j] ^ L];
}
}
src.position = src.length;
src.writeBytes(checksum);
len += 16;
// 3.3 Step 3. MD Buffer
var X:ByteArray = new ByteArray;
// 3.4 Process Message
for (i=0;i<len;i+=16) {
/* Copy block i into X */
for (j=0;j<16;j++) {
X[32+j] = (X[16+j] = src[i+j])^X[j];
}
var t:uint=0;
/* Do 18 rounds */
for (j=0;j<18;j++) {
/* Round j. */
for (var k:uint=0;k<48;k++) {
X[k] = t = X[k]^S[t];
}
t = (t+j)&0xff;
}
}
// 3.5 Step 5. Output
X.length = 16;
// restore original length;
src.length = savedLength;
return X;
}
public function toString():String
{
return "md2";
}
}
}
\ No newline at end of file
/**
* MD5
*
* An ActionScript 3 implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Copyright (c) 2007 Henri Torgemane
*
* Derived from
* A JavaScript implementation of the same.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* Note:
* This algorithm should not be your first choice for new developements, but is
* included to allow interoperability with existing codes and protocols.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class MD5 implements IHash
{
public static const HASH_SIZE:int = 16;
public var pad_size:int = 48;
public function getInputSize():uint
{
return 64;
}
public function getHashSize():uint
{
return HASH_SIZE;
}
public function getPadSize():int
{
return pad_size;
}
public function hash(src:ByteArray):ByteArray
{
var len:uint = src.length *8;
var savedEndian:String = src.endian;
// pad to nearest int.
while (src.length%4!=0) {
src[src.length]=0;
}
// convert ByteArray to an array of uint
src.position=0;
var a:Array = [];
src.endian=Endian.LITTLE_ENDIAN
for (var i:uint=0;i<src.length;i+=4) {
a.push(src.readUnsignedInt());
}
var h:Array = core_md5(a, len);
var out:ByteArray = new ByteArray;
out.endian=Endian.LITTLE_ENDIAN;
for (i=0;i<4;i++) {
out.writeUnsignedInt(h[i]);
}
// restore length!
src.length = len/8;
src.endian = savedEndian;
return out;
}
private function core_md5(x:Array, len:uint):Array {
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a:uint = 0x67452301; // 1732584193;
var b:uint = 0xEFCDAB89; //-271733879;
var c:uint = 0x98BADCFE; //-1732584194;
var d:uint = 0x10325476; // 271733878;
for(var i:uint = 0; i < x.length; i += 16)
{
x[i]||=0; x[i+1]||=0; x[i+2]||=0; x[i+3]||=0;
x[i+4]||=0; x[i+5]||=0; x[i+6]||=0; x[i+7]||=0;
x[i+8]||=0; x[i+9]||=0; x[i+10]||=0; x[i+11]||=0;
x[i+12]||=0; x[i+13]||=0; x[i+14]||=0; x[i+15]||=0;
var olda:uint = a;
var oldb:uint = b;
var oldc:uint = c;
var oldd:uint = d;
a = ff(a, b, c, d, x[i+ 0], 7 , 0xD76AA478);
d = ff(d, a, b, c, x[i+ 1], 12, 0xE8C7B756);
c = ff(c, d, a, b, x[i+ 2], 17, 0x242070DB);
b = ff(b, c, d, a, x[i+ 3], 22, 0xC1BDCEEE);
a = ff(a, b, c, d, x[i+ 4], 7 , 0xF57C0FAF);
d = ff(d, a, b, c, x[i+ 5], 12, 0x4787C62A);
c = ff(c, d, a, b, x[i+ 6], 17, 0xA8304613);
b = ff(b, c, d, a, x[i+ 7], 22, 0xFD469501);
a = ff(a, b, c, d, x[i+ 8], 7 , 0x698098D8);
d = ff(d, a, b, c, x[i+ 9], 12, 0x8B44F7AF);
c = ff(c, d, a, b, x[i+10], 17, 0xFFFF5BB1);
b = ff(b, c, d, a, x[i+11], 22, 0x895CD7BE);
a = ff(a, b, c, d, x[i+12], 7 , 0x6B901122);
d = ff(d, a, b, c, x[i+13], 12, 0xFD987193);
c = ff(c, d, a, b, x[i+14], 17, 0xA679438E);
b = ff(b, c, d, a, x[i+15], 22, 0x49B40821);
a = gg(a, b, c, d, x[i+ 1], 5 , 0xf61e2562);
d = gg(d, a, b, c, x[i+ 6], 9 , 0xc040b340);
c = gg(c, d, a, b, x[i+11], 14, 0x265e5a51);
b = gg(b, c, d, a, x[i+ 0], 20, 0xe9b6c7aa);
a = gg(a, b, c, d, x[i+ 5], 5 , 0xd62f105d);
d = gg(d, a, b, c, x[i+10], 9 , 0x2441453);
c = gg(c, d, a, b, x[i+15], 14, 0xd8a1e681);
b = gg(b, c, d, a, x[i+ 4], 20, 0xe7d3fbc8);
a = gg(a, b, c, d, x[i+ 9], 5 , 0x21e1cde6);
d = gg(d, a, b, c, x[i+14], 9 , 0xc33707d6);
c = gg(c, d, a, b, x[i+ 3], 14, 0xf4d50d87);
b = gg(b, c, d, a, x[i+ 8], 20, 0x455a14ed);
a = gg(a, b, c, d, x[i+13], 5 , 0xa9e3e905);
d = gg(d, a, b, c, x[i+ 2], 9 , 0xfcefa3f8);
c = gg(c, d, a, b, x[i+ 7], 14, 0x676f02d9);
b = gg(b, c, d, a, x[i+12], 20, 0x8d2a4c8a);
a = hh(a, b, c, d, x[i+ 5], 4 , 0xfffa3942);
d = hh(d, a, b, c, x[i+ 8], 11, 0x8771f681);
c = hh(c, d, a, b, x[i+11], 16, 0x6d9d6122);
b = hh(b, c, d, a, x[i+14], 23, 0xfde5380c);
a = hh(a, b, c, d, x[i+ 1], 4 , 0xa4beea44);
d = hh(d, a, b, c, x[i+ 4], 11, 0x4bdecfa9);
c = hh(c, d, a, b, x[i+ 7], 16, 0xf6bb4b60);
b = hh(b, c, d, a, x[i+10], 23, 0xbebfbc70);
a = hh(a, b, c, d, x[i+13], 4 , 0x289b7ec6);
d = hh(d, a, b, c, x[i+ 0], 11, 0xeaa127fa);
c = hh(c, d, a, b, x[i+ 3], 16, 0xd4ef3085);
b = hh(b, c, d, a, x[i+ 6], 23, 0x4881d05);
a = hh(a, b, c, d, x[i+ 9], 4 , 0xd9d4d039);
d = hh(d, a, b, c, x[i+12], 11, 0xe6db99e5);
c = hh(c, d, a, b, x[i+15], 16, 0x1fa27cf8);
b = hh(b, c, d, a, x[i+ 2], 23, 0xc4ac5665);
a = ii(a, b, c, d, x[i+ 0], 6 , 0xf4292244);
d = ii(d, a, b, c, x[i+ 7], 10, 0x432aff97);
c = ii(c, d, a, b, x[i+14], 15, 0xab9423a7);
b = ii(b, c, d, a, x[i+ 5], 21, 0xfc93a039);
a = ii(a, b, c, d, x[i+12], 6 , 0x655b59c3);
d = ii(d, a, b, c, x[i+ 3], 10, 0x8f0ccc92);
c = ii(c, d, a, b, x[i+10], 15, 0xffeff47d);
b = ii(b, c, d, a, x[i+ 1], 21, 0x85845dd1);
a = ii(a, b, c, d, x[i+ 8], 6 , 0x6fa87e4f);
d = ii(d, a, b, c, x[i+15], 10, 0xfe2ce6e0);
c = ii(c, d, a, b, x[i+ 6], 15, 0xa3014314);
b = ii(b, c, d, a, x[i+13], 21, 0x4e0811a1);
a = ii(a, b, c, d, x[i+ 4], 6 , 0xf7537e82);
d = ii(d, a, b, c, x[i+11], 10, 0xbd3af235);
c = ii(c, d, a, b, x[i+ 2], 15, 0x2ad7d2bb);
b = ii(b, c, d, a, x[i+ 9], 21, 0xeb86d391);
a += olda;
b += oldb;
c += oldc;
d += oldd;
}
return [ a, b, c, d ];
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
private function rol(num:uint, cnt:uint):uint
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
private function cmn(q:uint, a:uint, b:uint, x:uint, s:uint, t:uint):uint {
return rol(a + q + x + t, s) + b;
}
private function ff(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
private function gg(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
private function hh(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
private function ii(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
public function toString():String {
return "md5";
}
}
}
\ No newline at end of file
/**
* SHA1
*
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
public class SHA1 extends SHABase implements IHash
{
public static const HASH_SIZE:int = 20;
public override function getHashSize():uint {
return HASH_SIZE;
}
protected override function core(x:Array, len:uint):Array
{
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w:Array = [];
var a:uint = 0x67452301; //1732584193;
var b:uint = 0xEFCDAB89; //-271733879;
var c:uint = 0x98BADCFE; //-1732584194;
var d:uint = 0x10325476; //271733878;
var e:uint = 0xC3D2E1F0; //-1009589776;
for(var i:uint = 0; i < x.length; i += 16)
{
var olda:uint = a;
var oldb:uint = b;
var oldc:uint = c;
var oldd:uint = d;
var olde:uint = e;
for(var j:uint = 0; j < 80; j++)
{
if (j < 16) {
w[j] = x[i + j] || 0;
} else {
w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
}
var t:uint = rol(a,5) + ft(j,b,c,d) + e + w[j] + kt(j);
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a += olda;
b += oldb;
c += oldc;
d += oldd;
e += olde;
}
return [ a, b, c, d, e ];
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
private function rol(num:uint, cnt:uint):uint
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
private function ft(t:uint, b:uint, c:uint, d:uint):uint
{
if(t < 20) return (b & c) | ((~b) & d);
if(t < 40) return b ^ c ^ d;
if(t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
private function kt(t:uint):uint
{
return (t < 20) ? 0x5A827999 : (t < 40) ? 0x6ED9EBA1 :
(t < 60) ? 0x8F1BBCDC : 0xCA62C1D6;
}
public override function toString():String {
return "sha1";
}
}
}
/**
* SHA224
*
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-224, as defined
* in FIPS PUB 180-2
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
public class SHA224 extends SHA256
{
function SHA224() {
h = [
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
];
}
public override function getHashSize():uint {
return 28;
}
public override function toString():String {
return "sha224";
}
}
}
\ No newline at end of file
/**
* SHA256
*
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-256, as defined
* in FIPS PUB 180-2
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* A JavaScript implementation of the Secure Hash Standard
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
* Derived from:
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
public class SHA256 extends SHABase implements IHash
{
protected static const k: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];
protected var h:Array = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
public function SHA256(){
}
public override function getHashSize():uint
{
return 32;
}
protected override function core(x:Array, len:uint):Array {
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w:Array = [];
var a:uint = h[0];
var b:uint = h[1];
var c:uint = h[2];
var d:uint = h[3];
var e:uint = h[4];
var f:uint = h[5];
var g:uint = h[6];
var h:uint = h[7];
for (var i:uint=0; i<x.length; i+=16) {
var olda:uint = a;
var oldb:uint = b;
var oldc:uint = c;
var oldd:uint = d;
var olde:uint = e;
var oldf:uint = f;
var oldg:uint = g;
var oldh:uint = h;
for (var j:uint=0; j<64; j++) {
if (j<16) {
w[j] = x[i+j] || 0;
} else {
var s0:uint = rrol(w[j-15],7)^rrol(w[j-15],18)^(w[j-15]>>>3);
var s1:uint = rrol(w[j-2], 17)^rrol(w[j-2],19)^(w[j-2]>>>10);
w[j] = w[j-16] + s0 + w[j-7] + s1;
}
var t2:uint = (rrol(a,2) ^ rrol(a,13) ^ rrol(a,22)) + ((a&b) ^ (a&c) ^ (b&c));
var t1:uint = h + (rrol(e,6) ^ rrol(e,11) ^ rrol(e,25)) + ((e&f)^(g&~e)) + k[j] + w[j]
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
a += olda;
b += oldb;
c += oldc;
d += oldd;
e += olde;
f += oldf;
g += oldg;
h += oldh;
}
return [ a,b,c,d,e,f,g,h ];
}
/*
* Bitwise rotate a 32-bit number to the right.
*/
protected function rrol(num:uint, cnt:uint):uint {
return (num << (32-cnt)) | (num >>> cnt);
}
public override function toString():String {
return "sha256";
}
}
}
\ No newline at end of file
/**
* SHABase
*
* An ActionScript 3 abstract class for the SHA family of hash functions
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class SHABase implements IHash
{
public var pad_size:int = 40;
public function getInputSize():uint
{
return 64;
}
public function getHashSize():uint
{
return 0;
}
public function getPadSize():int
{
return pad_size;
}
public function hash(src:ByteArray):ByteArray
{
var savedLength:uint = src.length;
var savedEndian:String = src.endian;
src.endian = Endian.BIG_ENDIAN;
var len:uint = savedLength *8;
// pad to nearest int.
while (src.length%4!=0) {
src[src.length]=0;
}
// convert ByteArray to an array of uint
src.position=0;
var a:Array = [];
for (var i:uint=0;i<src.length;i+=4) {
a.push(src.readUnsignedInt());
}
var h:Array = core(a, len);
var out:ByteArray = new ByteArray;
var words:uint = getHashSize()/4;
for (i=0;i<words;i++) {
out.writeUnsignedInt(h[i]);
}
// unpad, to leave the source untouched.
src.length = savedLength;
src.endian = savedEndian;
return out;
}
protected function core(x:Array, len:uint):Array {
return null;
}
public function toString():String {
return "sha";
}
}
}
\ No newline at end of file
/**
* HMAC
*
* An ActionScript 3 implementation of HMAC, Keyed-Hashing for Message
* Authentication, as defined by RFC-2104
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
public class HMAC implements IHMAC
{
private var hash:IHash;
private var bits:uint;
/**
* Create a HMAC object, using a Hash function, and
* optionally a number of bits to return.
* The HMAC will be truncated to that size if needed.
*/
public function HMAC(hash:IHash, bits:uint=0) {
this.hash = hash;
this.bits = bits;
}
public function getHashSize():uint {
if (bits!=0) {
return bits/8;
} else {
return hash.getHashSize();
}
}
/**
* Compute a HMAC using a key and some data.
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
*/
public function compute(key:ByteArray, data:ByteArray):ByteArray {
var hashKey:ByteArray;
if (key.length>hash.getInputSize()) {
hashKey = hash.hash(key);
} else {
hashKey = new ByteArray;
hashKey.writeBytes(key);
}
while (hashKey.length<hash.getInputSize()) {
hashKey[hashKey.length]=0;
}
var innerKey:ByteArray = new ByteArray;
var outerKey:ByteArray = new ByteArray;
for (var i:uint=0;i<hashKey.length;i++) {
innerKey[i] = hashKey[i] ^ 0x36;
outerKey[i] = hashKey[i] ^ 0x5c;
}
// inner + data
innerKey.position = hashKey.length;
innerKey.writeBytes(data);
var innerHash:ByteArray = hash.hash(innerKey);
// outer + innerHash
outerKey.position = hashKey.length;
outerKey.writeBytes(innerHash);
var outerHash:ByteArray = hash.hash(outerKey);
if (bits>0 && bits<8*outerHash.length) {
outerHash.length = bits/8;
}
return outerHash;
}
public function dispose():void {
hash = null;
bits = 0;
}
public function toString():String {
return "hmac-"+(bits>0?bits+"-":"")+hash.toString();
}
}
}
\ No newline at end of file
/**
* HMAC
*
* An ActionScript 3 interface for HMAC & MAC
* implementations.
*
* Loosely copyrighted by Bobby Parker
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
public interface IHMAC
{
function getHashSize():uint;
/**
* Compute a HMAC using a key and some data.
* It doesn't modify either, and returns a new ByteArray with the HMAC value.
*/
function compute(key:ByteArray, data:ByteArray):ByteArray;
function dispose():void;
function toString():String;
}
}
\ No newline at end of file
/**
* IHash
*
* An interface for each hash function to implement
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
public interface IHash
{
function getInputSize():uint;
function getHashSize():uint;
function hash(src:ByteArray):ByteArray;
function toString():String;
function getPadSize():int;
}
}
\ No newline at end of file
/**
* MAC
*
* An ActionScript 3 implementation of MAC, Message Authentication Code
* for use with SSL 3.0.
* Loosely copyrighted by Bobby Parker.
* As3crypto copyrighted by Henri Torgemane.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
public class MAC implements IHMAC
{
private var hash:IHash;
private var bits:uint;
private var pad_1:ByteArray;
private var pad_2:ByteArray;
private var innerHash:ByteArray;
private var outerHash:ByteArray;
private var outerKey:ByteArray;
private var innerKey:ByteArray;
/**
* Create a MAC object (for SSL 3.0 ) and
* optionally a number of bits to return.
* The MAC will be truncated to that size if needed.
*/
public function MAC(hash:IHash, bits:uint=0) {
this.hash = hash;
this.bits = bits;
innerHash = new ByteArray();
outerHash = new ByteArray();
innerKey = new ByteArray();
outerKey = new ByteArray();
if (hash != null) {
var pad_size:int = hash.getPadSize();
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < pad_size; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
}
public function setPadSize(pad_size:int) : void { }
public function getHashSize():uint {
if (bits!=0) {
return bits/8;
} else {
return hash.getHashSize();
}
}
/**
* Compute a MAC using a key and some data.
*
*/
public function compute(key:ByteArray, data:ByteArray):ByteArray {
// take that incoming key and do hash(key + pad_2 + hash(key + pad_1 + sequence + length + record)
// note that data = (sequence + type + length + record)
if (pad_1 == null) {
var pad_size:int = hash.getPadSize();
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < pad_size; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
// Do some preliminary checking on stuff
/*
if (key.length > hash.getInputSize()) {
hashKey = hash.hash(key);
} else {
hashKey = new ByteArray;
hashKey.writeBytes(key);
}
while (hashKey.length < hash.getInputSize() ) {
hashKey[hashKey.length] = 0;
} */
// Henri's conventions work just fine here..
innerKey.length = 0;
outerKey.length = 0;
// trace("MAC Key: " + Hex.fromArray(key));
// trace("Key Length: " + key.length);
// trace("Pad_1 : " + Hex.fromArray(pad_1));
// inner hash calc
innerKey.writeBytes(key);
innerKey.writeBytes(pad_1);
innerKey.writeBytes(data);
// trace("MAC Inner Key: " + Hex.fromArray(innerKey));
innerHash = hash.hash(innerKey);
// trace("MAC Inner Hash: " + Hex.fromArray(innerHash));
// outer hash calc
outerKey.writeBytes(key);
outerKey.writeBytes(pad_2);
outerKey.writeBytes(innerHash);
// trace("MAC Outer Key: " + Hex.fromArray(outerKey));
outerHash = hash.hash(outerKey);
if (bits > 0 && bits < 8*outerHash.length) {
outerHash.length = bits/8;
}
// trace("MAC for record: " + Hex.fromArray(outerHash));
return outerHash;
}
public function dispose():void {
hash = null;
bits = 0;
}
public function toString():String {
return "mac-"+(bits>0?bits+"-":"")+hash.toString();
}
}
}
\ No newline at end of file
/**
* MD2
*
* An ActionScript 3 implementation of the RSA Data Security, Inc MD2 Message
* Digest Algorithm, as defined in RFC 1319
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*
* Excerpt from http://en.wikipedia.org/wiki/MD2:
* >
* > Rogier and Chauvaud (1997) described collisions of MD2's compression function,
* > although they were unable to extend the attack to the full MD2.
* >
* > In 2004, MD2 was shown to be vulnerable to a preimage attack with time
* > complexity equivalent to 2104 applications of the compression function
* > (Muller, 2004).
* > The author concludes, "MD2 can no longer be considered a secure one-way
* > hash function".
*
* also, this implementaton is quite slow.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
public class MD2 implements IHash
{
public static const HASH_SIZE:int = 16;
public var pad_size:int = 48; // probably will never get used, only here for SSL 3.0 support
private static const S:Array = [ // PI Digits
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 19,
98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 76, 130, 202,
30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 138, 23, 229, 18,
190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 245, 142, 187, 47, 238, 122,
169, 104, 121, 145, 21, 178, 7, 63, 148, 194, 16, 137, 11, 34, 95, 33,
128, 127, 93, 154, 90, 144, 50, 39, 53, 62, 204, 231, 191, 247, 151, 3,
255, 25, 48, 179, 72, 165, 181, 209, 215, 94, 146, 42, 172, 86, 170, 198,
79, 184, 56, 210, 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241,
69, 157, 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2,
27, 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 234, 38,
44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 129, 77, 82,
106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 8, 12, 189, 177, 74,
120, 136, 149, 139, 227, 99, 232, 109, 233, 203, 213, 254, 59, 0, 29, 57,
242, 239, 183, 14, 102, 88, 208, 228, 166, 119, 114, 248, 235, 117, 75, 10,
49, 68, 80, 180, 143, 237, 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 ];
public function MD2() { }
public function getInputSize():uint
{
return 16;
}
public function getPadSize():int {
return pad_size;
}
public function getHashSize():uint
{
return HASH_SIZE;
}
public function hash(src:ByteArray):ByteArray
{
var savedLength:uint = src.length;
// 3.1 Step 1. Padding
var i:uint = (16-src.length%16) || 16;
do {
src[src.length]=i;
} while (src.length%16!=0);
// 3.2 Step 2. Checksum
var len:uint = src.length;
var checksum:ByteArray = new ByteArray;
var L:uint = 0;
for (i = 0;i<len;i+=16) {
for (var j:uint=0;j<16;j++) {
L = checksum[j] ^= S[src[i+j] ^ L];
}
}
src.position = src.length;
src.writeBytes(checksum);
len += 16;
// 3.3 Step 3. MD Buffer
var X:ByteArray = new ByteArray;
// 3.4 Process Message
for (i=0;i<len;i+=16) {
/* Copy block i into X */
for (j=0;j<16;j++) {
X[32+j] = (X[16+j] = src[i+j])^X[j];
}
var t:uint=0;
/* Do 18 rounds */
for (j=0;j<18;j++) {
/* Round j. */
for (var k:uint=0;k<48;k++) {
X[k] = t = X[k]^S[t];
}
t = (t+j)&0xff;
}
}
// 3.5 Step 5. Output
X.length = 16;
// restore original length;
src.length = savedLength;
return X;
}
public function toString():String
{
return "md2";
}
}
}
/**
* MD5
*
* An ActionScript 3 implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Copyright (c) 2007 Henri Torgemane
*
* Derived from
* A JavaScript implementation of the same.
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* Note:
* This algorithm should not be your first choice for new developements, but is
* included to allow interoperability with existing codes and protocols.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class MD5 implements IHash
{
public static const HASH_SIZE:int = 16;
public var pad_size:int = 48;
public function MD5() { }
public function getInputSize():uint
{
return 64;
}
public function getHashSize():uint
{
return HASH_SIZE;
}
public function getPadSize():int
{
return pad_size;
}
public function hash(src:ByteArray):ByteArray
{
var len:uint = src.length *8;
var savedEndian:String = src.endian;
// pad to nearest int.
while (src.length%4!=0) {
src[src.length]=0;
}
// convert ByteArray to an array of uint
src.position=0;
var a:Array = [];
src.endian=Endian.LITTLE_ENDIAN
for (var i:uint=0;i<src.length;i+=4) {
a.push(src.readUnsignedInt());
}
var h:Array = core_md5(a, len);
var out:ByteArray = new ByteArray;
out.endian=Endian.LITTLE_ENDIAN;
for (i=0;i<4;i++) {
out.writeUnsignedInt(h[i]);
}
// restore length!
src.length = len/8;
src.endian = savedEndian;
return out;
}
private function core_md5(x:Array, len:uint):Array {
/* append padding */
x[len >> 5] |= 0x80 << ((len) % 32);
x[(((len + 64) >>> 9) << 4) + 14] = len;
var a:uint = 0x67452301; // 1732584193;
var b:uint = 0xEFCDAB89; //-271733879;
var c:uint = 0x98BADCFE; //-1732584194;
var d:uint = 0x10325476; // 271733878;
for(var i:uint = 0; i < x.length; i += 16)
{
x[i]||=0; x[i+1]||=0; x[i+2]||=0; x[i+3]||=0;
x[i+4]||=0; x[i+5]||=0; x[i+6]||=0; x[i+7]||=0;
x[i+8]||=0; x[i+9]||=0; x[i+10]||=0; x[i+11]||=0;
x[i+12]||=0; x[i+13]||=0; x[i+14]||=0; x[i+15]||=0;
var olda:uint = a;
var oldb:uint = b;
var oldc:uint = c;
var oldd:uint = d;
a = ff(a, b, c, d, x[i+ 0], 7 , 0xD76AA478);
d = ff(d, a, b, c, x[i+ 1], 12, 0xE8C7B756);
c = ff(c, d, a, b, x[i+ 2], 17, 0x242070DB);
b = ff(b, c, d, a, x[i+ 3], 22, 0xC1BDCEEE);
a = ff(a, b, c, d, x[i+ 4], 7 , 0xF57C0FAF);
d = ff(d, a, b, c, x[i+ 5], 12, 0x4787C62A);
c = ff(c, d, a, b, x[i+ 6], 17, 0xA8304613);
b = ff(b, c, d, a, x[i+ 7], 22, 0xFD469501);
a = ff(a, b, c, d, x[i+ 8], 7 , 0x698098D8);
d = ff(d, a, b, c, x[i+ 9], 12, 0x8B44F7AF);
c = ff(c, d, a, b, x[i+10], 17, 0xFFFF5BB1);
b = ff(b, c, d, a, x[i+11], 22, 0x895CD7BE);
a = ff(a, b, c, d, x[i+12], 7 , 0x6B901122);
d = ff(d, a, b, c, x[i+13], 12, 0xFD987193);
c = ff(c, d, a, b, x[i+14], 17, 0xA679438E);
b = ff(b, c, d, a, x[i+15], 22, 0x49B40821);
a = gg(a, b, c, d, x[i+ 1], 5 , 0xf61e2562);
d = gg(d, a, b, c, x[i+ 6], 9 , 0xc040b340);
c = gg(c, d, a, b, x[i+11], 14, 0x265e5a51);
b = gg(b, c, d, a, x[i+ 0], 20, 0xe9b6c7aa);
a = gg(a, b, c, d, x[i+ 5], 5 , 0xd62f105d);
d = gg(d, a, b, c, x[i+10], 9 , 0x2441453);
c = gg(c, d, a, b, x[i+15], 14, 0xd8a1e681);
b = gg(b, c, d, a, x[i+ 4], 20, 0xe7d3fbc8);
a = gg(a, b, c, d, x[i+ 9], 5 , 0x21e1cde6);
d = gg(d, a, b, c, x[i+14], 9 , 0xc33707d6);
c = gg(c, d, a, b, x[i+ 3], 14, 0xf4d50d87);
b = gg(b, c, d, a, x[i+ 8], 20, 0x455a14ed);
a = gg(a, b, c, d, x[i+13], 5 , 0xa9e3e905);
d = gg(d, a, b, c, x[i+ 2], 9 , 0xfcefa3f8);
c = gg(c, d, a, b, x[i+ 7], 14, 0x676f02d9);
b = gg(b, c, d, a, x[i+12], 20, 0x8d2a4c8a);
a = hh(a, b, c, d, x[i+ 5], 4 , 0xfffa3942);
d = hh(d, a, b, c, x[i+ 8], 11, 0x8771f681);
c = hh(c, d, a, b, x[i+11], 16, 0x6d9d6122);
b = hh(b, c, d, a, x[i+14], 23, 0xfde5380c);
a = hh(a, b, c, d, x[i+ 1], 4 , 0xa4beea44);
d = hh(d, a, b, c, x[i+ 4], 11, 0x4bdecfa9);
c = hh(c, d, a, b, x[i+ 7], 16, 0xf6bb4b60);
b = hh(b, c, d, a, x[i+10], 23, 0xbebfbc70);
a = hh(a, b, c, d, x[i+13], 4 , 0x289b7ec6);
d = hh(d, a, b, c, x[i+ 0], 11, 0xeaa127fa);
c = hh(c, d, a, b, x[i+ 3], 16, 0xd4ef3085);
b = hh(b, c, d, a, x[i+ 6], 23, 0x4881d05);
a = hh(a, b, c, d, x[i+ 9], 4 , 0xd9d4d039);
d = hh(d, a, b, c, x[i+12], 11, 0xe6db99e5);
c = hh(c, d, a, b, x[i+15], 16, 0x1fa27cf8);
b = hh(b, c, d, a, x[i+ 2], 23, 0xc4ac5665);
a = ii(a, b, c, d, x[i+ 0], 6 , 0xf4292244);
d = ii(d, a, b, c, x[i+ 7], 10, 0x432aff97);
c = ii(c, d, a, b, x[i+14], 15, 0xab9423a7);
b = ii(b, c, d, a, x[i+ 5], 21, 0xfc93a039);
a = ii(a, b, c, d, x[i+12], 6 , 0x655b59c3);
d = ii(d, a, b, c, x[i+ 3], 10, 0x8f0ccc92);
c = ii(c, d, a, b, x[i+10], 15, 0xffeff47d);
b = ii(b, c, d, a, x[i+ 1], 21, 0x85845dd1);
a = ii(a, b, c, d, x[i+ 8], 6 , 0x6fa87e4f);
d = ii(d, a, b, c, x[i+15], 10, 0xfe2ce6e0);
c = ii(c, d, a, b, x[i+ 6], 15, 0xa3014314);
b = ii(b, c, d, a, x[i+13], 21, 0x4e0811a1);
a = ii(a, b, c, d, x[i+ 4], 6 , 0xf7537e82);
d = ii(d, a, b, c, x[i+11], 10, 0xbd3af235);
c = ii(c, d, a, b, x[i+ 2], 15, 0x2ad7d2bb);
b = ii(b, c, d, a, x[i+ 9], 21, 0xeb86d391);
a += olda;
b += oldb;
c += oldc;
d += oldd;
}
return [ a, b, c, d ];
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
private function rol(num:uint, cnt:uint):uint
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
private function cmn(q:uint, a:uint, b:uint, x:uint, s:uint, t:uint):uint {
return rol(a + q + x + t, s) + b;
}
private function ff(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
private function gg(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
private function hh(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
private function ii(a:uint, b:uint, c:uint, d:uint, x:uint, s:uint, t:uint):uint {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
public function toString():String {
return "md5";
}
}
}
/**
* SHA1
*
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
public class SHA1 extends SHABase implements IHash
{
public static const HASH_SIZE:int = 20;
public override function getHashSize():uint {
return HASH_SIZE;
}
protected override function core(x:Array, len:uint):Array
{
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w:Array = [];
var a:uint = 0x67452301; //1732584193;
var b:uint = 0xEFCDAB89; //-271733879;
var c:uint = 0x98BADCFE; //-1732584194;
var d:uint = 0x10325476; //271733878;
var e:uint = 0xC3D2E1F0; //-1009589776;
for(var i:uint = 0; i < x.length; i += 16)
{
var olda:uint = a;
var oldb:uint = b;
var oldc:uint = c;
var oldd:uint = d;
var olde:uint = e;
for(var j:uint = 0; j < 80; j++)
{
if (j < 16) {
w[j] = x[i + j] || 0;
} else {
w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
}
var t:uint = rol(a,5) + ft(j,b,c,d) + e + w[j] + kt(j);
e = d;
d = c;
c = rol(b, 30);
b = a;
a = t;
}
a += olda;
b += oldb;
c += oldc;
d += oldd;
e += olde;
}
return [ a, b, c, d, e ];
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
private function rol(num:uint, cnt:uint):uint
{
return (num << cnt) | (num >>> (32 - cnt));
}
/*
* Perform the appropriate triplet combination function for the current
* iteration
*/
private function ft(t:uint, b:uint, c:uint, d:uint):uint
{
if(t < 20) return (b & c) | ((~b) & d);
if(t < 40) return b ^ c ^ d;
if(t < 60) return (b & c) | (b & d) | (c & d);
return b ^ c ^ d;
}
/*
* Determine the appropriate additive constant for the current iteration
*/
private function kt(t:uint):uint
{
return (t < 20) ? 0x5A827999 : (t < 40) ? 0x6ED9EBA1 :
(t < 60) ? 0x8F1BBCDC : 0xCA62C1D6;
}
public override function toString():String {
return "sha1";
}
}
}
/**
* SHA224
*
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-224, as defined
* in FIPS PUB 180-2
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
public class SHA224 extends SHA256
{
function SHA224() {
h = [
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
];
}
public override function getHashSize():uint {
return 28;
}
public override function toString():String {
return "sha224";
}
}
}
\ No newline at end of file
/**
* SHA256
*
* An ActionScript 3 implementation of Secure Hash Algorithm, SHA-256, as defined
* in FIPS PUB 180-2
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* A JavaScript implementation of the Secure Hash Standard
* Version 0.3 Copyright Angel Marin 2003-2004 - http://anmar.eu.org/
* Derived from:
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
* in FIPS PUB 180-1
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
public class SHA256 extends SHABase implements IHash
{
protected static const k: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];
protected var h:Array = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
public function SHA256(){
}
public override function getHashSize():uint
{
return 32;
}
protected override function core(x:Array, len:uint):Array {
/* append padding */
x[len >> 5] |= 0x80 << (24 - len % 32);
x[((len + 64 >> 9) << 4) + 15] = len;
var w:Array = [];
var a:uint = h[0];
var b:uint = h[1];
var c:uint = h[2];
var d:uint = h[3];
var e:uint = h[4];
var f:uint = h[5];
var g:uint = h[6];
var h:uint = h[7];
for (var i:uint=0; i<x.length; i+=16) {
var olda:uint = a;
var oldb:uint = b;
var oldc:uint = c;
var oldd:uint = d;
var olde:uint = e;
var oldf:uint = f;
var oldg:uint = g;
var oldh:uint = h;
for (var j:uint=0; j<64; j++) {
if (j<16) {
w[j] = x[i+j] || 0;
} else {
var s0:uint = rrol(w[j-15],7)^rrol(w[j-15],18)^(w[j-15]>>>3);
var s1:uint = rrol(w[j-2], 17)^rrol(w[j-2],19)^(w[j-2]>>>10);
w[j] = w[j-16] + s0 + w[j-7] + s1;
}
var t2:uint = (rrol(a,2) ^ rrol(a,13) ^ rrol(a,22)) + ((a&b) ^ (a&c) ^ (b&c));
var t1:uint = h + (rrol(e,6) ^ rrol(e,11) ^ rrol(e,25)) + ((e&f)^(g&~e)) + k[j] + w[j]
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
a += olda;
b += oldb;
c += oldc;
d += oldd;
e += olde;
f += oldf;
g += oldg;
h += oldh;
}
return [ a,b,c,d,e,f,g,h ];
}
/*
* Bitwise rotate a 32-bit number to the right.
*/
protected function rrol(num:uint, cnt:uint):uint {
return (num << (32-cnt)) | (num >>> cnt);
}
public override function toString():String {
return "sha256";
}
}
}
\ No newline at end of file
/**
* SHABase
*
* An ActionScript 3 abstract class for the SHA family of hash functions
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.hash
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class SHABase implements IHash
{
public function SHABase() { }
public var pad_size:int = 40;
public function getInputSize():uint
{
return 64;
}
public function getHashSize():uint
{
return 0;
}
public function getPadSize():int
{
return pad_size;
}
public function hash(src:ByteArray):ByteArray
{
var savedLength:uint = src.length;
var savedEndian:String = src.endian;
src.endian = Endian.BIG_ENDIAN;
var len:uint = savedLength *8;
// pad to nearest int.
while (src.length%4!=0) {
src[src.length]=0;
}
// convert ByteArray to an array of uint
src.position=0;
var a:Array = [];
for (var i:uint=0;i<src.length;i+=4) {
a.push(src.readUnsignedInt());
}
var h:Array = core(a, len);
var out:ByteArray = new ByteArray;
var words:uint = getHashSize()/4;
for (i=0;i<words;i++) {
out.writeUnsignedInt(h[i]);
}
// unpad, to leave the source untouched.
src.length = savedLength;
src.endian = savedEndian;
return out;
}
protected function core(x:Array, len:uint):Array {
return null;
}
public function toString():String {
return "sha";
}
}
}
/**
* ARC4
*
* An ActionScript 3 implementation of RC4
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.prng
{
import com.hurlant.crypto.symmetric.IStreamCipher;
import com.hurlant.util.Memory;
import flash.utils.ByteArray;
public class ARC4 implements IPRNG, IStreamCipher {
private var i:int = 0;
private var j:int = 0;
private var S:ByteArray;
private const psize:uint = 256;
public function ARC4(key:ByteArray = null){
S = new ByteArray;
if (key) {
init(key);
}
}
public function getPoolSize():uint {
return psize;
}
public function init(key:ByteArray):void {
var i:int;
var j:int;
var t:int;
for (i=0; i<256; ++i) {
S[i] = i;
}
j=0;
for (i=0; i<256; ++i) {
j = (j + S[i] + key[i%key.length]) & 255;
t = S[i];
S[i] = S[j];
S[j] = t;
}
this.i=0;
this.j=0;
}
public function next():uint {
var t:int;
i = (i+1)&255;
j = (j+S[i])&255;
t = S[i];
S[i] = S[j];
S[j] = t;
return S[(t+S[i])&255];
}
public function getBlockSize():uint {
return 1;
}
public function encrypt(block:ByteArray):void {
var i:uint = 0;
while (i<block.length) {
block[i++] ^= next();
}
}
public function decrypt(block:ByteArray):void {
encrypt(block); // the beauty of XOR.
}
public function dispose():void {
var i:uint = 0;
if (S!=null) {
for (i=0;i<S.length;i++) {
S[i] = Math.random()*256;
}
S.length=0;
S = null;
}
this.i = 0;
this.j = 0;
Memory.gc();
}
public function toString():String {
return "rc4";
}
}
}
\ No newline at end of file
/**
* IPRNG
*
* An interface for classes that can be used a pseudo-random number generators
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.prng
{
import flash.utils.ByteArray;
public interface IPRNG {
function getPoolSize():uint;
function init(key:ByteArray):void;
function next():uint;
function dispose():void;
function toString():String;
}
}
\ No newline at end of file
/**
* Random
*
* An ActionScript 3 implementation of a Random Number Generator
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.prng
{
import flash.utils.ByteArray;
import com.hurlant.util.Memory;
import flash.system.System;
import flash.system.Capabilities;
import flash.accessibility.AccessibilityProperties;
import flash.display.SWFVersion;
import flash.display.Stage;
import flash.utils.getTimer;
import flash.text.Font;
public class Random
{
private var state:IPRNG;
private var ready:Boolean = false;
private var pool:ByteArray;
private var psize:int;
private var pptr:int;
private var seeded:Boolean = false;
public function Random(prng:Class = null) {
if (prng==null) prng = ARC4;
state = new prng as IPRNG;
psize= state.getPoolSize();
pool = new ByteArray;
pptr = 0;
while (pptr <psize) {
var t:uint = 65536*Math.random();
pool[pptr++] = t >>> 8;
pool[pptr++] = t&255;
}
pptr=0;
seed();
}
public function seed(x:int = 0):void {
if (x==0) {
x = new Date().getTime();
}
pool[pptr++] ^= x & 255;
pool[pptr++] ^= (x>>8)&255;
pool[pptr++] ^= (x>>16)&255;
pool[pptr++] ^= (x>>24)&255;
pptr %= psize;
seeded = true;
}
/**
* Gather anything we have that isn't entirely predictable:
* - memory used
* - system capabilities
* - timing stuff
* - installed fonts
*/
public function autoSeed():void {
var b:ByteArray = new ByteArray;
b.writeUnsignedInt(System.totalMemory);
b.writeUTF(Capabilities.serverString);
b.writeUnsignedInt(getTimer());
b.writeUnsignedInt((new Date).getTime());
var a:Array = Font.enumerateFonts(true);
for each (var f:Font in a) {
b.writeUTF(f.fontName);
b.writeUTF(f.fontStyle);
b.writeUTF(f.fontType);
}
b.position=0;
while (b.bytesAvailable>=4) {
seed(b.readUnsignedInt());
}
}
public function nextBytes(buffer:ByteArray, length:int):void {
while (length--) {
buffer.writeByte(nextByte());
}
}
public function nextByte():int {
if (!ready) {
if (!seeded) {
autoSeed();
}
state.init(pool);
pool.length = 0;
pptr = 0;
ready = true;
}
return state.next();
}
public function dispose():void {
for (var i:uint=0;i<pool.length;i++) {
pool[i] = Math.random()*256;
}
pool.length=0;
pool = null;
state.dispose();
state = null;
psize = 0;
pptr = 0;
Memory.gc();
}
public function toString():String {
return "random-"+state.toString();
}
}
}
/**
* 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;
}
}
}
\ No newline at end of file
/**
* RSAKey
*
* An ActionScript 3 implementation of RSA + PKCS#1 (light version)
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.rsa
{
import com.hurlant.crypto.prng.Random;
import com.hurlant.math.BigInteger;
import com.hurlant.util.Memory;
import flash.utils.ByteArray;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.util.Hex;
import com.hurlant.util.der.DER;
import com.hurlant.util.der.OID;
import com.hurlant.util.ArrayUtil;
import com.hurlant.util.der.Type;
import com.hurlant.util.der.Sequence;
import com.hurlant.util.der.ObjectIdentifier;
import com.hurlant.util.der.ByteString;
import com.hurlant.crypto.tls.TLSError;
/**
* Current limitations:
* exponent must be smaller than 2^31.
*/
public class RSAKey
{
// public key
public var e:int; // public exponent. must be <2^31
public var n:BigInteger; // modulus
// private key
public var d:BigInteger;
// extended private key
public var p:BigInteger;
public var q:BigInteger;
public var dmp1:BigInteger
public var dmq1:BigInteger;
public var coeff:BigInteger;
// flags. flags are cool.
protected var canDecrypt:Boolean;
protected var canEncrypt:Boolean;
public function RSAKey(N:BigInteger, E:int,
D:BigInteger=null,
P:BigInteger = null, Q:BigInteger=null,
DP:BigInteger=null, DQ:BigInteger=null,
C:BigInteger=null) {
this.n = N;
this.e = E;
this.d = D;
this.p = P;
this.q = Q;
this.dmp1 = DP;
this.dmq1 = DQ;
this.coeff = C;
// adjust a few flags.
canEncrypt = (n!=null&&e!=0);
canDecrypt = (canEncrypt&&d!=null);
}
public static function parsePublicKey(N:String, E:String):RSAKey {
return new RSAKey(new BigInteger(N, 16, true), parseInt(E,16));
}
public static function parsePrivateKey(N:String, E:String, D:String,
P:String=null,Q:String=null, DMP1:String=null, DMQ1:String=null, IQMP:String=null):RSAKey {
if (P==null) {
return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true));
} else {
return new RSAKey(new BigInteger(N,16, true), parseInt(E,16), new BigInteger(D,16, true),
new BigInteger(P,16, true), new BigInteger(Q,16, true),
new BigInteger(DMP1,16, true), new BigInteger(DMQ1, 16, true),
new BigInteger(IQMP, 16, true));
}
}
public function getBlockSize():uint {
return (n.bitLength()+7)/8;
}
public function dispose():void {
e = 0;
n.dispose();
n = null;
Memory.gc();
}
public function encrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {
_encrypt(doPublic, src, dst, length, pad, 0x02);
}
public function decrypt(src:ByteArray, dst:ByteArray, length:uint, pad:Function=null):void {
_decrypt(doPrivate2, src, dst, length, pad, 0x02);
}
public function sign(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {
_encrypt(doPrivate2, src, dst, length, pad, 0x01);
}
public function verify(src:ByteArray, dst:ByteArray, length:uint, pad:Function = null):void {
_decrypt(doPublic, src, dst, length, pad, 0x01);
}
private function _encrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {
// adjust pad if needed
if (pad==null) pad = pkcs1pad;
// convert src to BigInteger
if (src.position >= src.length) {
src.position = 0;
}
var bl:uint = getBlockSize();
var end:int = src.position + length;
while (src.position<end) {
var block:BigInteger = new BigInteger(pad(src, end, bl, padType), bl, true);
var chunk:BigInteger = op(block);
chunk.toArray(dst);
}
}
private function _decrypt(op:Function, src:ByteArray, dst:ByteArray, length:uint, pad:Function, padType:int):void {
// adjust pad if needed
if (pad==null) pad = pkcs1unpad;
// convert src to BigInteger
if (src.position >= src.length) {
src.position = 0;
}
var bl:uint = getBlockSize();
var end:int = src.position + length;
while (src.position<end) {
var block:BigInteger = new BigInteger(src, bl, true);
var chunk:BigInteger = op(block);
var b:ByteArray = pad(chunk, bl, padType);
if (b == null)
throw new TLSError( "Decrypt error - padding function returned null!", TLSError.decode_error );
// if (b != null)
dst.writeBytes(b);
}
}
/**
* PKCS#1 pad. type 1 (0xff) or 2, random.
* puts as much data from src into it, leaves what doesn't fit alone.
*/
private function pkcs1pad(src:ByteArray, end:int, n:uint, type:uint = 0x02):ByteArray {
var out:ByteArray = new ByteArray;
var p:uint = src.position;
end = Math.min(end, src.length, p+n-11);
src.position = end;
var i:int = end-1;
while (i>=p && n>11) {
out[--n] = src[i--];
}
out[--n] = 0;
if (type==0x02) { // type 2
var rng:Random = new Random;
var x:int = 0;
while (n>2) {
do {
x = rng.nextByte();
} while (x==0);
out[--n] = x;
}
} else { // type 1
while (n>2) {
out[--n] = 0xFF;
}
}
out[--n] = type;
out[--n] = 0;
return out;
}
/**
*
* @param src
* @param n
* @param type Not used.
* @return
*
*/
private function pkcs1unpad(src:BigInteger, n:uint, type:uint = 0x02):ByteArray {
var b:ByteArray = src.toByteArray();
var out:ByteArray = new ByteArray;
b.position = 0;
var i:int = 0;
while (i<b.length && b[i]==0) ++i;
if (b.length-i != n-1 || b[i]!=type) {
trace("PKCS#1 unpad: i="+i+", expected b[i]=="+type+", got b[i]="+b[i].toString(16));
return null;
}
++i;
while (b[i]!=0) {
if (++i>=b.length) {
trace("PKCS#1 unpad: i="+i+", b[i-1]!=0 (="+b[i-1].toString(16)+")");
return null;
}
}
while (++i < b.length) {
out.writeByte(b[i]);
}
out.position = 0;
return out;
}
/**
* Raw pad.
*/
public function rawpad(src:ByteArray, end:int, n:uint, type:uint = 0):ByteArray {
return src;
}
public function rawunpad(src:BigInteger, n:uint, type:uint = 0):ByteArray {
return src.toByteArray();
}
public function toString():String {
return "rsa";
}
public function dump():String {
var s:String= "N="+n.toString(16)+"\n"+
"E="+e.toString(16)+"\n";
if (canDecrypt) {
s+="D="+d.toString(16)+"\n";
if (p!=null && q!=null) {
s+="P="+p.toString(16)+"\n";
s+="Q="+q.toString(16)+"\n";
s+="DMP1="+dmp1.toString(16)+"\n";
s+="DMQ1="+dmq1.toString(16)+"\n";
s+="IQMP="+coeff.toString(16)+"\n";
}
}
return s;
}
/**
*
* note: We should have a "nice" variant of this function that takes a callback,
* and perform the computation is small fragments, to keep the web browser
* usable.
*
* @param B
* @param E
* @return a new random private key B bits long, using public expt E
*
*/
public static function generate(B:uint, E:String):RSAKey {
var rng:Random = new Random;
var qs:uint = B>>1;
var key:RSAKey = new RSAKey(null,0,null);
key.e = parseInt(E, 16);
var ee:BigInteger = new BigInteger(E,16, true);
for (;;) {
for (;;) {
key.p = bigRandom(B-qs, rng);
if (key.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&
key.p.isProbablePrime(10)) break;
}
for (;;) {
key.q = bigRandom(qs, rng);
if (key.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE)==0 &&
key.q.isProbablePrime(10)) break;
}
if (key.p.compareTo(key.q)<=0) {
var t:BigInteger = key.p;
key.p = key.q;
key.q = t;
}
var p1:BigInteger = key.p.subtract(BigInteger.ONE);
var q1:BigInteger = key.q.subtract(BigInteger.ONE);
var phi:BigInteger = p1.multiply(q1);
if (phi.gcd(ee).compareTo(BigInteger.ONE)==0) {
key.n = key.p.multiply(key.q);
key.d = ee.modInverse(phi);
key.dmp1 = key.d.mod(p1);
key.dmq1 = key.d.mod(q1);
key.coeff = key.q.modInverse(key.p);
break;
}
}
return key;
}
protected static function bigRandom(bits:int, rnd:Random):BigInteger {
if (bits<2) return BigInteger.nbv(1);
var x:ByteArray = new ByteArray;
rnd.nextBytes(x, (bits>>3));
x.position = 0;
var b:BigInteger = new BigInteger(x,0,true);
b.primify(bits, 1);
return b;
}
protected function doPublic(x:BigInteger):BigInteger {
return x.modPowInt(e, n);
}
protected function doPrivate2(x:BigInteger):BigInteger {
if (p==null && q==null) {
return x.modPow(d,n);
}
var xp:BigInteger = x.mod(p).modPow(dmp1, p);
var xq:BigInteger = x.mod(q).modPow(dmq1, q);
while (xp.compareTo(xq)<0) {
xp = xp.add(p);
}
var r:BigInteger = xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);
return r;
}
protected function doPrivate(x:BigInteger):BigInteger {
if (p==null || q==null) {
return x.modPow(d, n);
}
// TODO: re-calculate any missing CRT params
var xp:BigInteger = x.mod(p).modPow(dmp1, p);
var xq:BigInteger = x.mod(q).modPow(dmq1, q);
while (xp.compareTo(xq)<0) {
xp = xp.add(p);
}
return xp.subtract(xq).multiply(coeff).mod(p).multiply(q).add(xq);
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* BlowFishKey
*
* An Actionscript 3 implementation of the BlowFish encryption algorithm,
* as documented at http://www.schneier.com/blowfish.html
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The Bouncy Castle Crypto package,
* Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
* (http://www.bouncycastle.org)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
import com.hurlant.util.Memory;
public class BlowFishKey implements ISymmetricKey
{
private static const KP:Array = [ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,
0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5,
0xB5470917, 0x9216D5D9, 0x8979FB1B ];
private static const KS0:Array = [ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947,
0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658,
0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918,
0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF,
0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C,
0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60,
0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2,
0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176,
0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F,
0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6,
0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C,
0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39,
0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB,
0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8,
0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC,
0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB,
0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777,
0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81,
0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B,
0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9,
0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476,
0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A ];
private static const KS1:Array = [ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71,
0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65,
0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6,
0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A,
0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC,
0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1,
0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718,
0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908,
0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6,
0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6,
0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D,
0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1,
0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90,
0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA,
0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E,
0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF,
0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA,
0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A,
0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092,
0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E,
0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705,
0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 ];
private static const KS2:Array = [ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471,
0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF,
0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6,
0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35,
0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332,
0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7,
0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE,
0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60,
0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62,
0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60,
0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3,
0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF,
0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659,
0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086,
0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187,
0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E,
0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09,
0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F,
0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7,
0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188,
0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3,
0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 ];
private static const KS3:Array = [ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D,
0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79,
0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8,
0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3,
0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797,
0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472,
0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15,
0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5,
0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862,
0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD,
0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB,
0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671,
0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1,
0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A,
0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF,
0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532,
0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E,
0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5,
0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD,
0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3,
0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0,
0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 ];
// ====================================
// Useful constants
// ====================================
private static const ROUNDS:uint = 16;
private static const BLOCK_SIZE:uint = 8; // bytes = 64 bits
private static const SBOX_SK:uint = 256;
private static const P_SZ:uint = ROUNDS + 2;
private var S0:Array;
private var S1:Array;
private var S2:Array;
private var S3:Array; // the s-boxes
private var P:Array; // the p-array
private var key:ByteArray = null;
public function BlowFishKey(key:ByteArray) {
this.key = key;
setKey(key);
}
public function getBlockSize():uint
{
return BLOCK_SIZE;
}
public function decrypt(block:ByteArray, index:uint=0):void
{
decryptBlock(block, index, block, index);
}
public function dispose():void
{
var i:uint=0;
for (i=0;i<S0.length;i++) { S0[i]=0; }
for (i=0;i<S1.length;i++) { S1[i]=0; }
for (i=0;i<S2.length;i++) { S2[i]=0; }
for (i=0;i<S3.length;i++) { S3[i]=0; }
for (i=0;i<P.length;i++) { P[i]=0; }
S0 = null;
S1 = null;
S2 = null;
S3 = null;
P = null;
for (i=0;i<key.length;i++) {
key[i]=0;
}
key.length = 0;
key = null;
Memory.gc();
}
public function encrypt(block:ByteArray, index:uint=0):void
{
encryptBlock(block, index, block, index);
}
// ==================================
// Private Implementation
// ==================================
private function F(x:uint):uint
{
return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff]) ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]);
}
/**
* apply the encryption cycle to each value pair in the table.
*/
private function processTable(xl:uint, xr:uint, table:Array):void
{
var size:uint = table.length;
for (var s:uint = 0; s < size; s += 2)
{
xl ^= P[0];
for (var i:uint = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr ^= P[ROUNDS + 1];
table[s] = xr;
table[s + 1] = xl;
xr = xl; // end of cycle swap
xl = table[s];
}
}
private function setKey(key:ByteArray):void
{
/*
* - comments are from _Applied Crypto_, Schneier, p338 please be
* careful comparing the two, AC numbers the arrays from 1, the enclosed
* code from 0.
*
* (1) Initialise the S-boxes and the P-array, with a fixed string This
* string contains the hexadecimal digits of pi (3.141...)
*/
S0 = KS0.concat();
S1 = KS1.concat();
S2 = KS2.concat();
S3 = KS3.concat();
P = KP.concat();
/*
* (2) Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with
* the second 32-bits of the key, and so on for all bits of the key (up
* to P[17]). Repeatedly cycle through the key bits until the entire
* P-array has been XOR-ed with the key bits
*/
var keyLength:uint= key.length;
var keyIndex:uint = 0;
for (var i:uint = 0; i < P_SZ; i++)
{
// get the 32 bits of the key, in 4 * 8 bit chunks
var data:uint = 0x0000000;
for (var j:uint = 0; j < 4; j++)
{
// create a 32 bit block
data = (data << 8) | (key[keyIndex++] & 0xff);
// wrap when we get to the end of the key
if (keyIndex >= keyLength)
{
keyIndex = 0;
}
}
// XOR the newly created 32 bit chunk onto the P-array
P[i] ^= data;
}
/*
* (3) Encrypt the all-zero string with the Blowfish algorithm, using
* the subkeys described in (1) and (2)
*
* (4) Replace P1 and P2 with the output of step (3)
*
* (5) Encrypt the output of step(3) using the Blowfish algorithm, with
* the modified subkeys.
*
* (6) Replace P3 and P4 with the output of step (5)
*
* (7) Continue the process, replacing all elements of the P-array and
* then all four S-boxes in order, with the output of the continuously
* changing Blowfish algorithm
*/
processTable(0, 0, P);
processTable(P[P_SZ - 2], P[P_SZ - 1], S0);
processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
}
/**
* Encrypt the given input starting at the given offset and place the result
* in the provided buffer starting at the given offset. The input will be an
* exact multiple of our blocksize.
*/
private function encryptBlock(src:ByteArray, srcIndex:uint, dst:ByteArray, dstIndex:uint):void
{
var xl:uint = BytesTo32bits(src, srcIndex);
var xr:uint = BytesTo32bits(src, srcIndex + 4);
xl ^= P[0];
for (var i:uint = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr ^= P[ROUNDS + 1];
Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex + 4);
}
/**
* Decrypt the given input starting at the given offset and place the result
* in the provided buffer starting at the given offset. The input will be an
* exact multiple of our blocksize.
*/
private function decryptBlock(src:ByteArray, srcIndex:uint, dst:ByteArray, dstIndex:uint):void
{
var xl:uint = BytesTo32bits(src, srcIndex);
var xr:uint = BytesTo32bits(src, srcIndex + 4);
xl ^= P[ROUNDS + 1];
for (var i:uint = ROUNDS; i > 0; i -= 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i - 1];
}
xr ^= P[0];
Bits32ToBytes(xr, dst, dstIndex);
Bits32ToBytes(xl, dst, dstIndex + 4);
}
private function BytesTo32bits(b:ByteArray, i:uint):uint
{
return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | ((b[i + 3] & 0xff));
}
private function Bits32ToBytes(i:uint, b:ByteArray, offset:uint):void
{
b[offset + 3] = i;
b[offset + 2] = (i >> 8);
b[offset + 1] = (i >> 16);
b[offset] = (i >> 24);
}
public function toString():String {
return "blowfish";
}
}
}
/**
* CBCMode
*
* An ActionScript 3 implementation of the CBC confidentiality mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
/**
* CBC confidentiality mode. why not.
*/
public class CBCMode extends IVMode implements IMode
{
public function CBCMode(key:ISymmetricKey, padding:IPad = null) {
super(key, padding);
}
public function encrypt(src:ByteArray):void {
padding.pad(src);
var vector:ByteArray = getIV4e();
for (var i:uint=0;i<src.length;i+=blockSize) {
for (var j:uint=0;j<blockSize;j++) {
src[i+j] ^= vector[j];
}
key.encrypt(src, i);
vector.position=0;
vector.writeBytes(src, i, blockSize);
}
}
public function decrypt(src:ByteArray):void {
var vector:ByteArray = getIV4d();
var tmp:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i+=blockSize) {
tmp.position=0;
tmp.writeBytes(src, i, blockSize);
key.decrypt(src, i);
for (var j:uint=0;j<blockSize;j++) {
src[i+j] ^= vector[j];
}
vector.position=0;
vector.writeBytes(tmp, 0, blockSize);
}
padding.unpad(src);
}
public function toString():String {
return key.toString()+"-cbc";
}
}
}
/**
* CFB8Mode
*
* An ActionScript 3 implementation of the CFB-8 confidentiality mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import com.hurlant.crypto.tests.TestCase;
import flash.utils.ByteArray;
/**
*
* Note: The constructor accepts an optional padding argument, but ignores it otherwise.
*/
public class CFB8Mode extends IVMode implements IMode
{
public function CFB8Mode(key:ISymmetricKey, padding:IPad = null) {
super(key, null);
}
public function encrypt(src:ByteArray):void {
var vector:ByteArray = getIV4e();
var tmp:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i++) {
tmp.position = 0;
tmp.writeBytes(vector);
key.encrypt(vector);
src[i] ^= vector[0];
// rotate
for (var j:uint=0;j<blockSize-1;j++) {
vector[j] = tmp[j+1];
}
vector[blockSize-1] = src[i];
}
}
public function decrypt(src:ByteArray):void {
var vector:ByteArray = getIV4d();
var tmp:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i++) {
var c:uint = src[i];
tmp.position = 0;
tmp.writeBytes(vector); // I <- tmp
key.encrypt(vector); // O <- vector
src[i] ^= vector[0];
// rotate
for (var j:uint=0;j<blockSize-1;j++) {
vector[j] = tmp[j+1];
}
vector[blockSize-1] = c;
}
}
public function toString():String {
return key.toString()+"-cfb8";
}
}
}
\ No newline at end of file
/**
* CFBMode
*
* An ActionScript 3 implementation of the CFB confidentiality mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
/**
* This is the "full" CFB.
* CFB1 and CFB8 are hiding somewhere else.
*
* Note: The constructor accepts an optional padding argument, but ignores it otherwise.
*/
public class CFBMode extends IVMode implements IMode
{
public function CFBMode(key:ISymmetricKey, padding:IPad = null) {
super(key,null);
}
public function encrypt(src:ByteArray):void
{
var l:uint = src.length;
var vector:ByteArray = getIV4e();
for (var i:uint=0;i<src.length;i+=blockSize) {
key.encrypt(vector);
var chunk:uint = (i+blockSize<l)?blockSize:l-i;
for (var j:uint=0;j<chunk;j++) {
src[i+j] ^= vector[j];
}
vector.position=0;
vector.writeBytes(src, i, chunk);
}
}
public function decrypt(src:ByteArray):void
{
var l:uint = src.length;
var vector:ByteArray = getIV4d();
var tmp:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i+=blockSize) {
key.encrypt(vector);
var chunk:uint = (i+blockSize<l)?blockSize:l-i;
tmp.position=0;
tmp.writeBytes(src, i, chunk);
for (var j:uint=0;j<chunk;j++) {
src[i+j] ^= vector[j];
}
vector.position=0;
vector.writeBytes(tmp);
}
}
public function toString():String {
return key.toString()+"-cfb";
}
}
}
\ No newline at end of file
/**
* CTRMode
*
* An ActionScript 3 implementation of the counter confidentiality mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
public class CTRMode extends IVMode implements IMode
{
public function CTRMode(key:ISymmetricKey, padding:IPad = null) {
super(key, padding);
}
public function encrypt(src:ByteArray):void
{
padding.pad(src);
var vector:ByteArray = getIV4e();
core(src, vector);
}
public function decrypt(src:ByteArray):void
{
var vector:ByteArray = getIV4d();
core(src, vector);
padding.unpad(src);
}
private function core(src:ByteArray, iv:ByteArray):void {
var X:ByteArray = new ByteArray;
var Xenc:ByteArray = new ByteArray;
X.writeBytes(iv);
for (var i:uint=0;i<src.length;i+=blockSize) {
Xenc.position=0;
Xenc.writeBytes(X);
key.encrypt(Xenc);
for (var j:uint=0;j<blockSize;j++) {
src[i+j] ^= Xenc[j];
}
for (j=blockSize-1;j>=0;--j) {
X[j]++;
if (X[j]!=0)
break;
}
}
}
public function toString():String {
return key.toString()+"-ctr";
}
}
}
\ No newline at end of file
/**
* DESKey
*
* An Actionscript 3 implementation of the Data Encryption Standard (DES)
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The Bouncy Castle Crypto package,
* Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
* (http://www.bouncycastle.org)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.util.Memory;
public class DESKey implements ISymmetricKey
{
/**
* what follows is mainly taken from "Applied Cryptography", by Bruce
* Schneier, however it also bears great resemblance to Richard
* Outerbridge's D3DES...
*/
private static const Df_Key:Array = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
0x10, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67 ];
private static const bytebit:Array = [ 128, 64, 32, 16, 8, 4, 2, 1 ];
private static const bigbyte:Array = [ 0x800000, 0x400000, 0x200000, 0x100000, 0x80000, 0x40000, 0x20000, 0x10000, 0x8000,
0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 ];
/*
* Use the key schedule specified in the Standard (ANSI X3.92-1981).
*/
private static const pc1:Array = [ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2,
59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12,
4, 27, 19, 11, 3 ];
private static const totrot:Array = [ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 ];
private static const pc2:Array = [ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40,
51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 ];
private static const SP1:Array = [ 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004,
0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004,
0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404,
0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400,
0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404,
0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004,
0x00010400, 0x00000000, 0x01010004 ];
private static const SP2:Array = [ 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020,
0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020,
0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020,
0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020,
0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020,
0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000,
0x80100020, 0x80108020, 0x00108000 ];
private static const SP3:Array = [ 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208,
0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208,
0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000,
0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208,
0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208,
0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208,
0x00000008, 0x08020008, 0x00020200 ];
private static const SP4:Array = [ 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001,
0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081,
0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001,
0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081,
0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000,
0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080,
0x00800000, 0x00002000, 0x00802080 ];
private static const SP5:Array = [ 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000,
0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000,
0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100,
0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000,
0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100,
0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000,
0x40080000, 0x02080100, 0x40000100 ];
private static const SP6:Array = [ 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010,
0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010,
0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010,
0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000,
0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010,
0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000,
0x20000000, 0x00400010, 0x20004010 ];
private static const SP7:Array = [ 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802,
0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000,
0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800,
0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800,
0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000,
0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002,
0x04000800, 0x00000800, 0x00200002 ];
private static const SP8:Array = [ 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040,
0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040,
0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000,
0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040,
0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040,
0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040,
0x00040040, 0x10000000, 0x10041000 ];
protected var key:ByteArray;
protected var encKey:Array;
protected var decKey:Array;
public function DESKey(key:ByteArray) {
this.key = key;
this.encKey = generateWorkingKey(true, key, 0);
this.decKey = generateWorkingKey(false, key, 0);
}
public function getBlockSize():uint
{
return 8;
}
public function decrypt(block:ByteArray, index:uint=0):void
{
desFunc(decKey, block, index, block, index);
}
public function dispose():void
{
var i:uint=0;
for (i=0;i<encKey.length;i++) { encKey[i]=0; }
for (i=0;i<decKey.length;i++) { decKey[i]=0; }
encKey=null;
decKey=null;
for (i=0;i<key.length;i++) { key[i]=0; }
key.length = 0;
key = null;
Memory.gc();
}
public function encrypt(block:ByteArray, index:uint=0):void
{
desFunc(encKey, block, index, block, index);
}
/**
* generate an integer based working key based on our secret key and what we
* processing we are planning to do.
*
* Acknowledgements for this routine go to James Gillogly & Phil Karn.
*/
protected function generateWorkingKey(encrypting:Boolean, key:ByteArray, off:uint):Array
{
//int[] newKey = new int[32];
var newKey:Array = [];
//boolean[] pc1m = new boolean[56], pcr = new boolean[56];
var pc1m:ByteArray = new ByteArray;
var pcr:ByteArray = new ByteArray;
var l:uint;
for (var j:uint = 0; j < 56; j++)
{
l = pc1[j];
pc1m[j] = ((key[off + (l >>> 3)] & bytebit[l & 07]) != 0);
}
for (var i:uint = 0; i < 16; i++)
{
var m:uint;
var n:uint;
if (encrypting)
{
m = i << 1;
}
else
{
m = (15 - i) << 1;
}
n = m + 1;
newKey[m] = newKey[n] = 0;
for (j = 0; j < 28; j++)
{
l = j + totrot[i];
if (l < 28)
{
pcr[j] = pc1m[l];
}
else
{
pcr[j] = pc1m[l - 28];
}
}
for (j = 28; j < 56; j++)
{
l = j + totrot[i];
if (l < 56)
{
pcr[j] = pc1m[l];
}
else
{
pcr[j] = pc1m[l - 28];
}
}
for (j = 0; j < 24; j++)
{
if (pcr[pc2[j]])
{
newKey[m] |= bigbyte[j];
}
if (pcr[pc2[j + 24]])
{
newKey[n] |= bigbyte[j];
}
}
}
//
// store the processed key
//
for (i = 0; i != 32; i += 2)
{
var i1:uint;
var i2:uint;
i1 = newKey[i];
i2 = newKey[i + 1];
newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10) | ((i2 & 0x00fc0000) >>> 10)
| ((i2 & 0x00000fc0) >>> 6);
newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16) | ((i2 & 0x0003f000) >>> 4)
| (i2 & 0x0000003f);
}
return newKey;
}
/**
* the DES engine.
*/
protected function desFunc(wKey:Array, inp:ByteArray, inOff:uint, out:ByteArray, outOff:uint):void
{
var work:uint;
var right:uint;
var left:uint;
left = (inp[inOff + 0] & 0xff) << 24;
left |= (inp[inOff + 1] & 0xff) << 16;
left |= (inp[inOff + 2] & 0xff) << 8;
left |= (inp[inOff + 3] & 0xff);
right = (inp[inOff + 4] & 0xff) << 24;
right |= (inp[inOff + 5] & 0xff) << 16;
right |= (inp[inOff + 6] & 0xff) << 8;
right |= (inp[inOff + 7] & 0xff);
work = ((left >>> 4) ^ right) & 0x0f0f0f0f;
right ^= work;
left ^= (work << 4);
work = ((left >>> 16) ^ right) & 0x0000ffff;
right ^= work;
left ^= (work << 16);
work = ((right >>> 2) ^ left) & 0x33333333;
left ^= work;
right ^= (work << 2);
work = ((right >>> 8) ^ left) & 0x00ff00ff;
left ^= work;
right ^= (work << 8);
right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;
work = (left ^ right) & 0xaaaaaaaa;
left ^= work;
right ^= work;
left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;
for (var round:uint = 0; round < 8; round++)
{
var fval:uint;
work = (right << 28) | (right >>> 4);
work ^= wKey[round * 4 + 0];
fval = SP7[work & 0x3f];
fval |= SP5[(work >>> 8) & 0x3f];
fval |= SP3[(work >>> 16) & 0x3f];
fval |= SP1[(work >>> 24) & 0x3f];
work = right ^ wKey[round * 4 + 1];
fval |= SP8[work & 0x3f];
fval |= SP6[(work >>> 8) & 0x3f];
fval |= SP4[(work >>> 16) & 0x3f];
fval |= SP2[(work >>> 24) & 0x3f];
left ^= fval;
work = (left << 28) | (left >>> 4);
work ^= wKey[round * 4 + 2];
fval = SP7[work & 0x3f];
fval |= SP5[(work >>> 8) & 0x3f];
fval |= SP3[(work >>> 16) & 0x3f];
fval |= SP1[(work >>> 24) & 0x3f];
work = left ^ wKey[round * 4 + 3];
fval |= SP8[work & 0x3f];
fval |= SP6[(work >>> 8) & 0x3f];
fval |= SP4[(work >>> 16) & 0x3f];
fval |= SP2[(work >>> 24) & 0x3f];
right ^= fval;
}
right = (right << 31) | (right >>> 1);
work = (left ^ right) & 0xaaaaaaaa;
left ^= work;
right ^= work;
left = (left << 31) | (left >>> 1);
work = ((left >>> 8) ^ right) & 0x00ff00ff;
right ^= work;
left ^= (work << 8);
work = ((left >>> 2) ^ right) & 0x33333333;
right ^= work;
left ^= (work << 2);
work = ((right >>> 16) ^ left) & 0x0000ffff;
left ^= work;
right ^= (work << 16);
work = ((right >>> 4) ^ left) & 0x0f0f0f0f;
left ^= work;
right ^= (work << 4);
out[outOff + 0] = ((right >>> 24) & 0xff);
out[outOff + 1] = ((right >>> 16) & 0xff);
out[outOff + 2] = ((right >>> 8) & 0xff);
out[outOff + 3] = (right & 0xff);
out[outOff + 4] = ((left >>> 24) & 0xff);
out[outOff + 5] = ((left >>> 16) & 0xff);
out[outOff + 6] = ((left >>> 8) & 0xff);
out[outOff + 7] = (left & 0xff);
}
public function toString():String {
return "des";
}
}
}
\ No newline at end of file
/**
* ECBMode
*
* An ActionScript 3 implementation of the ECB confidentiality mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
import com.hurlant.util.Memory;
import com.hurlant.util.Hex;
/**
* ECB mode.
* This uses a padding and a symmetric key.
* If no padding is given, PKCS#5 is used.
*/
public class ECBMode implements IMode, ICipher
{
private var key:ISymmetricKey;
private var padding:IPad;
public function ECBMode(key:ISymmetricKey, padding:IPad = null) {
this.key = key;
if (padding == null) {
padding = new PKCS5(key.getBlockSize());
} else {
padding.setBlockSize(key.getBlockSize());
}
this.padding = padding;
}
public function getBlockSize():uint {
return key.getBlockSize();
}
public function encrypt(src:ByteArray):void {
padding.pad(src);
src.position = 0;
var blockSize:uint = key.getBlockSize();
var tmp:ByteArray = new ByteArray;
var dst:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i+=blockSize) {
tmp.length=0;
src.readBytes(tmp, 0, blockSize);
key.encrypt(tmp);
dst.writeBytes(tmp);
}
src.length=0;
src.writeBytes(dst);
}
public function decrypt(src:ByteArray):void {
src.position = 0;
var blockSize:uint = key.getBlockSize();
// sanity check.
if (src.length%blockSize!=0) {
throw new Error("ECB mode cipher length must be a multiple of blocksize "+blockSize);
}
var tmp:ByteArray = new ByteArray;
var dst:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i+=blockSize) {
tmp.length=0;
src.readBytes(tmp, 0, blockSize);
key.decrypt(tmp);
dst.writeBytes(tmp);
}
padding.unpad(dst);
src.length=0;
src.writeBytes(dst);
}
public function dispose():void {
key.dispose();
key = null;
padding = null;
Memory.gc();
}
public function toString():String {
return key.toString()+"-ecb";
}
}
}
\ No newline at end of file
/**
* ICipher
*
* A generic interface to use symmetric ciphers
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
public interface ICipher
{
function getBlockSize():uint;
function encrypt(src:ByteArray):void;
function decrypt(src:ByteArray):void;
function dispose():void;
function toString():String;
}
}
\ No newline at end of file
/**
* IMode
*
* An interface for confidentiality modes to implement
* This could become deprecated at some point.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
public interface IMode extends ICipher
{
}
}
\ No newline at end of file
/**
* IPad
*
* An interface for padding mechanisms to implement.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
/**
* Tiny interface that represents a padding mechanism.
*/
public interface IPad
{
/**
* Add padding to the array
*/
function pad(a:ByteArray):void;
/**
* Remove padding from the array.
* @throws Error if the padding is invalid.
*/
function unpad(a:ByteArray):void;
/**
* Set the blockSize to work on
*/
function setBlockSize(bs:uint):void;
}
}
\ No newline at end of file
/**
* IStreamCipher
*
* A "marker" interface for stream ciphers.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric {
/**
* A marker to indicate how this cipher works.
* A stream cipher:
* - does not use initialization vector
* - keeps some internal state between calls to encrypt() and decrypt()
*
*/
public interface IStreamCipher extends ICipher {
}
}
\ No newline at end of file
/**
* ISymmetricKey
*
* An interface for symmetric encryption keys to implement.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
public interface ISymmetricKey
{
/**
* Returns the block size used by this particular encryption algorithm
*/
function getBlockSize():uint;
/**
* Encrypt one block of data in "block", starting at "index", of length "getBlockSize()"
*/
function encrypt(block:ByteArray, index:uint=0):void;
/**
* Decrypt one block of data in "block", starting at "index", of length "getBlockSize()"
*/
function decrypt(block:ByteArray, index:uint=0):void;
/**
* Attempts to destroy sensitive information from memory, such as encryption keys.
* Note: This is not guaranteed to work given the Flash sandbox model.
*/
function dispose():void;
function toString():String;
}
}
\ No newline at end of file
/**
* IVMode
*
* An abstract class for confidentialy modes that rely on an initialization vector.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import com.hurlant.crypto.prng.Random;
import com.hurlant.crypto.tests.TestCase;
import com.hurlant.util.Memory;
import flash.utils.ByteArray;
/**
* An "abtract" class to avoid redundant code in subclasses
*/
public class IVMode
{
protected var key:ISymmetricKey;
protected var padding:IPad;
// random generator used to generate IVs
protected var prng:Random;
// optional static IV. used for testing only.
protected var iv:ByteArray;
// generated IV is stored here.
protected var lastIV:ByteArray;
protected var blockSize:uint;
public function IVMode(key:ISymmetricKey, padding:IPad = null) {
this.key = key;
blockSize = key.getBlockSize();
if (padding == null) {
padding = new PKCS5(blockSize);
} else {
padding.setBlockSize(blockSize);
}
this.padding = padding;
prng = new Random;
iv = null;
lastIV = new ByteArray;
}
public function getBlockSize():uint {
return key.getBlockSize();
}
public function dispose():void {
var i:uint;
if (iv != null) {
for (i=0;i<iv.length;i++) {
iv[i] = prng.nextByte();
}
iv.length=0;
iv = null;
}
if (lastIV != null) {
for (i=0;i<iv.length;i++) {
lastIV[i] = prng.nextByte();
}
lastIV.length=0;
lastIV=null;
}
key.dispose();
key = null;
padding = null;
prng.dispose();
prng = null;
Memory.gc();
}
/**
* Optional function to force the IV value.
* Normally, an IV gets generated randomly at every encrypt() call.
* Also, use this to set the IV before calling decrypt()
* (if not set before decrypt(), the IV is read from the beginning of the stream.)
*/
public function set IV(value:ByteArray):void {
iv = value;
lastIV.length=0;
lastIV.writeBytes(iv);
}
public function get IV():ByteArray {
return lastIV;
}
protected function getIV4e():ByteArray {
var vec:ByteArray = new ByteArray;
if (iv) {
vec.writeBytes(iv);
} else {
prng.nextBytes(vec, blockSize);
}
lastIV.length=0;
lastIV.writeBytes(vec);
return vec;
}
protected function getIV4d():ByteArray {
var vec:ByteArray = new ByteArray;
if (iv) {
vec.writeBytes(iv);
} else {
throw new Error("an IV must be set before calling decrypt()");
}
return vec;
}
}
}
\ No newline at end of file
/**
* NullPad
*
* A padding class that doesn't pad.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
/**
* A pad that does nothing.
* Useful when you don't want padding in your Mode.
*/
public class NullPad implements IPad
{
public function unpad(a:ByteArray):void
{
return;
}
public function pad(a:ByteArray):void
{
return;
}
public function setBlockSize(bs:uint):void {
return;
}
}
}
\ No newline at end of file
/**
* OFBMode
*
* An ActionScript 3 implementation of the OFB confidentiality mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
public class OFBMode extends IVMode implements IMode
{
public function OFBMode(key:ISymmetricKey, padding:IPad=null)
{
super(key, null);
}
public function encrypt(src:ByteArray):void
{
var vector:ByteArray = getIV4e();
core(src, vector);
}
public function decrypt(src:ByteArray):void
{
var vector:ByteArray = getIV4d();
core(src, vector);
}
private function core(src:ByteArray, iv:ByteArray):void {
var l:uint = src.length;
var tmp:ByteArray = new ByteArray;
for (var i:uint=0;i<src.length;i+=blockSize) {
key.encrypt(iv);
tmp.position=0;
tmp.writeBytes(iv);
var chunk:uint = (i+blockSize<l)?blockSize:l-i;
for (var j:uint=0;j<chunk;j++) {
src[i+j] ^= iv[j];
}
iv.position=0;
iv.writeBytes(tmp);
}
}
public function toString():String {
return key.toString()+"-ofb";
}
}
}
\ No newline at end of file
/**
* PKCS5
*
* A padding implementation of PKCS5.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
public class PKCS5 implements IPad
{
private var blockSize:uint;
public function PKCS5(blockSize:uint=0) {
this.blockSize = blockSize;
}
public function pad(a:ByteArray):void {
var c:uint = blockSize-a.length%blockSize;
for (var i:uint=0;i<c;i++){
a[a.length] = c;
}
}
public function unpad(a:ByteArray):void {
var c:uint = a.length%blockSize;
if (c!=0) throw new Error("PKCS#5::unpad: ByteArray.length isn't a multiple of the blockSize");
c = a[a.length-1];
for (var i:uint=c;i>0;i--) {
var v:uint = a[a.length-1];
a.length--;
if (c!=v) throw new Error("PKCS#5:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]");
}
// that is all.
}
public function setBlockSize(bs:uint):void {
blockSize = bs;
}
}
}
\ No newline at end of file
/**
* TLSPad
*
* A padding implementation used by TLS
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric {
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.crypto.tls.TLSError;
public class SSLPad implements IPad {
private var blockSize:uint;
public function SSLPad(blockSize:uint=0) {
this.blockSize = blockSize;
}
public function pad(a:ByteArray):void {
var c:uint = blockSize - (a.length+1)%blockSize;
for (var i:uint=0;i<=c;i++) {
a[a.length] = c;
}
}
public function unpad(a:ByteArray):void {
var c:uint = a.length%blockSize;
if (c!=0) throw new TLSError("SSLPad::unpad: ByteArray.length isn't a multiple of the blockSize", TLSError.bad_record_mac);
c = a[a.length-1];
for (var i:uint=c;i>0;i--) {
var v:uint = a[a.length-1];
a.length--;
// But LOOK! SSL 3.0 doesn't care about this, bytes are arbitrary!
// if (c!=v) throw new TLSError("SSLPad:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]", TLSError.bad_record_mac);
}
a.length--;
}
public function setBlockSize(bs:uint):void {
blockSize = bs;
}
}
}
\ No newline at end of file
/**
* SimpleIVMode
*
* A convenience class that automatically places the IV
* at the beginning of the encrypted stream, so it doesn't have to
* be handled explicitely.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
import com.hurlant.util.Memory;
public class SimpleIVMode implements IMode, ICipher
{
protected var mode:IVMode;
protected var cipher:ICipher;
public function SimpleIVMode(mode:IVMode) {
this.mode = mode;
cipher = mode as ICipher;
}
public function getBlockSize():uint {
return mode.getBlockSize();
}
public function dispose():void {
mode.dispose();
mode = null;
cipher = null;
Memory.gc();
}
public function encrypt(src:ByteArray):void {
cipher.encrypt(src);
var tmp:ByteArray = new ByteArray;
tmp.writeBytes(mode.IV);
tmp.writeBytes(src);
src.position=0;
src.writeBytes(tmp);
}
public function decrypt(src:ByteArray):void {
var tmp:ByteArray = new ByteArray;
tmp.writeBytes(src, 0, getBlockSize());
mode.IV = tmp;
tmp = new ByteArray;
tmp.writeBytes(src, getBlockSize());
cipher.decrypt(tmp);
src.length=0;
src.writeBytes(tmp);
}
public function toString():String {
return "simple-"+cipher.toString();
}
}
}
\ No newline at end of file
/**
* TLSPad
*
* A padding implementation used by TLS
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric {
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.crypto.tls.TLSError;
public class TLSPad implements IPad {
private var blockSize:uint;
public function TLSPad(blockSize:uint=0) {
this.blockSize = blockSize;
}
public function pad(a:ByteArray):void {
var c:uint = blockSize - (a.length+1)%blockSize;
for (var i:uint=0;i<=c;i++) {
a[a.length] = c;
}
}
public function unpad(a:ByteArray):void {
var c:uint = a.length%blockSize;
if (c!=0) throw new TLSError("TLSPad::unpad: ByteArray.length isn't a multiple of the blockSize", TLSError.bad_record_mac);
c = a[a.length-1];
for (var i:uint=c;i>0;i--) {
var v:uint = a[a.length-1];
a.length--;
if (c!=v) throw new TLSError("TLSPad:unpad: Invalid padding value. expected ["+c+"], found ["+v+"]", TLSError.bad_record_mac);
}
a.length--;
// mostly ripped off from PKCS5.as, but with subtle differences
}
public function setBlockSize(bs:uint):void {
blockSize = bs;
}
}
}
\ No newline at end of file
/**
* TripleDESKey
*
* An Actionscript 3 implementation of Triple DES
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The Bouncy Castle Crypto package,
* Copyright (c) 2000-2004 The Legion Of The Bouncy Castle
* (http://www.bouncycastle.org)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import flash.utils.ByteArray;
import com.hurlant.util.Memory;
import com.hurlant.util.Hex;
public class TripleDESKey extends DESKey
{
protected var encKey2:Array;
protected var encKey3:Array;
protected var decKey2:Array;
protected var decKey3:Array;
/**
* This supports 2TDES and 3TDES.
* If the key passed is 128 bits, 2TDES is used.
* If the key has 192 bits, 3TDES is used.
* Other key lengths give "undefined" results.
*/
public function TripleDESKey(key:ByteArray)
{
super(key);
encKey2 = generateWorkingKey(false, key, 8);
decKey2 = generateWorkingKey(true, key, 8);
if (key.length>16) {
encKey3 = generateWorkingKey(true, key, 16);
decKey3 = generateWorkingKey(false, key, 16);
} else {
encKey3 = encKey;
decKey3 = decKey;
}
}
public override function dispose():void
{
super.dispose();
var i:uint = 0;
if (encKey2!=null) {
for (i=0;i<encKey2.length;i++) { encKey2[i]=0; }
encKey2=null;
}
if (encKey3!=null) {
for (i=0;i<encKey3.length;i++) { encKey3[i]=0; }
encKey3=null;
}
if (decKey2!=null) {
for (i=0;i<decKey2.length;i++) { decKey2[i]=0; }
decKey2=null
}
if (decKey3!=null) {
for (i=0;i<decKey3.length;i++) { decKey3[i]=0; }
decKey3=null;
}
Memory.gc();
}
public override function encrypt(block:ByteArray, index:uint=0):void
{
desFunc(encKey, block,index, block,index);
desFunc(encKey2, block,index, block,index);
desFunc(encKey3, block,index, block,index);
}
public override function decrypt(block:ByteArray, index:uint=0):void
{
desFunc(decKey3, block, index, block, index);
desFunc(decKey2, block, index, block, index);
desFunc(decKey, block, index, block, index);
}
public override function toString():String {
return "3des";
}
}
}
\ No newline at end of file
/**
* XTeaKey
*
* An ActionScript 3 implementation of the XTea algorithm
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.symmetric
{
import com.hurlant.crypto.prng.Random;
import com.hurlant.util.Memory;
import flash.utils.ByteArray;
public class XTeaKey implements ISymmetricKey
{
public const NUM_ROUNDS:uint = 64;
private var k:Array;
public function XTeaKey(a:ByteArray) {
a.position=0;
k = [a.readUnsignedInt(),a.readUnsignedInt(),a.readUnsignedInt(),a.readUnsignedInt()];
}
/**
* K is an hex string with 32 digits.
*/
public static function parseKey(K:String):XTeaKey {
var a:ByteArray = new ByteArray;
a.writeUnsignedInt(parseInt(K.substr(0,8),16));
a.writeUnsignedInt(parseInt(K.substr(8,8),16));
a.writeUnsignedInt(parseInt(K.substr(16,8),16));
a.writeUnsignedInt(parseInt(K.substr(24,8),16));
a.position = 0;
return new XTeaKey(a);
}
public function getBlockSize():uint {
return 8;
}
public function encrypt(block:ByteArray, index:uint=0):void {
block.position = index;
var v0:uint = block.readUnsignedInt();
var v1:uint = block.readUnsignedInt();
var i:uint;
var sum:uint =0;
var delta:uint = 0x9E3779B9;
for (i=0; i<NUM_ROUNDS; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
}
block.position-=8;
block.writeUnsignedInt(v0);
block.writeUnsignedInt(v1);
}
public function decrypt(block:ByteArray, index:uint=0):void {
block.position = index;
var v0:uint = block.readUnsignedInt();
var v1:uint = block.readUnsignedInt();
var i:uint;
var delta:uint = 0x9E3779B9;
var sum:uint = delta*NUM_ROUNDS;
for (i=0; i<NUM_ROUNDS; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
}
block.position-=8;
block.writeUnsignedInt(v0);
block.writeUnsignedInt(v1);
}
public function dispose():void {
//private var k:Array;
var r:Random = new Random;
for (var i:uint=0;i<k.length;i++) {
k[i] = r.nextByte();
delete k[i];
}
k = null;
Memory.gc();
}
public function toString():String {
return "xtea";
}
}
}
\ No newline at end of file
#!/usr/bin/perl
use strict;
use warnings;
sub say {
my $w = shift;
print $w;
print "\n";
}
sub dump {
my $i = shift;
&say(sprintf("Sbox[%d] = _Sbox[%d]", $i, $i));
&say(sprintf("InvSbox[%d] = _InvSbox[%d]", $i, $i));
&say(sprintf("Xtime2Sbox[%d] = _Xtime2Sbox[%d]", $i, $i));
&say(sprintf("Xtime3Sbox[%d] = _Xtime3Sbox[%d]", $i, $i));
&say(sprintf("Xtime2[%d] = _Xtime2[%d]", $i, $i));
&say(sprintf("Xtime9[%d] = _Xtime9[%d]", $i, $i));
&say(sprintf("XtimeB[%d] = _XtimeB[%d]", $i, $i));
&say(sprintf("XtimeD[%d] = _XtimeD[%d]", $i, $i));
&say(sprintf("XtimeE[%d] = _XtimeE[%d]", $i, $i));
}
for (my $i=0;$i<256;$i++) {
&dump($i);
}
Sbox[0] = _Sbox[0]
InvSbox[0] = _InvSbox[0]
Xtime2Sbox[0] = _Xtime2Sbox[0]
Xtime3Sbox[0] = _Xtime3Sbox[0]
Xtime2[0] = _Xtime2[0]
Xtime9[0] = _Xtime9[0]
XtimeB[0] = _XtimeB[0]
XtimeD[0] = _XtimeD[0]
XtimeE[0] = _XtimeE[0]
Sbox[1] = _Sbox[1]
InvSbox[1] = _InvSbox[1]
Xtime2Sbox[1] = _Xtime2Sbox[1]
Xtime3Sbox[1] = _Xtime3Sbox[1]
Xtime2[1] = _Xtime2[1]
Xtime9[1] = _Xtime9[1]
XtimeB[1] = _XtimeB[1]
XtimeD[1] = _XtimeD[1]
XtimeE[1] = _XtimeE[1]
Sbox[2] = _Sbox[2]
InvSbox[2] = _InvSbox[2]
Xtime2Sbox[2] = _Xtime2Sbox[2]
Xtime3Sbox[2] = _Xtime3Sbox[2]
Xtime2[2] = _Xtime2[2]
Xtime9[2] = _Xtime9[2]
XtimeB[2] = _XtimeB[2]
XtimeD[2] = _XtimeD[2]
XtimeE[2] = _XtimeE[2]
Sbox[3] = _Sbox[3]
InvSbox[3] = _InvSbox[3]
Xtime2Sbox[3] = _Xtime2Sbox[3]
Xtime3Sbox[3] = _Xtime3Sbox[3]
Xtime2[3] = _Xtime2[3]
Xtime9[3] = _Xtime9[3]
XtimeB[3] = _XtimeB[3]
XtimeD[3] = _XtimeD[3]
XtimeE[3] = _XtimeE[3]
Sbox[4] = _Sbox[4]
InvSbox[4] = _InvSbox[4]
Xtime2Sbox[4] = _Xtime2Sbox[4]
Xtime3Sbox[4] = _Xtime3Sbox[4]
Xtime2[4] = _Xtime2[4]
Xtime9[4] = _Xtime9[4]
XtimeB[4] = _XtimeB[4]
XtimeD[4] = _XtimeD[4]
XtimeE[4] = _XtimeE[4]
Sbox[5] = _Sbox[5]
InvSbox[5] = _InvSbox[5]
Xtime2Sbox[5] = _Xtime2Sbox[5]
Xtime3Sbox[5] = _Xtime3Sbox[5]
Xtime2[5] = _Xtime2[5]
Xtime9[5] = _Xtime9[5]
XtimeB[5] = _XtimeB[5]
XtimeD[5] = _XtimeD[5]
XtimeE[5] = _XtimeE[5]
Sbox[6] = _Sbox[6]
InvSbox[6] = _InvSbox[6]
Xtime2Sbox[6] = _Xtime2Sbox[6]
Xtime3Sbox[6] = _Xtime3Sbox[6]
Xtime2[6] = _Xtime2[6]
Xtime9[6] = _Xtime9[6]
XtimeB[6] = _XtimeB[6]
XtimeD[6] = _XtimeD[6]
XtimeE[6] = _XtimeE[6]
Sbox[7] = _Sbox[7]
InvSbox[7] = _InvSbox[7]
Xtime2Sbox[7] = _Xtime2Sbox[7]
Xtime3Sbox[7] = _Xtime3Sbox[7]
Xtime2[7] = _Xtime2[7]
Xtime9[7] = _Xtime9[7]
XtimeB[7] = _XtimeB[7]
XtimeD[7] = _XtimeD[7]
XtimeE[7] = _XtimeE[7]
Sbox[8] = _Sbox[8]
InvSbox[8] = _InvSbox[8]
Xtime2Sbox[8] = _Xtime2Sbox[8]
Xtime3Sbox[8] = _Xtime3Sbox[8]
Xtime2[8] = _Xtime2[8]
Xtime9[8] = _Xtime9[8]
XtimeB[8] = _XtimeB[8]
XtimeD[8] = _XtimeD[8]
XtimeE[8] = _XtimeE[8]
Sbox[9] = _Sbox[9]
InvSbox[9] = _InvSbox[9]
Xtime2Sbox[9] = _Xtime2Sbox[9]
Xtime3Sbox[9] = _Xtime3Sbox[9]
Xtime2[9] = _Xtime2[9]
Xtime9[9] = _Xtime9[9]
XtimeB[9] = _XtimeB[9]
XtimeD[9] = _XtimeD[9]
XtimeE[9] = _XtimeE[9]
Sbox[10] = _Sbox[10]
InvSbox[10] = _InvSbox[10]
Xtime2Sbox[10] = _Xtime2Sbox[10]
Xtime3Sbox[10] = _Xtime3Sbox[10]
Xtime2[10] = _Xtime2[10]
Xtime9[10] = _Xtime9[10]
XtimeB[10] = _XtimeB[10]
XtimeD[10] = _XtimeD[10]
XtimeE[10] = _XtimeE[10]
Sbox[11] = _Sbox[11]
InvSbox[11] = _InvSbox[11]
Xtime2Sbox[11] = _Xtime2Sbox[11]
Xtime3Sbox[11] = _Xtime3Sbox[11]
Xtime2[11] = _Xtime2[11]
Xtime9[11] = _Xtime9[11]
XtimeB[11] = _XtimeB[11]
XtimeD[11] = _XtimeD[11]
XtimeE[11] = _XtimeE[11]
Sbox[12] = _Sbox[12]
InvSbox[12] = _InvSbox[12]
Xtime2Sbox[12] = _Xtime2Sbox[12]
Xtime3Sbox[12] = _Xtime3Sbox[12]
Xtime2[12] = _Xtime2[12]
Xtime9[12] = _Xtime9[12]
XtimeB[12] = _XtimeB[12]
XtimeD[12] = _XtimeD[12]
XtimeE[12] = _XtimeE[12]
Sbox[13] = _Sbox[13]
InvSbox[13] = _InvSbox[13]
Xtime2Sbox[13] = _Xtime2Sbox[13]
Xtime3Sbox[13] = _Xtime3Sbox[13]
Xtime2[13] = _Xtime2[13]
Xtime9[13] = _Xtime9[13]
XtimeB[13] = _XtimeB[13]
XtimeD[13] = _XtimeD[13]
XtimeE[13] = _XtimeE[13]
Sbox[14] = _Sbox[14]
InvSbox[14] = _InvSbox[14]
Xtime2Sbox[14] = _Xtime2Sbox[14]
Xtime3Sbox[14] = _Xtime3Sbox[14]
Xtime2[14] = _Xtime2[14]
Xtime9[14] = _Xtime9[14]
XtimeB[14] = _XtimeB[14]
XtimeD[14] = _XtimeD[14]
XtimeE[14] = _XtimeE[14]
Sbox[15] = _Sbox[15]
InvSbox[15] = _InvSbox[15]
Xtime2Sbox[15] = _Xtime2Sbox[15]
Xtime3Sbox[15] = _Xtime3Sbox[15]
Xtime2[15] = _Xtime2[15]
Xtime9[15] = _Xtime9[15]
XtimeB[15] = _XtimeB[15]
XtimeD[15] = _XtimeD[15]
XtimeE[15] = _XtimeE[15]
Sbox[16] = _Sbox[16]
InvSbox[16] = _InvSbox[16]
Xtime2Sbox[16] = _Xtime2Sbox[16]
Xtime3Sbox[16] = _Xtime3Sbox[16]
Xtime2[16] = _Xtime2[16]
Xtime9[16] = _Xtime9[16]
XtimeB[16] = _XtimeB[16]
XtimeD[16] = _XtimeD[16]
XtimeE[16] = _XtimeE[16]
Sbox[17] = _Sbox[17]
InvSbox[17] = _InvSbox[17]
Xtime2Sbox[17] = _Xtime2Sbox[17]
Xtime3Sbox[17] = _Xtime3Sbox[17]
Xtime2[17] = _Xtime2[17]
Xtime9[17] = _Xtime9[17]
XtimeB[17] = _XtimeB[17]
XtimeD[17] = _XtimeD[17]
XtimeE[17] = _XtimeE[17]
Sbox[18] = _Sbox[18]
InvSbox[18] = _InvSbox[18]
Xtime2Sbox[18] = _Xtime2Sbox[18]
Xtime3Sbox[18] = _Xtime3Sbox[18]
Xtime2[18] = _Xtime2[18]
Xtime9[18] = _Xtime9[18]
XtimeB[18] = _XtimeB[18]
XtimeD[18] = _XtimeD[18]
XtimeE[18] = _XtimeE[18]
Sbox[19] = _Sbox[19]
InvSbox[19] = _InvSbox[19]
Xtime2Sbox[19] = _Xtime2Sbox[19]
Xtime3Sbox[19] = _Xtime3Sbox[19]
Xtime2[19] = _Xtime2[19]
Xtime9[19] = _Xtime9[19]
XtimeB[19] = _XtimeB[19]
XtimeD[19] = _XtimeD[19]
XtimeE[19] = _XtimeE[19]
Sbox[20] = _Sbox[20]
InvSbox[20] = _InvSbox[20]
Xtime2Sbox[20] = _Xtime2Sbox[20]
Xtime3Sbox[20] = _Xtime3Sbox[20]
Xtime2[20] = _Xtime2[20]
Xtime9[20] = _Xtime9[20]
XtimeB[20] = _XtimeB[20]
XtimeD[20] = _XtimeD[20]
XtimeE[20] = _XtimeE[20]
Sbox[21] = _Sbox[21]
InvSbox[21] = _InvSbox[21]
Xtime2Sbox[21] = _Xtime2Sbox[21]
Xtime3Sbox[21] = _Xtime3Sbox[21]
Xtime2[21] = _Xtime2[21]
Xtime9[21] = _Xtime9[21]
XtimeB[21] = _XtimeB[21]
XtimeD[21] = _XtimeD[21]
XtimeE[21] = _XtimeE[21]
Sbox[22] = _Sbox[22]
InvSbox[22] = _InvSbox[22]
Xtime2Sbox[22] = _Xtime2Sbox[22]
Xtime3Sbox[22] = _Xtime3Sbox[22]
Xtime2[22] = _Xtime2[22]
Xtime9[22] = _Xtime9[22]
XtimeB[22] = _XtimeB[22]
XtimeD[22] = _XtimeD[22]
XtimeE[22] = _XtimeE[22]
Sbox[23] = _Sbox[23]
InvSbox[23] = _InvSbox[23]
Xtime2Sbox[23] = _Xtime2Sbox[23]
Xtime3Sbox[23] = _Xtime3Sbox[23]
Xtime2[23] = _Xtime2[23]
Xtime9[23] = _Xtime9[23]
XtimeB[23] = _XtimeB[23]
XtimeD[23] = _XtimeD[23]
XtimeE[23] = _XtimeE[23]
Sbox[24] = _Sbox[24]
InvSbox[24] = _InvSbox[24]
Xtime2Sbox[24] = _Xtime2Sbox[24]
Xtime3Sbox[24] = _Xtime3Sbox[24]
Xtime2[24] = _Xtime2[24]
Xtime9[24] = _Xtime9[24]
XtimeB[24] = _XtimeB[24]
XtimeD[24] = _XtimeD[24]
XtimeE[24] = _XtimeE[24]
Sbox[25] = _Sbox[25]
InvSbox[25] = _InvSbox[25]
Xtime2Sbox[25] = _Xtime2Sbox[25]
Xtime3Sbox[25] = _Xtime3Sbox[25]
Xtime2[25] = _Xtime2[25]
Xtime9[25] = _Xtime9[25]
XtimeB[25] = _XtimeB[25]
XtimeD[25] = _XtimeD[25]
XtimeE[25] = _XtimeE[25]
Sbox[26] = _Sbox[26]
InvSbox[26] = _InvSbox[26]
Xtime2Sbox[26] = _Xtime2Sbox[26]
Xtime3Sbox[26] = _Xtime3Sbox[26]
Xtime2[26] = _Xtime2[26]
Xtime9[26] = _Xtime9[26]
XtimeB[26] = _XtimeB[26]
XtimeD[26] = _XtimeD[26]
XtimeE[26] = _XtimeE[26]
Sbox[27] = _Sbox[27]
InvSbox[27] = _InvSbox[27]
Xtime2Sbox[27] = _Xtime2Sbox[27]
Xtime3Sbox[27] = _Xtime3Sbox[27]
Xtime2[27] = _Xtime2[27]
Xtime9[27] = _Xtime9[27]
XtimeB[27] = _XtimeB[27]
XtimeD[27] = _XtimeD[27]
XtimeE[27] = _XtimeE[27]
Sbox[28] = _Sbox[28]
InvSbox[28] = _InvSbox[28]
Xtime2Sbox[28] = _Xtime2Sbox[28]
Xtime3Sbox[28] = _Xtime3Sbox[28]
Xtime2[28] = _Xtime2[28]
Xtime9[28] = _Xtime9[28]
XtimeB[28] = _XtimeB[28]
XtimeD[28] = _XtimeD[28]
XtimeE[28] = _XtimeE[28]
Sbox[29] = _Sbox[29]
InvSbox[29] = _InvSbox[29]
Xtime2Sbox[29] = _Xtime2Sbox[29]
Xtime3Sbox[29] = _Xtime3Sbox[29]
Xtime2[29] = _Xtime2[29]
Xtime9[29] = _Xtime9[29]
XtimeB[29] = _XtimeB[29]
XtimeD[29] = _XtimeD[29]
XtimeE[29] = _XtimeE[29]
Sbox[30] = _Sbox[30]
InvSbox[30] = _InvSbox[30]
Xtime2Sbox[30] = _Xtime2Sbox[30]
Xtime3Sbox[30] = _Xtime3Sbox[30]
Xtime2[30] = _Xtime2[30]
Xtime9[30] = _Xtime9[30]
XtimeB[30] = _XtimeB[30]
XtimeD[30] = _XtimeD[30]
XtimeE[30] = _XtimeE[30]
Sbox[31] = _Sbox[31]
InvSbox[31] = _InvSbox[31]
Xtime2Sbox[31] = _Xtime2Sbox[31]
Xtime3Sbox[31] = _Xtime3Sbox[31]
Xtime2[31] = _Xtime2[31]
Xtime9[31] = _Xtime9[31]
XtimeB[31] = _XtimeB[31]
XtimeD[31] = _XtimeD[31]
XtimeE[31] = _XtimeE[31]
Sbox[32] = _Sbox[32]
InvSbox[32] = _InvSbox[32]
Xtime2Sbox[32] = _Xtime2Sbox[32]
Xtime3Sbox[32] = _Xtime3Sbox[32]
Xtime2[32] = _Xtime2[32]
Xtime9[32] = _Xtime9[32]
XtimeB[32] = _XtimeB[32]
XtimeD[32] = _XtimeD[32]
XtimeE[32] = _XtimeE[32]
Sbox[33] = _Sbox[33]
InvSbox[33] = _InvSbox[33]
Xtime2Sbox[33] = _Xtime2Sbox[33]
Xtime3Sbox[33] = _Xtime3Sbox[33]
Xtime2[33] = _Xtime2[33]
Xtime9[33] = _Xtime9[33]
XtimeB[33] = _XtimeB[33]
XtimeD[33] = _XtimeD[33]
XtimeE[33] = _XtimeE[33]
Sbox[34] = _Sbox[34]
InvSbox[34] = _InvSbox[34]
Xtime2Sbox[34] = _Xtime2Sbox[34]
Xtime3Sbox[34] = _Xtime3Sbox[34]
Xtime2[34] = _Xtime2[34]
Xtime9[34] = _Xtime9[34]
XtimeB[34] = _XtimeB[34]
XtimeD[34] = _XtimeD[34]
XtimeE[34] = _XtimeE[34]
Sbox[35] = _Sbox[35]
InvSbox[35] = _InvSbox[35]
Xtime2Sbox[35] = _Xtime2Sbox[35]
Xtime3Sbox[35] = _Xtime3Sbox[35]
Xtime2[35] = _Xtime2[35]
Xtime9[35] = _Xtime9[35]
XtimeB[35] = _XtimeB[35]
XtimeD[35] = _XtimeD[35]
XtimeE[35] = _XtimeE[35]
Sbox[36] = _Sbox[36]
InvSbox[36] = _InvSbox[36]
Xtime2Sbox[36] = _Xtime2Sbox[36]
Xtime3Sbox[36] = _Xtime3Sbox[36]
Xtime2[36] = _Xtime2[36]
Xtime9[36] = _Xtime9[36]
XtimeB[36] = _XtimeB[36]
XtimeD[36] = _XtimeD[36]
XtimeE[36] = _XtimeE[36]
Sbox[37] = _Sbox[37]
InvSbox[37] = _InvSbox[37]
Xtime2Sbox[37] = _Xtime2Sbox[37]
Xtime3Sbox[37] = _Xtime3Sbox[37]
Xtime2[37] = _Xtime2[37]
Xtime9[37] = _Xtime9[37]
XtimeB[37] = _XtimeB[37]
XtimeD[37] = _XtimeD[37]
XtimeE[37] = _XtimeE[37]
Sbox[38] = _Sbox[38]
InvSbox[38] = _InvSbox[38]
Xtime2Sbox[38] = _Xtime2Sbox[38]
Xtime3Sbox[38] = _Xtime3Sbox[38]
Xtime2[38] = _Xtime2[38]
Xtime9[38] = _Xtime9[38]
XtimeB[38] = _XtimeB[38]
XtimeD[38] = _XtimeD[38]
XtimeE[38] = _XtimeE[38]
Sbox[39] = _Sbox[39]
InvSbox[39] = _InvSbox[39]
Xtime2Sbox[39] = _Xtime2Sbox[39]
Xtime3Sbox[39] = _Xtime3Sbox[39]
Xtime2[39] = _Xtime2[39]
Xtime9[39] = _Xtime9[39]
XtimeB[39] = _XtimeB[39]
XtimeD[39] = _XtimeD[39]
XtimeE[39] = _XtimeE[39]
Sbox[40] = _Sbox[40]
InvSbox[40] = _InvSbox[40]
Xtime2Sbox[40] = _Xtime2Sbox[40]
Xtime3Sbox[40] = _Xtime3Sbox[40]
Xtime2[40] = _Xtime2[40]
Xtime9[40] = _Xtime9[40]
XtimeB[40] = _XtimeB[40]
XtimeD[40] = _XtimeD[40]
XtimeE[40] = _XtimeE[40]
Sbox[41] = _Sbox[41]
InvSbox[41] = _InvSbox[41]
Xtime2Sbox[41] = _Xtime2Sbox[41]
Xtime3Sbox[41] = _Xtime3Sbox[41]
Xtime2[41] = _Xtime2[41]
Xtime9[41] = _Xtime9[41]
XtimeB[41] = _XtimeB[41]
XtimeD[41] = _XtimeD[41]
XtimeE[41] = _XtimeE[41]
Sbox[42] = _Sbox[42]
InvSbox[42] = _InvSbox[42]
Xtime2Sbox[42] = _Xtime2Sbox[42]
Xtime3Sbox[42] = _Xtime3Sbox[42]
Xtime2[42] = _Xtime2[42]
Xtime9[42] = _Xtime9[42]
XtimeB[42] = _XtimeB[42]
XtimeD[42] = _XtimeD[42]
XtimeE[42] = _XtimeE[42]
Sbox[43] = _Sbox[43]
InvSbox[43] = _InvSbox[43]
Xtime2Sbox[43] = _Xtime2Sbox[43]
Xtime3Sbox[43] = _Xtime3Sbox[43]
Xtime2[43] = _Xtime2[43]
Xtime9[43] = _Xtime9[43]
XtimeB[43] = _XtimeB[43]
XtimeD[43] = _XtimeD[43]
XtimeE[43] = _XtimeE[43]
Sbox[44] = _Sbox[44]
InvSbox[44] = _InvSbox[44]
Xtime2Sbox[44] = _Xtime2Sbox[44]
Xtime3Sbox[44] = _Xtime3Sbox[44]
Xtime2[44] = _Xtime2[44]
Xtime9[44] = _Xtime9[44]
XtimeB[44] = _XtimeB[44]
XtimeD[44] = _XtimeD[44]
XtimeE[44] = _XtimeE[44]
Sbox[45] = _Sbox[45]
InvSbox[45] = _InvSbox[45]
Xtime2Sbox[45] = _Xtime2Sbox[45]
Xtime3Sbox[45] = _Xtime3Sbox[45]
Xtime2[45] = _Xtime2[45]
Xtime9[45] = _Xtime9[45]
XtimeB[45] = _XtimeB[45]
XtimeD[45] = _XtimeD[45]
XtimeE[45] = _XtimeE[45]
Sbox[46] = _Sbox[46]
InvSbox[46] = _InvSbox[46]
Xtime2Sbox[46] = _Xtime2Sbox[46]
Xtime3Sbox[46] = _Xtime3Sbox[46]
Xtime2[46] = _Xtime2[46]
Xtime9[46] = _Xtime9[46]
XtimeB[46] = _XtimeB[46]
XtimeD[46] = _XtimeD[46]
XtimeE[46] = _XtimeE[46]
Sbox[47] = _Sbox[47]
InvSbox[47] = _InvSbox[47]
Xtime2Sbox[47] = _Xtime2Sbox[47]
Xtime3Sbox[47] = _Xtime3Sbox[47]
Xtime2[47] = _Xtime2[47]
Xtime9[47] = _Xtime9[47]
XtimeB[47] = _XtimeB[47]
XtimeD[47] = _XtimeD[47]
XtimeE[47] = _XtimeE[47]
Sbox[48] = _Sbox[48]
InvSbox[48] = _InvSbox[48]
Xtime2Sbox[48] = _Xtime2Sbox[48]
Xtime3Sbox[48] = _Xtime3Sbox[48]
Xtime2[48] = _Xtime2[48]
Xtime9[48] = _Xtime9[48]
XtimeB[48] = _XtimeB[48]
XtimeD[48] = _XtimeD[48]
XtimeE[48] = _XtimeE[48]
Sbox[49] = _Sbox[49]
InvSbox[49] = _InvSbox[49]
Xtime2Sbox[49] = _Xtime2Sbox[49]
Xtime3Sbox[49] = _Xtime3Sbox[49]
Xtime2[49] = _Xtime2[49]
Xtime9[49] = _Xtime9[49]
XtimeB[49] = _XtimeB[49]
XtimeD[49] = _XtimeD[49]
XtimeE[49] = _XtimeE[49]
Sbox[50] = _Sbox[50]
InvSbox[50] = _InvSbox[50]
Xtime2Sbox[50] = _Xtime2Sbox[50]
Xtime3Sbox[50] = _Xtime3Sbox[50]
Xtime2[50] = _Xtime2[50]
Xtime9[50] = _Xtime9[50]
XtimeB[50] = _XtimeB[50]
XtimeD[50] = _XtimeD[50]
XtimeE[50] = _XtimeE[50]
Sbox[51] = _Sbox[51]
InvSbox[51] = _InvSbox[51]
Xtime2Sbox[51] = _Xtime2Sbox[51]
Xtime3Sbox[51] = _Xtime3Sbox[51]
Xtime2[51] = _Xtime2[51]
Xtime9[51] = _Xtime9[51]
XtimeB[51] = _XtimeB[51]
XtimeD[51] = _XtimeD[51]
XtimeE[51] = _XtimeE[51]
Sbox[52] = _Sbox[52]
InvSbox[52] = _InvSbox[52]
Xtime2Sbox[52] = _Xtime2Sbox[52]
Xtime3Sbox[52] = _Xtime3Sbox[52]
Xtime2[52] = _Xtime2[52]
Xtime9[52] = _Xtime9[52]
XtimeB[52] = _XtimeB[52]
XtimeD[52] = _XtimeD[52]
XtimeE[52] = _XtimeE[52]
Sbox[53] = _Sbox[53]
InvSbox[53] = _InvSbox[53]
Xtime2Sbox[53] = _Xtime2Sbox[53]
Xtime3Sbox[53] = _Xtime3Sbox[53]
Xtime2[53] = _Xtime2[53]
Xtime9[53] = _Xtime9[53]
XtimeB[53] = _XtimeB[53]
XtimeD[53] = _XtimeD[53]
XtimeE[53] = _XtimeE[53]
Sbox[54] = _Sbox[54]
InvSbox[54] = _InvSbox[54]
Xtime2Sbox[54] = _Xtime2Sbox[54]
Xtime3Sbox[54] = _Xtime3Sbox[54]
Xtime2[54] = _Xtime2[54]
Xtime9[54] = _Xtime9[54]
XtimeB[54] = _XtimeB[54]
XtimeD[54] = _XtimeD[54]
XtimeE[54] = _XtimeE[54]
Sbox[55] = _Sbox[55]
InvSbox[55] = _InvSbox[55]
Xtime2Sbox[55] = _Xtime2Sbox[55]
Xtime3Sbox[55] = _Xtime3Sbox[55]
Xtime2[55] = _Xtime2[55]
Xtime9[55] = _Xtime9[55]
XtimeB[55] = _XtimeB[55]
XtimeD[55] = _XtimeD[55]
XtimeE[55] = _XtimeE[55]
Sbox[56] = _Sbox[56]
InvSbox[56] = _InvSbox[56]
Xtime2Sbox[56] = _Xtime2Sbox[56]
Xtime3Sbox[56] = _Xtime3Sbox[56]
Xtime2[56] = _Xtime2[56]
Xtime9[56] = _Xtime9[56]
XtimeB[56] = _XtimeB[56]
XtimeD[56] = _XtimeD[56]
XtimeE[56] = _XtimeE[56]
Sbox[57] = _Sbox[57]
InvSbox[57] = _InvSbox[57]
Xtime2Sbox[57] = _Xtime2Sbox[57]
Xtime3Sbox[57] = _Xtime3Sbox[57]
Xtime2[57] = _Xtime2[57]
Xtime9[57] = _Xtime9[57]
XtimeB[57] = _XtimeB[57]
XtimeD[57] = _XtimeD[57]
XtimeE[57] = _XtimeE[57]
Sbox[58] = _Sbox[58]
InvSbox[58] = _InvSbox[58]
Xtime2Sbox[58] = _Xtime2Sbox[58]
Xtime3Sbox[58] = _Xtime3Sbox[58]
Xtime2[58] = _Xtime2[58]
Xtime9[58] = _Xtime9[58]
XtimeB[58] = _XtimeB[58]
XtimeD[58] = _XtimeD[58]
XtimeE[58] = _XtimeE[58]
Sbox[59] = _Sbox[59]
InvSbox[59] = _InvSbox[59]
Xtime2Sbox[59] = _Xtime2Sbox[59]
Xtime3Sbox[59] = _Xtime3Sbox[59]
Xtime2[59] = _Xtime2[59]
Xtime9[59] = _Xtime9[59]
XtimeB[59] = _XtimeB[59]
XtimeD[59] = _XtimeD[59]
XtimeE[59] = _XtimeE[59]
Sbox[60] = _Sbox[60]
InvSbox[60] = _InvSbox[60]
Xtime2Sbox[60] = _Xtime2Sbox[60]
Xtime3Sbox[60] = _Xtime3Sbox[60]
Xtime2[60] = _Xtime2[60]
Xtime9[60] = _Xtime9[60]
XtimeB[60] = _XtimeB[60]
XtimeD[60] = _XtimeD[60]
XtimeE[60] = _XtimeE[60]
Sbox[61] = _Sbox[61]
InvSbox[61] = _InvSbox[61]
Xtime2Sbox[61] = _Xtime2Sbox[61]
Xtime3Sbox[61] = _Xtime3Sbox[61]
Xtime2[61] = _Xtime2[61]
Xtime9[61] = _Xtime9[61]
XtimeB[61] = _XtimeB[61]
XtimeD[61] = _XtimeD[61]
XtimeE[61] = _XtimeE[61]
Sbox[62] = _Sbox[62]
InvSbox[62] = _InvSbox[62]
Xtime2Sbox[62] = _Xtime2Sbox[62]
Xtime3Sbox[62] = _Xtime3Sbox[62]
Xtime2[62] = _Xtime2[62]
Xtime9[62] = _Xtime9[62]
XtimeB[62] = _XtimeB[62]
XtimeD[62] = _XtimeD[62]
XtimeE[62] = _XtimeE[62]
Sbox[63] = _Sbox[63]
InvSbox[63] = _InvSbox[63]
Xtime2Sbox[63] = _Xtime2Sbox[63]
Xtime3Sbox[63] = _Xtime3Sbox[63]
Xtime2[63] = _Xtime2[63]
Xtime9[63] = _Xtime9[63]
XtimeB[63] = _XtimeB[63]
XtimeD[63] = _XtimeD[63]
XtimeE[63] = _XtimeE[63]
Sbox[64] = _Sbox[64]
InvSbox[64] = _InvSbox[64]
Xtime2Sbox[64] = _Xtime2Sbox[64]
Xtime3Sbox[64] = _Xtime3Sbox[64]
Xtime2[64] = _Xtime2[64]
Xtime9[64] = _Xtime9[64]
XtimeB[64] = _XtimeB[64]
XtimeD[64] = _XtimeD[64]
XtimeE[64] = _XtimeE[64]
Sbox[65] = _Sbox[65]
InvSbox[65] = _InvSbox[65]
Xtime2Sbox[65] = _Xtime2Sbox[65]
Xtime3Sbox[65] = _Xtime3Sbox[65]
Xtime2[65] = _Xtime2[65]
Xtime9[65] = _Xtime9[65]
XtimeB[65] = _XtimeB[65]
XtimeD[65] = _XtimeD[65]
XtimeE[65] = _XtimeE[65]
Sbox[66] = _Sbox[66]
InvSbox[66] = _InvSbox[66]
Xtime2Sbox[66] = _Xtime2Sbox[66]
Xtime3Sbox[66] = _Xtime3Sbox[66]
Xtime2[66] = _Xtime2[66]
Xtime9[66] = _Xtime9[66]
XtimeB[66] = _XtimeB[66]
XtimeD[66] = _XtimeD[66]
XtimeE[66] = _XtimeE[66]
Sbox[67] = _Sbox[67]
InvSbox[67] = _InvSbox[67]
Xtime2Sbox[67] = _Xtime2Sbox[67]
Xtime3Sbox[67] = _Xtime3Sbox[67]
Xtime2[67] = _Xtime2[67]
Xtime9[67] = _Xtime9[67]
XtimeB[67] = _XtimeB[67]
XtimeD[67] = _XtimeD[67]
XtimeE[67] = _XtimeE[67]
Sbox[68] = _Sbox[68]
InvSbox[68] = _InvSbox[68]
Xtime2Sbox[68] = _Xtime2Sbox[68]
Xtime3Sbox[68] = _Xtime3Sbox[68]
Xtime2[68] = _Xtime2[68]
Xtime9[68] = _Xtime9[68]
XtimeB[68] = _XtimeB[68]
XtimeD[68] = _XtimeD[68]
XtimeE[68] = _XtimeE[68]
Sbox[69] = _Sbox[69]
InvSbox[69] = _InvSbox[69]
Xtime2Sbox[69] = _Xtime2Sbox[69]
Xtime3Sbox[69] = _Xtime3Sbox[69]
Xtime2[69] = _Xtime2[69]
Xtime9[69] = _Xtime9[69]
XtimeB[69] = _XtimeB[69]
XtimeD[69] = _XtimeD[69]
XtimeE[69] = _XtimeE[69]
Sbox[70] = _Sbox[70]
InvSbox[70] = _InvSbox[70]
Xtime2Sbox[70] = _Xtime2Sbox[70]
Xtime3Sbox[70] = _Xtime3Sbox[70]
Xtime2[70] = _Xtime2[70]
Xtime9[70] = _Xtime9[70]
XtimeB[70] = _XtimeB[70]
XtimeD[70] = _XtimeD[70]
XtimeE[70] = _XtimeE[70]
Sbox[71] = _Sbox[71]
InvSbox[71] = _InvSbox[71]
Xtime2Sbox[71] = _Xtime2Sbox[71]
Xtime3Sbox[71] = _Xtime3Sbox[71]
Xtime2[71] = _Xtime2[71]
Xtime9[71] = _Xtime9[71]
XtimeB[71] = _XtimeB[71]
XtimeD[71] = _XtimeD[71]
XtimeE[71] = _XtimeE[71]
Sbox[72] = _Sbox[72]
InvSbox[72] = _InvSbox[72]
Xtime2Sbox[72] = _Xtime2Sbox[72]
Xtime3Sbox[72] = _Xtime3Sbox[72]
Xtime2[72] = _Xtime2[72]
Xtime9[72] = _Xtime9[72]
XtimeB[72] = _XtimeB[72]
XtimeD[72] = _XtimeD[72]
XtimeE[72] = _XtimeE[72]
Sbox[73] = _Sbox[73]
InvSbox[73] = _InvSbox[73]
Xtime2Sbox[73] = _Xtime2Sbox[73]
Xtime3Sbox[73] = _Xtime3Sbox[73]
Xtime2[73] = _Xtime2[73]
Xtime9[73] = _Xtime9[73]
XtimeB[73] = _XtimeB[73]
XtimeD[73] = _XtimeD[73]
XtimeE[73] = _XtimeE[73]
Sbox[74] = _Sbox[74]
InvSbox[74] = _InvSbox[74]
Xtime2Sbox[74] = _Xtime2Sbox[74]
Xtime3Sbox[74] = _Xtime3Sbox[74]
Xtime2[74] = _Xtime2[74]
Xtime9[74] = _Xtime9[74]
XtimeB[74] = _XtimeB[74]
XtimeD[74] = _XtimeD[74]
XtimeE[74] = _XtimeE[74]
Sbox[75] = _Sbox[75]
InvSbox[75] = _InvSbox[75]
Xtime2Sbox[75] = _Xtime2Sbox[75]
Xtime3Sbox[75] = _Xtime3Sbox[75]
Xtime2[75] = _Xtime2[75]
Xtime9[75] = _Xtime9[75]
XtimeB[75] = _XtimeB[75]
XtimeD[75] = _XtimeD[75]
XtimeE[75] = _XtimeE[75]
Sbox[76] = _Sbox[76]
InvSbox[76] = _InvSbox[76]
Xtime2Sbox[76] = _Xtime2Sbox[76]
Xtime3Sbox[76] = _Xtime3Sbox[76]
Xtime2[76] = _Xtime2[76]
Xtime9[76] = _Xtime9[76]
XtimeB[76] = _XtimeB[76]
XtimeD[76] = _XtimeD[76]
XtimeE[76] = _XtimeE[76]
Sbox[77] = _Sbox[77]
InvSbox[77] = _InvSbox[77]
Xtime2Sbox[77] = _Xtime2Sbox[77]
Xtime3Sbox[77] = _Xtime3Sbox[77]
Xtime2[77] = _Xtime2[77]
Xtime9[77] = _Xtime9[77]
XtimeB[77] = _XtimeB[77]
XtimeD[77] = _XtimeD[77]
XtimeE[77] = _XtimeE[77]
Sbox[78] = _Sbox[78]
InvSbox[78] = _InvSbox[78]
Xtime2Sbox[78] = _Xtime2Sbox[78]
Xtime3Sbox[78] = _Xtime3Sbox[78]
Xtime2[78] = _Xtime2[78]
Xtime9[78] = _Xtime9[78]
XtimeB[78] = _XtimeB[78]
XtimeD[78] = _XtimeD[78]
XtimeE[78] = _XtimeE[78]
Sbox[79] = _Sbox[79]
InvSbox[79] = _InvSbox[79]
Xtime2Sbox[79] = _Xtime2Sbox[79]
Xtime3Sbox[79] = _Xtime3Sbox[79]
Xtime2[79] = _Xtime2[79]
Xtime9[79] = _Xtime9[79]
XtimeB[79] = _XtimeB[79]
XtimeD[79] = _XtimeD[79]
XtimeE[79] = _XtimeE[79]
Sbox[80] = _Sbox[80]
InvSbox[80] = _InvSbox[80]
Xtime2Sbox[80] = _Xtime2Sbox[80]
Xtime3Sbox[80] = _Xtime3Sbox[80]
Xtime2[80] = _Xtime2[80]
Xtime9[80] = _Xtime9[80]
XtimeB[80] = _XtimeB[80]
XtimeD[80] = _XtimeD[80]
XtimeE[80] = _XtimeE[80]
Sbox[81] = _Sbox[81]
InvSbox[81] = _InvSbox[81]
Xtime2Sbox[81] = _Xtime2Sbox[81]
Xtime3Sbox[81] = _Xtime3Sbox[81]
Xtime2[81] = _Xtime2[81]
Xtime9[81] = _Xtime9[81]
XtimeB[81] = _XtimeB[81]
XtimeD[81] = _XtimeD[81]
XtimeE[81] = _XtimeE[81]
Sbox[82] = _Sbox[82]
InvSbox[82] = _InvSbox[82]
Xtime2Sbox[82] = _Xtime2Sbox[82]
Xtime3Sbox[82] = _Xtime3Sbox[82]
Xtime2[82] = _Xtime2[82]
Xtime9[82] = _Xtime9[82]
XtimeB[82] = _XtimeB[82]
XtimeD[82] = _XtimeD[82]
XtimeE[82] = _XtimeE[82]
Sbox[83] = _Sbox[83]
InvSbox[83] = _InvSbox[83]
Xtime2Sbox[83] = _Xtime2Sbox[83]
Xtime3Sbox[83] = _Xtime3Sbox[83]
Xtime2[83] = _Xtime2[83]
Xtime9[83] = _Xtime9[83]
XtimeB[83] = _XtimeB[83]
XtimeD[83] = _XtimeD[83]
XtimeE[83] = _XtimeE[83]
Sbox[84] = _Sbox[84]
InvSbox[84] = _InvSbox[84]
Xtime2Sbox[84] = _Xtime2Sbox[84]
Xtime3Sbox[84] = _Xtime3Sbox[84]
Xtime2[84] = _Xtime2[84]
Xtime9[84] = _Xtime9[84]
XtimeB[84] = _XtimeB[84]
XtimeD[84] = _XtimeD[84]
XtimeE[84] = _XtimeE[84]
Sbox[85] = _Sbox[85]
InvSbox[85] = _InvSbox[85]
Xtime2Sbox[85] = _Xtime2Sbox[85]
Xtime3Sbox[85] = _Xtime3Sbox[85]
Xtime2[85] = _Xtime2[85]
Xtime9[85] = _Xtime9[85]
XtimeB[85] = _XtimeB[85]
XtimeD[85] = _XtimeD[85]
XtimeE[85] = _XtimeE[85]
Sbox[86] = _Sbox[86]
InvSbox[86] = _InvSbox[86]
Xtime2Sbox[86] = _Xtime2Sbox[86]
Xtime3Sbox[86] = _Xtime3Sbox[86]
Xtime2[86] = _Xtime2[86]
Xtime9[86] = _Xtime9[86]
XtimeB[86] = _XtimeB[86]
XtimeD[86] = _XtimeD[86]
XtimeE[86] = _XtimeE[86]
Sbox[87] = _Sbox[87]
InvSbox[87] = _InvSbox[87]
Xtime2Sbox[87] = _Xtime2Sbox[87]
Xtime3Sbox[87] = _Xtime3Sbox[87]
Xtime2[87] = _Xtime2[87]
Xtime9[87] = _Xtime9[87]
XtimeB[87] = _XtimeB[87]
XtimeD[87] = _XtimeD[87]
XtimeE[87] = _XtimeE[87]
Sbox[88] = _Sbox[88]
InvSbox[88] = _InvSbox[88]
Xtime2Sbox[88] = _Xtime2Sbox[88]
Xtime3Sbox[88] = _Xtime3Sbox[88]
Xtime2[88] = _Xtime2[88]
Xtime9[88] = _Xtime9[88]
XtimeB[88] = _XtimeB[88]
XtimeD[88] = _XtimeD[88]
XtimeE[88] = _XtimeE[88]
Sbox[89] = _Sbox[89]
InvSbox[89] = _InvSbox[89]
Xtime2Sbox[89] = _Xtime2Sbox[89]
Xtime3Sbox[89] = _Xtime3Sbox[89]
Xtime2[89] = _Xtime2[89]
Xtime9[89] = _Xtime9[89]
XtimeB[89] = _XtimeB[89]
XtimeD[89] = _XtimeD[89]
XtimeE[89] = _XtimeE[89]
Sbox[90] = _Sbox[90]
InvSbox[90] = _InvSbox[90]
Xtime2Sbox[90] = _Xtime2Sbox[90]
Xtime3Sbox[90] = _Xtime3Sbox[90]
Xtime2[90] = _Xtime2[90]
Xtime9[90] = _Xtime9[90]
XtimeB[90] = _XtimeB[90]
XtimeD[90] = _XtimeD[90]
XtimeE[90] = _XtimeE[90]
Sbox[91] = _Sbox[91]
InvSbox[91] = _InvSbox[91]
Xtime2Sbox[91] = _Xtime2Sbox[91]
Xtime3Sbox[91] = _Xtime3Sbox[91]
Xtime2[91] = _Xtime2[91]
Xtime9[91] = _Xtime9[91]
XtimeB[91] = _XtimeB[91]
XtimeD[91] = _XtimeD[91]
XtimeE[91] = _XtimeE[91]
Sbox[92] = _Sbox[92]
InvSbox[92] = _InvSbox[92]
Xtime2Sbox[92] = _Xtime2Sbox[92]
Xtime3Sbox[92] = _Xtime3Sbox[92]
Xtime2[92] = _Xtime2[92]
Xtime9[92] = _Xtime9[92]
XtimeB[92] = _XtimeB[92]
XtimeD[92] = _XtimeD[92]
XtimeE[92] = _XtimeE[92]
Sbox[93] = _Sbox[93]
InvSbox[93] = _InvSbox[93]
Xtime2Sbox[93] = _Xtime2Sbox[93]
Xtime3Sbox[93] = _Xtime3Sbox[93]
Xtime2[93] = _Xtime2[93]
Xtime9[93] = _Xtime9[93]
XtimeB[93] = _XtimeB[93]
XtimeD[93] = _XtimeD[93]
XtimeE[93] = _XtimeE[93]
Sbox[94] = _Sbox[94]
InvSbox[94] = _InvSbox[94]
Xtime2Sbox[94] = _Xtime2Sbox[94]
Xtime3Sbox[94] = _Xtime3Sbox[94]
Xtime2[94] = _Xtime2[94]
Xtime9[94] = _Xtime9[94]
XtimeB[94] = _XtimeB[94]
XtimeD[94] = _XtimeD[94]
XtimeE[94] = _XtimeE[94]
Sbox[95] = _Sbox[95]
InvSbox[95] = _InvSbox[95]
Xtime2Sbox[95] = _Xtime2Sbox[95]
Xtime3Sbox[95] = _Xtime3Sbox[95]
Xtime2[95] = _Xtime2[95]
Xtime9[95] = _Xtime9[95]
XtimeB[95] = _XtimeB[95]
XtimeD[95] = _XtimeD[95]
XtimeE[95] = _XtimeE[95]
Sbox[96] = _Sbox[96]
InvSbox[96] = _InvSbox[96]
Xtime2Sbox[96] = _Xtime2Sbox[96]
Xtime3Sbox[96] = _Xtime3Sbox[96]
Xtime2[96] = _Xtime2[96]
Xtime9[96] = _Xtime9[96]
XtimeB[96] = _XtimeB[96]
XtimeD[96] = _XtimeD[96]
XtimeE[96] = _XtimeE[96]
Sbox[97] = _Sbox[97]
InvSbox[97] = _InvSbox[97]
Xtime2Sbox[97] = _Xtime2Sbox[97]
Xtime3Sbox[97] = _Xtime3Sbox[97]
Xtime2[97] = _Xtime2[97]
Xtime9[97] = _Xtime9[97]
XtimeB[97] = _XtimeB[97]
XtimeD[97] = _XtimeD[97]
XtimeE[97] = _XtimeE[97]
Sbox[98] = _Sbox[98]
InvSbox[98] = _InvSbox[98]
Xtime2Sbox[98] = _Xtime2Sbox[98]
Xtime3Sbox[98] = _Xtime3Sbox[98]
Xtime2[98] = _Xtime2[98]
Xtime9[98] = _Xtime9[98]
XtimeB[98] = _XtimeB[98]
XtimeD[98] = _XtimeD[98]
XtimeE[98] = _XtimeE[98]
Sbox[99] = _Sbox[99]
InvSbox[99] = _InvSbox[99]
Xtime2Sbox[99] = _Xtime2Sbox[99]
Xtime3Sbox[99] = _Xtime3Sbox[99]
Xtime2[99] = _Xtime2[99]
Xtime9[99] = _Xtime9[99]
XtimeB[99] = _XtimeB[99]
XtimeD[99] = _XtimeD[99]
XtimeE[99] = _XtimeE[99]
Sbox[100] = _Sbox[100]
InvSbox[100] = _InvSbox[100]
Xtime2Sbox[100] = _Xtime2Sbox[100]
Xtime3Sbox[100] = _Xtime3Sbox[100]
Xtime2[100] = _Xtime2[100]
Xtime9[100] = _Xtime9[100]
XtimeB[100] = _XtimeB[100]
XtimeD[100] = _XtimeD[100]
XtimeE[100] = _XtimeE[100]
Sbox[101] = _Sbox[101]
InvSbox[101] = _InvSbox[101]
Xtime2Sbox[101] = _Xtime2Sbox[101]
Xtime3Sbox[101] = _Xtime3Sbox[101]
Xtime2[101] = _Xtime2[101]
Xtime9[101] = _Xtime9[101]
XtimeB[101] = _XtimeB[101]
XtimeD[101] = _XtimeD[101]
XtimeE[101] = _XtimeE[101]
Sbox[102] = _Sbox[102]
InvSbox[102] = _InvSbox[102]
Xtime2Sbox[102] = _Xtime2Sbox[102]
Xtime3Sbox[102] = _Xtime3Sbox[102]
Xtime2[102] = _Xtime2[102]
Xtime9[102] = _Xtime9[102]
XtimeB[102] = _XtimeB[102]
XtimeD[102] = _XtimeD[102]
XtimeE[102] = _XtimeE[102]
Sbox[103] = _Sbox[103]
InvSbox[103] = _InvSbox[103]
Xtime2Sbox[103] = _Xtime2Sbox[103]
Xtime3Sbox[103] = _Xtime3Sbox[103]
Xtime2[103] = _Xtime2[103]
Xtime9[103] = _Xtime9[103]
XtimeB[103] = _XtimeB[103]
XtimeD[103] = _XtimeD[103]
XtimeE[103] = _XtimeE[103]
Sbox[104] = _Sbox[104]
InvSbox[104] = _InvSbox[104]
Xtime2Sbox[104] = _Xtime2Sbox[104]
Xtime3Sbox[104] = _Xtime3Sbox[104]
Xtime2[104] = _Xtime2[104]
Xtime9[104] = _Xtime9[104]
XtimeB[104] = _XtimeB[104]
XtimeD[104] = _XtimeD[104]
XtimeE[104] = _XtimeE[104]
Sbox[105] = _Sbox[105]
InvSbox[105] = _InvSbox[105]
Xtime2Sbox[105] = _Xtime2Sbox[105]
Xtime3Sbox[105] = _Xtime3Sbox[105]
Xtime2[105] = _Xtime2[105]
Xtime9[105] = _Xtime9[105]
XtimeB[105] = _XtimeB[105]
XtimeD[105] = _XtimeD[105]
XtimeE[105] = _XtimeE[105]
Sbox[106] = _Sbox[106]
InvSbox[106] = _InvSbox[106]
Xtime2Sbox[106] = _Xtime2Sbox[106]
Xtime3Sbox[106] = _Xtime3Sbox[106]
Xtime2[106] = _Xtime2[106]
Xtime9[106] = _Xtime9[106]
XtimeB[106] = _XtimeB[106]
XtimeD[106] = _XtimeD[106]
XtimeE[106] = _XtimeE[106]
Sbox[107] = _Sbox[107]
InvSbox[107] = _InvSbox[107]
Xtime2Sbox[107] = _Xtime2Sbox[107]
Xtime3Sbox[107] = _Xtime3Sbox[107]
Xtime2[107] = _Xtime2[107]
Xtime9[107] = _Xtime9[107]
XtimeB[107] = _XtimeB[107]
XtimeD[107] = _XtimeD[107]
XtimeE[107] = _XtimeE[107]
Sbox[108] = _Sbox[108]
InvSbox[108] = _InvSbox[108]
Xtime2Sbox[108] = _Xtime2Sbox[108]
Xtime3Sbox[108] = _Xtime3Sbox[108]
Xtime2[108] = _Xtime2[108]
Xtime9[108] = _Xtime9[108]
XtimeB[108] = _XtimeB[108]
XtimeD[108] = _XtimeD[108]
XtimeE[108] = _XtimeE[108]
Sbox[109] = _Sbox[109]
InvSbox[109] = _InvSbox[109]
Xtime2Sbox[109] = _Xtime2Sbox[109]
Xtime3Sbox[109] = _Xtime3Sbox[109]
Xtime2[109] = _Xtime2[109]
Xtime9[109] = _Xtime9[109]
XtimeB[109] = _XtimeB[109]
XtimeD[109] = _XtimeD[109]
XtimeE[109] = _XtimeE[109]
Sbox[110] = _Sbox[110]
InvSbox[110] = _InvSbox[110]
Xtime2Sbox[110] = _Xtime2Sbox[110]
Xtime3Sbox[110] = _Xtime3Sbox[110]
Xtime2[110] = _Xtime2[110]
Xtime9[110] = _Xtime9[110]
XtimeB[110] = _XtimeB[110]
XtimeD[110] = _XtimeD[110]
XtimeE[110] = _XtimeE[110]
Sbox[111] = _Sbox[111]
InvSbox[111] = _InvSbox[111]
Xtime2Sbox[111] = _Xtime2Sbox[111]
Xtime3Sbox[111] = _Xtime3Sbox[111]
Xtime2[111] = _Xtime2[111]
Xtime9[111] = _Xtime9[111]
XtimeB[111] = _XtimeB[111]
XtimeD[111] = _XtimeD[111]
XtimeE[111] = _XtimeE[111]
Sbox[112] = _Sbox[112]
InvSbox[112] = _InvSbox[112]
Xtime2Sbox[112] = _Xtime2Sbox[112]
Xtime3Sbox[112] = _Xtime3Sbox[112]
Xtime2[112] = _Xtime2[112]
Xtime9[112] = _Xtime9[112]
XtimeB[112] = _XtimeB[112]
XtimeD[112] = _XtimeD[112]
XtimeE[112] = _XtimeE[112]
Sbox[113] = _Sbox[113]
InvSbox[113] = _InvSbox[113]
Xtime2Sbox[113] = _Xtime2Sbox[113]
Xtime3Sbox[113] = _Xtime3Sbox[113]
Xtime2[113] = _Xtime2[113]
Xtime9[113] = _Xtime9[113]
XtimeB[113] = _XtimeB[113]
XtimeD[113] = _XtimeD[113]
XtimeE[113] = _XtimeE[113]
Sbox[114] = _Sbox[114]
InvSbox[114] = _InvSbox[114]
Xtime2Sbox[114] = _Xtime2Sbox[114]
Xtime3Sbox[114] = _Xtime3Sbox[114]
Xtime2[114] = _Xtime2[114]
Xtime9[114] = _Xtime9[114]
XtimeB[114] = _XtimeB[114]
XtimeD[114] = _XtimeD[114]
XtimeE[114] = _XtimeE[114]
Sbox[115] = _Sbox[115]
InvSbox[115] = _InvSbox[115]
Xtime2Sbox[115] = _Xtime2Sbox[115]
Xtime3Sbox[115] = _Xtime3Sbox[115]
Xtime2[115] = _Xtime2[115]
Xtime9[115] = _Xtime9[115]
XtimeB[115] = _XtimeB[115]
XtimeD[115] = _XtimeD[115]
XtimeE[115] = _XtimeE[115]
Sbox[116] = _Sbox[116]
InvSbox[116] = _InvSbox[116]
Xtime2Sbox[116] = _Xtime2Sbox[116]
Xtime3Sbox[116] = _Xtime3Sbox[116]
Xtime2[116] = _Xtime2[116]
Xtime9[116] = _Xtime9[116]
XtimeB[116] = _XtimeB[116]
XtimeD[116] = _XtimeD[116]
XtimeE[116] = _XtimeE[116]
Sbox[117] = _Sbox[117]
InvSbox[117] = _InvSbox[117]
Xtime2Sbox[117] = _Xtime2Sbox[117]
Xtime3Sbox[117] = _Xtime3Sbox[117]
Xtime2[117] = _Xtime2[117]
Xtime9[117] = _Xtime9[117]
XtimeB[117] = _XtimeB[117]
XtimeD[117] = _XtimeD[117]
XtimeE[117] = _XtimeE[117]
Sbox[118] = _Sbox[118]
InvSbox[118] = _InvSbox[118]
Xtime2Sbox[118] = _Xtime2Sbox[118]
Xtime3Sbox[118] = _Xtime3Sbox[118]
Xtime2[118] = _Xtime2[118]
Xtime9[118] = _Xtime9[118]
XtimeB[118] = _XtimeB[118]
XtimeD[118] = _XtimeD[118]
XtimeE[118] = _XtimeE[118]
Sbox[119] = _Sbox[119]
InvSbox[119] = _InvSbox[119]
Xtime2Sbox[119] = _Xtime2Sbox[119]
Xtime3Sbox[119] = _Xtime3Sbox[119]
Xtime2[119] = _Xtime2[119]
Xtime9[119] = _Xtime9[119]
XtimeB[119] = _XtimeB[119]
XtimeD[119] = _XtimeD[119]
XtimeE[119] = _XtimeE[119]
Sbox[120] = _Sbox[120]
InvSbox[120] = _InvSbox[120]
Xtime2Sbox[120] = _Xtime2Sbox[120]
Xtime3Sbox[120] = _Xtime3Sbox[120]
Xtime2[120] = _Xtime2[120]
Xtime9[120] = _Xtime9[120]
XtimeB[120] = _XtimeB[120]
XtimeD[120] = _XtimeD[120]
XtimeE[120] = _XtimeE[120]
Sbox[121] = _Sbox[121]
InvSbox[121] = _InvSbox[121]
Xtime2Sbox[121] = _Xtime2Sbox[121]
Xtime3Sbox[121] = _Xtime3Sbox[121]
Xtime2[121] = _Xtime2[121]
Xtime9[121] = _Xtime9[121]
XtimeB[121] = _XtimeB[121]
XtimeD[121] = _XtimeD[121]
XtimeE[121] = _XtimeE[121]
Sbox[122] = _Sbox[122]
InvSbox[122] = _InvSbox[122]
Xtime2Sbox[122] = _Xtime2Sbox[122]
Xtime3Sbox[122] = _Xtime3Sbox[122]
Xtime2[122] = _Xtime2[122]
Xtime9[122] = _Xtime9[122]
XtimeB[122] = _XtimeB[122]
XtimeD[122] = _XtimeD[122]
XtimeE[122] = _XtimeE[122]
Sbox[123] = _Sbox[123]
InvSbox[123] = _InvSbox[123]
Xtime2Sbox[123] = _Xtime2Sbox[123]
Xtime3Sbox[123] = _Xtime3Sbox[123]
Xtime2[123] = _Xtime2[123]
Xtime9[123] = _Xtime9[123]
XtimeB[123] = _XtimeB[123]
XtimeD[123] = _XtimeD[123]
XtimeE[123] = _XtimeE[123]
Sbox[124] = _Sbox[124]
InvSbox[124] = _InvSbox[124]
Xtime2Sbox[124] = _Xtime2Sbox[124]
Xtime3Sbox[124] = _Xtime3Sbox[124]
Xtime2[124] = _Xtime2[124]
Xtime9[124] = _Xtime9[124]
XtimeB[124] = _XtimeB[124]
XtimeD[124] = _XtimeD[124]
XtimeE[124] = _XtimeE[124]
Sbox[125] = _Sbox[125]
InvSbox[125] = _InvSbox[125]
Xtime2Sbox[125] = _Xtime2Sbox[125]
Xtime3Sbox[125] = _Xtime3Sbox[125]
Xtime2[125] = _Xtime2[125]
Xtime9[125] = _Xtime9[125]
XtimeB[125] = _XtimeB[125]
XtimeD[125] = _XtimeD[125]
XtimeE[125] = _XtimeE[125]
Sbox[126] = _Sbox[126]
InvSbox[126] = _InvSbox[126]
Xtime2Sbox[126] = _Xtime2Sbox[126]
Xtime3Sbox[126] = _Xtime3Sbox[126]
Xtime2[126] = _Xtime2[126]
Xtime9[126] = _Xtime9[126]
XtimeB[126] = _XtimeB[126]
XtimeD[126] = _XtimeD[126]
XtimeE[126] = _XtimeE[126]
Sbox[127] = _Sbox[127]
InvSbox[127] = _InvSbox[127]
Xtime2Sbox[127] = _Xtime2Sbox[127]
Xtime3Sbox[127] = _Xtime3Sbox[127]
Xtime2[127] = _Xtime2[127]
Xtime9[127] = _Xtime9[127]
XtimeB[127] = _XtimeB[127]
XtimeD[127] = _XtimeD[127]
XtimeE[127] = _XtimeE[127]
Sbox[128] = _Sbox[128]
InvSbox[128] = _InvSbox[128]
Xtime2Sbox[128] = _Xtime2Sbox[128]
Xtime3Sbox[128] = _Xtime3Sbox[128]
Xtime2[128] = _Xtime2[128]
Xtime9[128] = _Xtime9[128]
XtimeB[128] = _XtimeB[128]
XtimeD[128] = _XtimeD[128]
XtimeE[128] = _XtimeE[128]
Sbox[129] = _Sbox[129]
InvSbox[129] = _InvSbox[129]
Xtime2Sbox[129] = _Xtime2Sbox[129]
Xtime3Sbox[129] = _Xtime3Sbox[129]
Xtime2[129] = _Xtime2[129]
Xtime9[129] = _Xtime9[129]
XtimeB[129] = _XtimeB[129]
XtimeD[129] = _XtimeD[129]
XtimeE[129] = _XtimeE[129]
Sbox[130] = _Sbox[130]
InvSbox[130] = _InvSbox[130]
Xtime2Sbox[130] = _Xtime2Sbox[130]
Xtime3Sbox[130] = _Xtime3Sbox[130]
Xtime2[130] = _Xtime2[130]
Xtime9[130] = _Xtime9[130]
XtimeB[130] = _XtimeB[130]
XtimeD[130] = _XtimeD[130]
XtimeE[130] = _XtimeE[130]
Sbox[131] = _Sbox[131]
InvSbox[131] = _InvSbox[131]
Xtime2Sbox[131] = _Xtime2Sbox[131]
Xtime3Sbox[131] = _Xtime3Sbox[131]
Xtime2[131] = _Xtime2[131]
Xtime9[131] = _Xtime9[131]
XtimeB[131] = _XtimeB[131]
XtimeD[131] = _XtimeD[131]
XtimeE[131] = _XtimeE[131]
Sbox[132] = _Sbox[132]
InvSbox[132] = _InvSbox[132]
Xtime2Sbox[132] = _Xtime2Sbox[132]
Xtime3Sbox[132] = _Xtime3Sbox[132]
Xtime2[132] = _Xtime2[132]
Xtime9[132] = _Xtime9[132]
XtimeB[132] = _XtimeB[132]
XtimeD[132] = _XtimeD[132]
XtimeE[132] = _XtimeE[132]
Sbox[133] = _Sbox[133]
InvSbox[133] = _InvSbox[133]
Xtime2Sbox[133] = _Xtime2Sbox[133]
Xtime3Sbox[133] = _Xtime3Sbox[133]
Xtime2[133] = _Xtime2[133]
Xtime9[133] = _Xtime9[133]
XtimeB[133] = _XtimeB[133]
XtimeD[133] = _XtimeD[133]
XtimeE[133] = _XtimeE[133]
Sbox[134] = _Sbox[134]
InvSbox[134] = _InvSbox[134]
Xtime2Sbox[134] = _Xtime2Sbox[134]
Xtime3Sbox[134] = _Xtime3Sbox[134]
Xtime2[134] = _Xtime2[134]
Xtime9[134] = _Xtime9[134]
XtimeB[134] = _XtimeB[134]
XtimeD[134] = _XtimeD[134]
XtimeE[134] = _XtimeE[134]
Sbox[135] = _Sbox[135]
InvSbox[135] = _InvSbox[135]
Xtime2Sbox[135] = _Xtime2Sbox[135]
Xtime3Sbox[135] = _Xtime3Sbox[135]
Xtime2[135] = _Xtime2[135]
Xtime9[135] = _Xtime9[135]
XtimeB[135] = _XtimeB[135]
XtimeD[135] = _XtimeD[135]
XtimeE[135] = _XtimeE[135]
Sbox[136] = _Sbox[136]
InvSbox[136] = _InvSbox[136]
Xtime2Sbox[136] = _Xtime2Sbox[136]
Xtime3Sbox[136] = _Xtime3Sbox[136]
Xtime2[136] = _Xtime2[136]
Xtime9[136] = _Xtime9[136]
XtimeB[136] = _XtimeB[136]
XtimeD[136] = _XtimeD[136]
XtimeE[136] = _XtimeE[136]
Sbox[137] = _Sbox[137]
InvSbox[137] = _InvSbox[137]
Xtime2Sbox[137] = _Xtime2Sbox[137]
Xtime3Sbox[137] = _Xtime3Sbox[137]
Xtime2[137] = _Xtime2[137]
Xtime9[137] = _Xtime9[137]
XtimeB[137] = _XtimeB[137]
XtimeD[137] = _XtimeD[137]
XtimeE[137] = _XtimeE[137]
Sbox[138] = _Sbox[138]
InvSbox[138] = _InvSbox[138]
Xtime2Sbox[138] = _Xtime2Sbox[138]
Xtime3Sbox[138] = _Xtime3Sbox[138]
Xtime2[138] = _Xtime2[138]
Xtime9[138] = _Xtime9[138]
XtimeB[138] = _XtimeB[138]
XtimeD[138] = _XtimeD[138]
XtimeE[138] = _XtimeE[138]
Sbox[139] = _Sbox[139]
InvSbox[139] = _InvSbox[139]
Xtime2Sbox[139] = _Xtime2Sbox[139]
Xtime3Sbox[139] = _Xtime3Sbox[139]
Xtime2[139] = _Xtime2[139]
Xtime9[139] = _Xtime9[139]
XtimeB[139] = _XtimeB[139]
XtimeD[139] = _XtimeD[139]
XtimeE[139] = _XtimeE[139]
Sbox[140] = _Sbox[140]
InvSbox[140] = _InvSbox[140]
Xtime2Sbox[140] = _Xtime2Sbox[140]
Xtime3Sbox[140] = _Xtime3Sbox[140]
Xtime2[140] = _Xtime2[140]
Xtime9[140] = _Xtime9[140]
XtimeB[140] = _XtimeB[140]
XtimeD[140] = _XtimeD[140]
XtimeE[140] = _XtimeE[140]
Sbox[141] = _Sbox[141]
InvSbox[141] = _InvSbox[141]
Xtime2Sbox[141] = _Xtime2Sbox[141]
Xtime3Sbox[141] = _Xtime3Sbox[141]
Xtime2[141] = _Xtime2[141]
Xtime9[141] = _Xtime9[141]
XtimeB[141] = _XtimeB[141]
XtimeD[141] = _XtimeD[141]
XtimeE[141] = _XtimeE[141]
Sbox[142] = _Sbox[142]
InvSbox[142] = _InvSbox[142]
Xtime2Sbox[142] = _Xtime2Sbox[142]
Xtime3Sbox[142] = _Xtime3Sbox[142]
Xtime2[142] = _Xtime2[142]
Xtime9[142] = _Xtime9[142]
XtimeB[142] = _XtimeB[142]
XtimeD[142] = _XtimeD[142]
XtimeE[142] = _XtimeE[142]
Sbox[143] = _Sbox[143]
InvSbox[143] = _InvSbox[143]
Xtime2Sbox[143] = _Xtime2Sbox[143]
Xtime3Sbox[143] = _Xtime3Sbox[143]
Xtime2[143] = _Xtime2[143]
Xtime9[143] = _Xtime9[143]
XtimeB[143] = _XtimeB[143]
XtimeD[143] = _XtimeD[143]
XtimeE[143] = _XtimeE[143]
Sbox[144] = _Sbox[144]
InvSbox[144] = _InvSbox[144]
Xtime2Sbox[144] = _Xtime2Sbox[144]
Xtime3Sbox[144] = _Xtime3Sbox[144]
Xtime2[144] = _Xtime2[144]
Xtime9[144] = _Xtime9[144]
XtimeB[144] = _XtimeB[144]
XtimeD[144] = _XtimeD[144]
XtimeE[144] = _XtimeE[144]
Sbox[145] = _Sbox[145]
InvSbox[145] = _InvSbox[145]
Xtime2Sbox[145] = _Xtime2Sbox[145]
Xtime3Sbox[145] = _Xtime3Sbox[145]
Xtime2[145] = _Xtime2[145]
Xtime9[145] = _Xtime9[145]
XtimeB[145] = _XtimeB[145]
XtimeD[145] = _XtimeD[145]
XtimeE[145] = _XtimeE[145]
Sbox[146] = _Sbox[146]
InvSbox[146] = _InvSbox[146]
Xtime2Sbox[146] = _Xtime2Sbox[146]
Xtime3Sbox[146] = _Xtime3Sbox[146]
Xtime2[146] = _Xtime2[146]
Xtime9[146] = _Xtime9[146]
XtimeB[146] = _XtimeB[146]
XtimeD[146] = _XtimeD[146]
XtimeE[146] = _XtimeE[146]
Sbox[147] = _Sbox[147]
InvSbox[147] = _InvSbox[147]
Xtime2Sbox[147] = _Xtime2Sbox[147]
Xtime3Sbox[147] = _Xtime3Sbox[147]
Xtime2[147] = _Xtime2[147]
Xtime9[147] = _Xtime9[147]
XtimeB[147] = _XtimeB[147]
XtimeD[147] = _XtimeD[147]
XtimeE[147] = _XtimeE[147]
Sbox[148] = _Sbox[148]
InvSbox[148] = _InvSbox[148]
Xtime2Sbox[148] = _Xtime2Sbox[148]
Xtime3Sbox[148] = _Xtime3Sbox[148]
Xtime2[148] = _Xtime2[148]
Xtime9[148] = _Xtime9[148]
XtimeB[148] = _XtimeB[148]
XtimeD[148] = _XtimeD[148]
XtimeE[148] = _XtimeE[148]
Sbox[149] = _Sbox[149]
InvSbox[149] = _InvSbox[149]
Xtime2Sbox[149] = _Xtime2Sbox[149]
Xtime3Sbox[149] = _Xtime3Sbox[149]
Xtime2[149] = _Xtime2[149]
Xtime9[149] = _Xtime9[149]
XtimeB[149] = _XtimeB[149]
XtimeD[149] = _XtimeD[149]
XtimeE[149] = _XtimeE[149]
Sbox[150] = _Sbox[150]
InvSbox[150] = _InvSbox[150]
Xtime2Sbox[150] = _Xtime2Sbox[150]
Xtime3Sbox[150] = _Xtime3Sbox[150]
Xtime2[150] = _Xtime2[150]
Xtime9[150] = _Xtime9[150]
XtimeB[150] = _XtimeB[150]
XtimeD[150] = _XtimeD[150]
XtimeE[150] = _XtimeE[150]
Sbox[151] = _Sbox[151]
InvSbox[151] = _InvSbox[151]
Xtime2Sbox[151] = _Xtime2Sbox[151]
Xtime3Sbox[151] = _Xtime3Sbox[151]
Xtime2[151] = _Xtime2[151]
Xtime9[151] = _Xtime9[151]
XtimeB[151] = _XtimeB[151]
XtimeD[151] = _XtimeD[151]
XtimeE[151] = _XtimeE[151]
Sbox[152] = _Sbox[152]
InvSbox[152] = _InvSbox[152]
Xtime2Sbox[152] = _Xtime2Sbox[152]
Xtime3Sbox[152] = _Xtime3Sbox[152]
Xtime2[152] = _Xtime2[152]
Xtime9[152] = _Xtime9[152]
XtimeB[152] = _XtimeB[152]
XtimeD[152] = _XtimeD[152]
XtimeE[152] = _XtimeE[152]
Sbox[153] = _Sbox[153]
InvSbox[153] = _InvSbox[153]
Xtime2Sbox[153] = _Xtime2Sbox[153]
Xtime3Sbox[153] = _Xtime3Sbox[153]
Xtime2[153] = _Xtime2[153]
Xtime9[153] = _Xtime9[153]
XtimeB[153] = _XtimeB[153]
XtimeD[153] = _XtimeD[153]
XtimeE[153] = _XtimeE[153]
Sbox[154] = _Sbox[154]
InvSbox[154] = _InvSbox[154]
Xtime2Sbox[154] = _Xtime2Sbox[154]
Xtime3Sbox[154] = _Xtime3Sbox[154]
Xtime2[154] = _Xtime2[154]
Xtime9[154] = _Xtime9[154]
XtimeB[154] = _XtimeB[154]
XtimeD[154] = _XtimeD[154]
XtimeE[154] = _XtimeE[154]
Sbox[155] = _Sbox[155]
InvSbox[155] = _InvSbox[155]
Xtime2Sbox[155] = _Xtime2Sbox[155]
Xtime3Sbox[155] = _Xtime3Sbox[155]
Xtime2[155] = _Xtime2[155]
Xtime9[155] = _Xtime9[155]
XtimeB[155] = _XtimeB[155]
XtimeD[155] = _XtimeD[155]
XtimeE[155] = _XtimeE[155]
Sbox[156] = _Sbox[156]
InvSbox[156] = _InvSbox[156]
Xtime2Sbox[156] = _Xtime2Sbox[156]
Xtime3Sbox[156] = _Xtime3Sbox[156]
Xtime2[156] = _Xtime2[156]
Xtime9[156] = _Xtime9[156]
XtimeB[156] = _XtimeB[156]
XtimeD[156] = _XtimeD[156]
XtimeE[156] = _XtimeE[156]
Sbox[157] = _Sbox[157]
InvSbox[157] = _InvSbox[157]
Xtime2Sbox[157] = _Xtime2Sbox[157]
Xtime3Sbox[157] = _Xtime3Sbox[157]
Xtime2[157] = _Xtime2[157]
Xtime9[157] = _Xtime9[157]
XtimeB[157] = _XtimeB[157]
XtimeD[157] = _XtimeD[157]
XtimeE[157] = _XtimeE[157]
Sbox[158] = _Sbox[158]
InvSbox[158] = _InvSbox[158]
Xtime2Sbox[158] = _Xtime2Sbox[158]
Xtime3Sbox[158] = _Xtime3Sbox[158]
Xtime2[158] = _Xtime2[158]
Xtime9[158] = _Xtime9[158]
XtimeB[158] = _XtimeB[158]
XtimeD[158] = _XtimeD[158]
XtimeE[158] = _XtimeE[158]
Sbox[159] = _Sbox[159]
InvSbox[159] = _InvSbox[159]
Xtime2Sbox[159] = _Xtime2Sbox[159]
Xtime3Sbox[159] = _Xtime3Sbox[159]
Xtime2[159] = _Xtime2[159]
Xtime9[159] = _Xtime9[159]
XtimeB[159] = _XtimeB[159]
XtimeD[159] = _XtimeD[159]
XtimeE[159] = _XtimeE[159]
Sbox[160] = _Sbox[160]
InvSbox[160] = _InvSbox[160]
Xtime2Sbox[160] = _Xtime2Sbox[160]
Xtime3Sbox[160] = _Xtime3Sbox[160]
Xtime2[160] = _Xtime2[160]
Xtime9[160] = _Xtime9[160]
XtimeB[160] = _XtimeB[160]
XtimeD[160] = _XtimeD[160]
XtimeE[160] = _XtimeE[160]
Sbox[161] = _Sbox[161]
InvSbox[161] = _InvSbox[161]
Xtime2Sbox[161] = _Xtime2Sbox[161]
Xtime3Sbox[161] = _Xtime3Sbox[161]
Xtime2[161] = _Xtime2[161]
Xtime9[161] = _Xtime9[161]
XtimeB[161] = _XtimeB[161]
XtimeD[161] = _XtimeD[161]
XtimeE[161] = _XtimeE[161]
Sbox[162] = _Sbox[162]
InvSbox[162] = _InvSbox[162]
Xtime2Sbox[162] = _Xtime2Sbox[162]
Xtime3Sbox[162] = _Xtime3Sbox[162]
Xtime2[162] = _Xtime2[162]
Xtime9[162] = _Xtime9[162]
XtimeB[162] = _XtimeB[162]
XtimeD[162] = _XtimeD[162]
XtimeE[162] = _XtimeE[162]
Sbox[163] = _Sbox[163]
InvSbox[163] = _InvSbox[163]
Xtime2Sbox[163] = _Xtime2Sbox[163]
Xtime3Sbox[163] = _Xtime3Sbox[163]
Xtime2[163] = _Xtime2[163]
Xtime9[163] = _Xtime9[163]
XtimeB[163] = _XtimeB[163]
XtimeD[163] = _XtimeD[163]
XtimeE[163] = _XtimeE[163]
Sbox[164] = _Sbox[164]
InvSbox[164] = _InvSbox[164]
Xtime2Sbox[164] = _Xtime2Sbox[164]
Xtime3Sbox[164] = _Xtime3Sbox[164]
Xtime2[164] = _Xtime2[164]
Xtime9[164] = _Xtime9[164]
XtimeB[164] = _XtimeB[164]
XtimeD[164] = _XtimeD[164]
XtimeE[164] = _XtimeE[164]
Sbox[165] = _Sbox[165]
InvSbox[165] = _InvSbox[165]
Xtime2Sbox[165] = _Xtime2Sbox[165]
Xtime3Sbox[165] = _Xtime3Sbox[165]
Xtime2[165] = _Xtime2[165]
Xtime9[165] = _Xtime9[165]
XtimeB[165] = _XtimeB[165]
XtimeD[165] = _XtimeD[165]
XtimeE[165] = _XtimeE[165]
Sbox[166] = _Sbox[166]
InvSbox[166] = _InvSbox[166]
Xtime2Sbox[166] = _Xtime2Sbox[166]
Xtime3Sbox[166] = _Xtime3Sbox[166]
Xtime2[166] = _Xtime2[166]
Xtime9[166] = _Xtime9[166]
XtimeB[166] = _XtimeB[166]
XtimeD[166] = _XtimeD[166]
XtimeE[166] = _XtimeE[166]
Sbox[167] = _Sbox[167]
InvSbox[167] = _InvSbox[167]
Xtime2Sbox[167] = _Xtime2Sbox[167]
Xtime3Sbox[167] = _Xtime3Sbox[167]
Xtime2[167] = _Xtime2[167]
Xtime9[167] = _Xtime9[167]
XtimeB[167] = _XtimeB[167]
XtimeD[167] = _XtimeD[167]
XtimeE[167] = _XtimeE[167]
Sbox[168] = _Sbox[168]
InvSbox[168] = _InvSbox[168]
Xtime2Sbox[168] = _Xtime2Sbox[168]
Xtime3Sbox[168] = _Xtime3Sbox[168]
Xtime2[168] = _Xtime2[168]
Xtime9[168] = _Xtime9[168]
XtimeB[168] = _XtimeB[168]
XtimeD[168] = _XtimeD[168]
XtimeE[168] = _XtimeE[168]
Sbox[169] = _Sbox[169]
InvSbox[169] = _InvSbox[169]
Xtime2Sbox[169] = _Xtime2Sbox[169]
Xtime3Sbox[169] = _Xtime3Sbox[169]
Xtime2[169] = _Xtime2[169]
Xtime9[169] = _Xtime9[169]
XtimeB[169] = _XtimeB[169]
XtimeD[169] = _XtimeD[169]
XtimeE[169] = _XtimeE[169]
Sbox[170] = _Sbox[170]
InvSbox[170] = _InvSbox[170]
Xtime2Sbox[170] = _Xtime2Sbox[170]
Xtime3Sbox[170] = _Xtime3Sbox[170]
Xtime2[170] = _Xtime2[170]
Xtime9[170] = _Xtime9[170]
XtimeB[170] = _XtimeB[170]
XtimeD[170] = _XtimeD[170]
XtimeE[170] = _XtimeE[170]
Sbox[171] = _Sbox[171]
InvSbox[171] = _InvSbox[171]
Xtime2Sbox[171] = _Xtime2Sbox[171]
Xtime3Sbox[171] = _Xtime3Sbox[171]
Xtime2[171] = _Xtime2[171]
Xtime9[171] = _Xtime9[171]
XtimeB[171] = _XtimeB[171]
XtimeD[171] = _XtimeD[171]
XtimeE[171] = _XtimeE[171]
Sbox[172] = _Sbox[172]
InvSbox[172] = _InvSbox[172]
Xtime2Sbox[172] = _Xtime2Sbox[172]
Xtime3Sbox[172] = _Xtime3Sbox[172]
Xtime2[172] = _Xtime2[172]
Xtime9[172] = _Xtime9[172]
XtimeB[172] = _XtimeB[172]
XtimeD[172] = _XtimeD[172]
XtimeE[172] = _XtimeE[172]
Sbox[173] = _Sbox[173]
InvSbox[173] = _InvSbox[173]
Xtime2Sbox[173] = _Xtime2Sbox[173]
Xtime3Sbox[173] = _Xtime3Sbox[173]
Xtime2[173] = _Xtime2[173]
Xtime9[173] = _Xtime9[173]
XtimeB[173] = _XtimeB[173]
XtimeD[173] = _XtimeD[173]
XtimeE[173] = _XtimeE[173]
Sbox[174] = _Sbox[174]
InvSbox[174] = _InvSbox[174]
Xtime2Sbox[174] = _Xtime2Sbox[174]
Xtime3Sbox[174] = _Xtime3Sbox[174]
Xtime2[174] = _Xtime2[174]
Xtime9[174] = _Xtime9[174]
XtimeB[174] = _XtimeB[174]
XtimeD[174] = _XtimeD[174]
XtimeE[174] = _XtimeE[174]
Sbox[175] = _Sbox[175]
InvSbox[175] = _InvSbox[175]
Xtime2Sbox[175] = _Xtime2Sbox[175]
Xtime3Sbox[175] = _Xtime3Sbox[175]
Xtime2[175] = _Xtime2[175]
Xtime9[175] = _Xtime9[175]
XtimeB[175] = _XtimeB[175]
XtimeD[175] = _XtimeD[175]
XtimeE[175] = _XtimeE[175]
Sbox[176] = _Sbox[176]
InvSbox[176] = _InvSbox[176]
Xtime2Sbox[176] = _Xtime2Sbox[176]
Xtime3Sbox[176] = _Xtime3Sbox[176]
Xtime2[176] = _Xtime2[176]
Xtime9[176] = _Xtime9[176]
XtimeB[176] = _XtimeB[176]
XtimeD[176] = _XtimeD[176]
XtimeE[176] = _XtimeE[176]
Sbox[177] = _Sbox[177]
InvSbox[177] = _InvSbox[177]
Xtime2Sbox[177] = _Xtime2Sbox[177]
Xtime3Sbox[177] = _Xtime3Sbox[177]
Xtime2[177] = _Xtime2[177]
Xtime9[177] = _Xtime9[177]
XtimeB[177] = _XtimeB[177]
XtimeD[177] = _XtimeD[177]
XtimeE[177] = _XtimeE[177]
Sbox[178] = _Sbox[178]
InvSbox[178] = _InvSbox[178]
Xtime2Sbox[178] = _Xtime2Sbox[178]
Xtime3Sbox[178] = _Xtime3Sbox[178]
Xtime2[178] = _Xtime2[178]
Xtime9[178] = _Xtime9[178]
XtimeB[178] = _XtimeB[178]
XtimeD[178] = _XtimeD[178]
XtimeE[178] = _XtimeE[178]
Sbox[179] = _Sbox[179]
InvSbox[179] = _InvSbox[179]
Xtime2Sbox[179] = _Xtime2Sbox[179]
Xtime3Sbox[179] = _Xtime3Sbox[179]
Xtime2[179] = _Xtime2[179]
Xtime9[179] = _Xtime9[179]
XtimeB[179] = _XtimeB[179]
XtimeD[179] = _XtimeD[179]
XtimeE[179] = _XtimeE[179]
Sbox[180] = _Sbox[180]
InvSbox[180] = _InvSbox[180]
Xtime2Sbox[180] = _Xtime2Sbox[180]
Xtime3Sbox[180] = _Xtime3Sbox[180]
Xtime2[180] = _Xtime2[180]
Xtime9[180] = _Xtime9[180]
XtimeB[180] = _XtimeB[180]
XtimeD[180] = _XtimeD[180]
XtimeE[180] = _XtimeE[180]
Sbox[181] = _Sbox[181]
InvSbox[181] = _InvSbox[181]
Xtime2Sbox[181] = _Xtime2Sbox[181]
Xtime3Sbox[181] = _Xtime3Sbox[181]
Xtime2[181] = _Xtime2[181]
Xtime9[181] = _Xtime9[181]
XtimeB[181] = _XtimeB[181]
XtimeD[181] = _XtimeD[181]
XtimeE[181] = _XtimeE[181]
Sbox[182] = _Sbox[182]
InvSbox[182] = _InvSbox[182]
Xtime2Sbox[182] = _Xtime2Sbox[182]
Xtime3Sbox[182] = _Xtime3Sbox[182]
Xtime2[182] = _Xtime2[182]
Xtime9[182] = _Xtime9[182]
XtimeB[182] = _XtimeB[182]
XtimeD[182] = _XtimeD[182]
XtimeE[182] = _XtimeE[182]
Sbox[183] = _Sbox[183]
InvSbox[183] = _InvSbox[183]
Xtime2Sbox[183] = _Xtime2Sbox[183]
Xtime3Sbox[183] = _Xtime3Sbox[183]
Xtime2[183] = _Xtime2[183]
Xtime9[183] = _Xtime9[183]
XtimeB[183] = _XtimeB[183]
XtimeD[183] = _XtimeD[183]
XtimeE[183] = _XtimeE[183]
Sbox[184] = _Sbox[184]
InvSbox[184] = _InvSbox[184]
Xtime2Sbox[184] = _Xtime2Sbox[184]
Xtime3Sbox[184] = _Xtime3Sbox[184]
Xtime2[184] = _Xtime2[184]
Xtime9[184] = _Xtime9[184]
XtimeB[184] = _XtimeB[184]
XtimeD[184] = _XtimeD[184]
XtimeE[184] = _XtimeE[184]
Sbox[185] = _Sbox[185]
InvSbox[185] = _InvSbox[185]
Xtime2Sbox[185] = _Xtime2Sbox[185]
Xtime3Sbox[185] = _Xtime3Sbox[185]
Xtime2[185] = _Xtime2[185]
Xtime9[185] = _Xtime9[185]
XtimeB[185] = _XtimeB[185]
XtimeD[185] = _XtimeD[185]
XtimeE[185] = _XtimeE[185]
Sbox[186] = _Sbox[186]
InvSbox[186] = _InvSbox[186]
Xtime2Sbox[186] = _Xtime2Sbox[186]
Xtime3Sbox[186] = _Xtime3Sbox[186]
Xtime2[186] = _Xtime2[186]
Xtime9[186] = _Xtime9[186]
XtimeB[186] = _XtimeB[186]
XtimeD[186] = _XtimeD[186]
XtimeE[186] = _XtimeE[186]
Sbox[187] = _Sbox[187]
InvSbox[187] = _InvSbox[187]
Xtime2Sbox[187] = _Xtime2Sbox[187]
Xtime3Sbox[187] = _Xtime3Sbox[187]
Xtime2[187] = _Xtime2[187]
Xtime9[187] = _Xtime9[187]
XtimeB[187] = _XtimeB[187]
XtimeD[187] = _XtimeD[187]
XtimeE[187] = _XtimeE[187]
Sbox[188] = _Sbox[188]
InvSbox[188] = _InvSbox[188]
Xtime2Sbox[188] = _Xtime2Sbox[188]
Xtime3Sbox[188] = _Xtime3Sbox[188]
Xtime2[188] = _Xtime2[188]
Xtime9[188] = _Xtime9[188]
XtimeB[188] = _XtimeB[188]
XtimeD[188] = _XtimeD[188]
XtimeE[188] = _XtimeE[188]
Sbox[189] = _Sbox[189]
InvSbox[189] = _InvSbox[189]
Xtime2Sbox[189] = _Xtime2Sbox[189]
Xtime3Sbox[189] = _Xtime3Sbox[189]
Xtime2[189] = _Xtime2[189]
Xtime9[189] = _Xtime9[189]
XtimeB[189] = _XtimeB[189]
XtimeD[189] = _XtimeD[189]
XtimeE[189] = _XtimeE[189]
Sbox[190] = _Sbox[190]
InvSbox[190] = _InvSbox[190]
Xtime2Sbox[190] = _Xtime2Sbox[190]
Xtime3Sbox[190] = _Xtime3Sbox[190]
Xtime2[190] = _Xtime2[190]
Xtime9[190] = _Xtime9[190]
XtimeB[190] = _XtimeB[190]
XtimeD[190] = _XtimeD[190]
XtimeE[190] = _XtimeE[190]
Sbox[191] = _Sbox[191]
InvSbox[191] = _InvSbox[191]
Xtime2Sbox[191] = _Xtime2Sbox[191]
Xtime3Sbox[191] = _Xtime3Sbox[191]
Xtime2[191] = _Xtime2[191]
Xtime9[191] = _Xtime9[191]
XtimeB[191] = _XtimeB[191]
XtimeD[191] = _XtimeD[191]
XtimeE[191] = _XtimeE[191]
Sbox[192] = _Sbox[192]
InvSbox[192] = _InvSbox[192]
Xtime2Sbox[192] = _Xtime2Sbox[192]
Xtime3Sbox[192] = _Xtime3Sbox[192]
Xtime2[192] = _Xtime2[192]
Xtime9[192] = _Xtime9[192]
XtimeB[192] = _XtimeB[192]
XtimeD[192] = _XtimeD[192]
XtimeE[192] = _XtimeE[192]
Sbox[193] = _Sbox[193]
InvSbox[193] = _InvSbox[193]
Xtime2Sbox[193] = _Xtime2Sbox[193]
Xtime3Sbox[193] = _Xtime3Sbox[193]
Xtime2[193] = _Xtime2[193]
Xtime9[193] = _Xtime9[193]
XtimeB[193] = _XtimeB[193]
XtimeD[193] = _XtimeD[193]
XtimeE[193] = _XtimeE[193]
Sbox[194] = _Sbox[194]
InvSbox[194] = _InvSbox[194]
Xtime2Sbox[194] = _Xtime2Sbox[194]
Xtime3Sbox[194] = _Xtime3Sbox[194]
Xtime2[194] = _Xtime2[194]
Xtime9[194] = _Xtime9[194]
XtimeB[194] = _XtimeB[194]
XtimeD[194] = _XtimeD[194]
XtimeE[194] = _XtimeE[194]
Sbox[195] = _Sbox[195]
InvSbox[195] = _InvSbox[195]
Xtime2Sbox[195] = _Xtime2Sbox[195]
Xtime3Sbox[195] = _Xtime3Sbox[195]
Xtime2[195] = _Xtime2[195]
Xtime9[195] = _Xtime9[195]
XtimeB[195] = _XtimeB[195]
XtimeD[195] = _XtimeD[195]
XtimeE[195] = _XtimeE[195]
Sbox[196] = _Sbox[196]
InvSbox[196] = _InvSbox[196]
Xtime2Sbox[196] = _Xtime2Sbox[196]
Xtime3Sbox[196] = _Xtime3Sbox[196]
Xtime2[196] = _Xtime2[196]
Xtime9[196] = _Xtime9[196]
XtimeB[196] = _XtimeB[196]
XtimeD[196] = _XtimeD[196]
XtimeE[196] = _XtimeE[196]
Sbox[197] = _Sbox[197]
InvSbox[197] = _InvSbox[197]
Xtime2Sbox[197] = _Xtime2Sbox[197]
Xtime3Sbox[197] = _Xtime3Sbox[197]
Xtime2[197] = _Xtime2[197]
Xtime9[197] = _Xtime9[197]
XtimeB[197] = _XtimeB[197]
XtimeD[197] = _XtimeD[197]
XtimeE[197] = _XtimeE[197]
Sbox[198] = _Sbox[198]
InvSbox[198] = _InvSbox[198]
Xtime2Sbox[198] = _Xtime2Sbox[198]
Xtime3Sbox[198] = _Xtime3Sbox[198]
Xtime2[198] = _Xtime2[198]
Xtime9[198] = _Xtime9[198]
XtimeB[198] = _XtimeB[198]
XtimeD[198] = _XtimeD[198]
XtimeE[198] = _XtimeE[198]
Sbox[199] = _Sbox[199]
InvSbox[199] = _InvSbox[199]
Xtime2Sbox[199] = _Xtime2Sbox[199]
Xtime3Sbox[199] = _Xtime3Sbox[199]
Xtime2[199] = _Xtime2[199]
Xtime9[199] = _Xtime9[199]
XtimeB[199] = _XtimeB[199]
XtimeD[199] = _XtimeD[199]
XtimeE[199] = _XtimeE[199]
Sbox[200] = _Sbox[200]
InvSbox[200] = _InvSbox[200]
Xtime2Sbox[200] = _Xtime2Sbox[200]
Xtime3Sbox[200] = _Xtime3Sbox[200]
Xtime2[200] = _Xtime2[200]
Xtime9[200] = _Xtime9[200]
XtimeB[200] = _XtimeB[200]
XtimeD[200] = _XtimeD[200]
XtimeE[200] = _XtimeE[200]
Sbox[201] = _Sbox[201]
InvSbox[201] = _InvSbox[201]
Xtime2Sbox[201] = _Xtime2Sbox[201]
Xtime3Sbox[201] = _Xtime3Sbox[201]
Xtime2[201] = _Xtime2[201]
Xtime9[201] = _Xtime9[201]
XtimeB[201] = _XtimeB[201]
XtimeD[201] = _XtimeD[201]
XtimeE[201] = _XtimeE[201]
Sbox[202] = _Sbox[202]
InvSbox[202] = _InvSbox[202]
Xtime2Sbox[202] = _Xtime2Sbox[202]
Xtime3Sbox[202] = _Xtime3Sbox[202]
Xtime2[202] = _Xtime2[202]
Xtime9[202] = _Xtime9[202]
XtimeB[202] = _XtimeB[202]
XtimeD[202] = _XtimeD[202]
XtimeE[202] = _XtimeE[202]
Sbox[203] = _Sbox[203]
InvSbox[203] = _InvSbox[203]
Xtime2Sbox[203] = _Xtime2Sbox[203]
Xtime3Sbox[203] = _Xtime3Sbox[203]
Xtime2[203] = _Xtime2[203]
Xtime9[203] = _Xtime9[203]
XtimeB[203] = _XtimeB[203]
XtimeD[203] = _XtimeD[203]
XtimeE[203] = _XtimeE[203]
Sbox[204] = _Sbox[204]
InvSbox[204] = _InvSbox[204]
Xtime2Sbox[204] = _Xtime2Sbox[204]
Xtime3Sbox[204] = _Xtime3Sbox[204]
Xtime2[204] = _Xtime2[204]
Xtime9[204] = _Xtime9[204]
XtimeB[204] = _XtimeB[204]
XtimeD[204] = _XtimeD[204]
XtimeE[204] = _XtimeE[204]
Sbox[205] = _Sbox[205]
InvSbox[205] = _InvSbox[205]
Xtime2Sbox[205] = _Xtime2Sbox[205]
Xtime3Sbox[205] = _Xtime3Sbox[205]
Xtime2[205] = _Xtime2[205]
Xtime9[205] = _Xtime9[205]
XtimeB[205] = _XtimeB[205]
XtimeD[205] = _XtimeD[205]
XtimeE[205] = _XtimeE[205]
Sbox[206] = _Sbox[206]
InvSbox[206] = _InvSbox[206]
Xtime2Sbox[206] = _Xtime2Sbox[206]
Xtime3Sbox[206] = _Xtime3Sbox[206]
Xtime2[206] = _Xtime2[206]
Xtime9[206] = _Xtime9[206]
XtimeB[206] = _XtimeB[206]
XtimeD[206] = _XtimeD[206]
XtimeE[206] = _XtimeE[206]
Sbox[207] = _Sbox[207]
InvSbox[207] = _InvSbox[207]
Xtime2Sbox[207] = _Xtime2Sbox[207]
Xtime3Sbox[207] = _Xtime3Sbox[207]
Xtime2[207] = _Xtime2[207]
Xtime9[207] = _Xtime9[207]
XtimeB[207] = _XtimeB[207]
XtimeD[207] = _XtimeD[207]
XtimeE[207] = _XtimeE[207]
Sbox[208] = _Sbox[208]
InvSbox[208] = _InvSbox[208]
Xtime2Sbox[208] = _Xtime2Sbox[208]
Xtime3Sbox[208] = _Xtime3Sbox[208]
Xtime2[208] = _Xtime2[208]
Xtime9[208] = _Xtime9[208]
XtimeB[208] = _XtimeB[208]
XtimeD[208] = _XtimeD[208]
XtimeE[208] = _XtimeE[208]
Sbox[209] = _Sbox[209]
InvSbox[209] = _InvSbox[209]
Xtime2Sbox[209] = _Xtime2Sbox[209]
Xtime3Sbox[209] = _Xtime3Sbox[209]
Xtime2[209] = _Xtime2[209]
Xtime9[209] = _Xtime9[209]
XtimeB[209] = _XtimeB[209]
XtimeD[209] = _XtimeD[209]
XtimeE[209] = _XtimeE[209]
Sbox[210] = _Sbox[210]
InvSbox[210] = _InvSbox[210]
Xtime2Sbox[210] = _Xtime2Sbox[210]
Xtime3Sbox[210] = _Xtime3Sbox[210]
Xtime2[210] = _Xtime2[210]
Xtime9[210] = _Xtime9[210]
XtimeB[210] = _XtimeB[210]
XtimeD[210] = _XtimeD[210]
XtimeE[210] = _XtimeE[210]
Sbox[211] = _Sbox[211]
InvSbox[211] = _InvSbox[211]
Xtime2Sbox[211] = _Xtime2Sbox[211]
Xtime3Sbox[211] = _Xtime3Sbox[211]
Xtime2[211] = _Xtime2[211]
Xtime9[211] = _Xtime9[211]
XtimeB[211] = _XtimeB[211]
XtimeD[211] = _XtimeD[211]
XtimeE[211] = _XtimeE[211]
Sbox[212] = _Sbox[212]
InvSbox[212] = _InvSbox[212]
Xtime2Sbox[212] = _Xtime2Sbox[212]
Xtime3Sbox[212] = _Xtime3Sbox[212]
Xtime2[212] = _Xtime2[212]
Xtime9[212] = _Xtime9[212]
XtimeB[212] = _XtimeB[212]
XtimeD[212] = _XtimeD[212]
XtimeE[212] = _XtimeE[212]
Sbox[213] = _Sbox[213]
InvSbox[213] = _InvSbox[213]
Xtime2Sbox[213] = _Xtime2Sbox[213]
Xtime3Sbox[213] = _Xtime3Sbox[213]
Xtime2[213] = _Xtime2[213]
Xtime9[213] = _Xtime9[213]
XtimeB[213] = _XtimeB[213]
XtimeD[213] = _XtimeD[213]
XtimeE[213] = _XtimeE[213]
Sbox[214] = _Sbox[214]
InvSbox[214] = _InvSbox[214]
Xtime2Sbox[214] = _Xtime2Sbox[214]
Xtime3Sbox[214] = _Xtime3Sbox[214]
Xtime2[214] = _Xtime2[214]
Xtime9[214] = _Xtime9[214]
XtimeB[214] = _XtimeB[214]
XtimeD[214] = _XtimeD[214]
XtimeE[214] = _XtimeE[214]
Sbox[215] = _Sbox[215]
InvSbox[215] = _InvSbox[215]
Xtime2Sbox[215] = _Xtime2Sbox[215]
Xtime3Sbox[215] = _Xtime3Sbox[215]
Xtime2[215] = _Xtime2[215]
Xtime9[215] = _Xtime9[215]
XtimeB[215] = _XtimeB[215]
XtimeD[215] = _XtimeD[215]
XtimeE[215] = _XtimeE[215]
Sbox[216] = _Sbox[216]
InvSbox[216] = _InvSbox[216]
Xtime2Sbox[216] = _Xtime2Sbox[216]
Xtime3Sbox[216] = _Xtime3Sbox[216]
Xtime2[216] = _Xtime2[216]
Xtime9[216] = _Xtime9[216]
XtimeB[216] = _XtimeB[216]
XtimeD[216] = _XtimeD[216]
XtimeE[216] = _XtimeE[216]
Sbox[217] = _Sbox[217]
InvSbox[217] = _InvSbox[217]
Xtime2Sbox[217] = _Xtime2Sbox[217]
Xtime3Sbox[217] = _Xtime3Sbox[217]
Xtime2[217] = _Xtime2[217]
Xtime9[217] = _Xtime9[217]
XtimeB[217] = _XtimeB[217]
XtimeD[217] = _XtimeD[217]
XtimeE[217] = _XtimeE[217]
Sbox[218] = _Sbox[218]
InvSbox[218] = _InvSbox[218]
Xtime2Sbox[218] = _Xtime2Sbox[218]
Xtime3Sbox[218] = _Xtime3Sbox[218]
Xtime2[218] = _Xtime2[218]
Xtime9[218] = _Xtime9[218]
XtimeB[218] = _XtimeB[218]
XtimeD[218] = _XtimeD[218]
XtimeE[218] = _XtimeE[218]
Sbox[219] = _Sbox[219]
InvSbox[219] = _InvSbox[219]
Xtime2Sbox[219] = _Xtime2Sbox[219]
Xtime3Sbox[219] = _Xtime3Sbox[219]
Xtime2[219] = _Xtime2[219]
Xtime9[219] = _Xtime9[219]
XtimeB[219] = _XtimeB[219]
XtimeD[219] = _XtimeD[219]
XtimeE[219] = _XtimeE[219]
Sbox[220] = _Sbox[220]
InvSbox[220] = _InvSbox[220]
Xtime2Sbox[220] = _Xtime2Sbox[220]
Xtime3Sbox[220] = _Xtime3Sbox[220]
Xtime2[220] = _Xtime2[220]
Xtime9[220] = _Xtime9[220]
XtimeB[220] = _XtimeB[220]
XtimeD[220] = _XtimeD[220]
XtimeE[220] = _XtimeE[220]
Sbox[221] = _Sbox[221]
InvSbox[221] = _InvSbox[221]
Xtime2Sbox[221] = _Xtime2Sbox[221]
Xtime3Sbox[221] = _Xtime3Sbox[221]
Xtime2[221] = _Xtime2[221]
Xtime9[221] = _Xtime9[221]
XtimeB[221] = _XtimeB[221]
XtimeD[221] = _XtimeD[221]
XtimeE[221] = _XtimeE[221]
Sbox[222] = _Sbox[222]
InvSbox[222] = _InvSbox[222]
Xtime2Sbox[222] = _Xtime2Sbox[222]
Xtime3Sbox[222] = _Xtime3Sbox[222]
Xtime2[222] = _Xtime2[222]
Xtime9[222] = _Xtime9[222]
XtimeB[222] = _XtimeB[222]
XtimeD[222] = _XtimeD[222]
XtimeE[222] = _XtimeE[222]
Sbox[223] = _Sbox[223]
InvSbox[223] = _InvSbox[223]
Xtime2Sbox[223] = _Xtime2Sbox[223]
Xtime3Sbox[223] = _Xtime3Sbox[223]
Xtime2[223] = _Xtime2[223]
Xtime9[223] = _Xtime9[223]
XtimeB[223] = _XtimeB[223]
XtimeD[223] = _XtimeD[223]
XtimeE[223] = _XtimeE[223]
Sbox[224] = _Sbox[224]
InvSbox[224] = _InvSbox[224]
Xtime2Sbox[224] = _Xtime2Sbox[224]
Xtime3Sbox[224] = _Xtime3Sbox[224]
Xtime2[224] = _Xtime2[224]
Xtime9[224] = _Xtime9[224]
XtimeB[224] = _XtimeB[224]
XtimeD[224] = _XtimeD[224]
XtimeE[224] = _XtimeE[224]
Sbox[225] = _Sbox[225]
InvSbox[225] = _InvSbox[225]
Xtime2Sbox[225] = _Xtime2Sbox[225]
Xtime3Sbox[225] = _Xtime3Sbox[225]
Xtime2[225] = _Xtime2[225]
Xtime9[225] = _Xtime9[225]
XtimeB[225] = _XtimeB[225]
XtimeD[225] = _XtimeD[225]
XtimeE[225] = _XtimeE[225]
Sbox[226] = _Sbox[226]
InvSbox[226] = _InvSbox[226]
Xtime2Sbox[226] = _Xtime2Sbox[226]
Xtime3Sbox[226] = _Xtime3Sbox[226]
Xtime2[226] = _Xtime2[226]
Xtime9[226] = _Xtime9[226]
XtimeB[226] = _XtimeB[226]
XtimeD[226] = _XtimeD[226]
XtimeE[226] = _XtimeE[226]
Sbox[227] = _Sbox[227]
InvSbox[227] = _InvSbox[227]
Xtime2Sbox[227] = _Xtime2Sbox[227]
Xtime3Sbox[227] = _Xtime3Sbox[227]
Xtime2[227] = _Xtime2[227]
Xtime9[227] = _Xtime9[227]
XtimeB[227] = _XtimeB[227]
XtimeD[227] = _XtimeD[227]
XtimeE[227] = _XtimeE[227]
Sbox[228] = _Sbox[228]
InvSbox[228] = _InvSbox[228]
Xtime2Sbox[228] = _Xtime2Sbox[228]
Xtime3Sbox[228] = _Xtime3Sbox[228]
Xtime2[228] = _Xtime2[228]
Xtime9[228] = _Xtime9[228]
XtimeB[228] = _XtimeB[228]
XtimeD[228] = _XtimeD[228]
XtimeE[228] = _XtimeE[228]
Sbox[229] = _Sbox[229]
InvSbox[229] = _InvSbox[229]
Xtime2Sbox[229] = _Xtime2Sbox[229]
Xtime3Sbox[229] = _Xtime3Sbox[229]
Xtime2[229] = _Xtime2[229]
Xtime9[229] = _Xtime9[229]
XtimeB[229] = _XtimeB[229]
XtimeD[229] = _XtimeD[229]
XtimeE[229] = _XtimeE[229]
Sbox[230] = _Sbox[230]
InvSbox[230] = _InvSbox[230]
Xtime2Sbox[230] = _Xtime2Sbox[230]
Xtime3Sbox[230] = _Xtime3Sbox[230]
Xtime2[230] = _Xtime2[230]
Xtime9[230] = _Xtime9[230]
XtimeB[230] = _XtimeB[230]
XtimeD[230] = _XtimeD[230]
XtimeE[230] = _XtimeE[230]
Sbox[231] = _Sbox[231]
InvSbox[231] = _InvSbox[231]
Xtime2Sbox[231] = _Xtime2Sbox[231]
Xtime3Sbox[231] = _Xtime3Sbox[231]
Xtime2[231] = _Xtime2[231]
Xtime9[231] = _Xtime9[231]
XtimeB[231] = _XtimeB[231]
XtimeD[231] = _XtimeD[231]
XtimeE[231] = _XtimeE[231]
Sbox[232] = _Sbox[232]
InvSbox[232] = _InvSbox[232]
Xtime2Sbox[232] = _Xtime2Sbox[232]
Xtime3Sbox[232] = _Xtime3Sbox[232]
Xtime2[232] = _Xtime2[232]
Xtime9[232] = _Xtime9[232]
XtimeB[232] = _XtimeB[232]
XtimeD[232] = _XtimeD[232]
XtimeE[232] = _XtimeE[232]
Sbox[233] = _Sbox[233]
InvSbox[233] = _InvSbox[233]
Xtime2Sbox[233] = _Xtime2Sbox[233]
Xtime3Sbox[233] = _Xtime3Sbox[233]
Xtime2[233] = _Xtime2[233]
Xtime9[233] = _Xtime9[233]
XtimeB[233] = _XtimeB[233]
XtimeD[233] = _XtimeD[233]
XtimeE[233] = _XtimeE[233]
Sbox[234] = _Sbox[234]
InvSbox[234] = _InvSbox[234]
Xtime2Sbox[234] = _Xtime2Sbox[234]
Xtime3Sbox[234] = _Xtime3Sbox[234]
Xtime2[234] = _Xtime2[234]
Xtime9[234] = _Xtime9[234]
XtimeB[234] = _XtimeB[234]
XtimeD[234] = _XtimeD[234]
XtimeE[234] = _XtimeE[234]
Sbox[235] = _Sbox[235]
InvSbox[235] = _InvSbox[235]
Xtime2Sbox[235] = _Xtime2Sbox[235]
Xtime3Sbox[235] = _Xtime3Sbox[235]
Xtime2[235] = _Xtime2[235]
Xtime9[235] = _Xtime9[235]
XtimeB[235] = _XtimeB[235]
XtimeD[235] = _XtimeD[235]
XtimeE[235] = _XtimeE[235]
Sbox[236] = _Sbox[236]
InvSbox[236] = _InvSbox[236]
Xtime2Sbox[236] = _Xtime2Sbox[236]
Xtime3Sbox[236] = _Xtime3Sbox[236]
Xtime2[236] = _Xtime2[236]
Xtime9[236] = _Xtime9[236]
XtimeB[236] = _XtimeB[236]
XtimeD[236] = _XtimeD[236]
XtimeE[236] = _XtimeE[236]
Sbox[237] = _Sbox[237]
InvSbox[237] = _InvSbox[237]
Xtime2Sbox[237] = _Xtime2Sbox[237]
Xtime3Sbox[237] = _Xtime3Sbox[237]
Xtime2[237] = _Xtime2[237]
Xtime9[237] = _Xtime9[237]
XtimeB[237] = _XtimeB[237]
XtimeD[237] = _XtimeD[237]
XtimeE[237] = _XtimeE[237]
Sbox[238] = _Sbox[238]
InvSbox[238] = _InvSbox[238]
Xtime2Sbox[238] = _Xtime2Sbox[238]
Xtime3Sbox[238] = _Xtime3Sbox[238]
Xtime2[238] = _Xtime2[238]
Xtime9[238] = _Xtime9[238]
XtimeB[238] = _XtimeB[238]
XtimeD[238] = _XtimeD[238]
XtimeE[238] = _XtimeE[238]
Sbox[239] = _Sbox[239]
InvSbox[239] = _InvSbox[239]
Xtime2Sbox[239] = _Xtime2Sbox[239]
Xtime3Sbox[239] = _Xtime3Sbox[239]
Xtime2[239] = _Xtime2[239]
Xtime9[239] = _Xtime9[239]
XtimeB[239] = _XtimeB[239]
XtimeD[239] = _XtimeD[239]
XtimeE[239] = _XtimeE[239]
Sbox[240] = _Sbox[240]
InvSbox[240] = _InvSbox[240]
Xtime2Sbox[240] = _Xtime2Sbox[240]
Xtime3Sbox[240] = _Xtime3Sbox[240]
Xtime2[240] = _Xtime2[240]
Xtime9[240] = _Xtime9[240]
XtimeB[240] = _XtimeB[240]
XtimeD[240] = _XtimeD[240]
XtimeE[240] = _XtimeE[240]
Sbox[241] = _Sbox[241]
InvSbox[241] = _InvSbox[241]
Xtime2Sbox[241] = _Xtime2Sbox[241]
Xtime3Sbox[241] = _Xtime3Sbox[241]
Xtime2[241] = _Xtime2[241]
Xtime9[241] = _Xtime9[241]
XtimeB[241] = _XtimeB[241]
XtimeD[241] = _XtimeD[241]
XtimeE[241] = _XtimeE[241]
Sbox[242] = _Sbox[242]
InvSbox[242] = _InvSbox[242]
Xtime2Sbox[242] = _Xtime2Sbox[242]
Xtime3Sbox[242] = _Xtime3Sbox[242]
Xtime2[242] = _Xtime2[242]
Xtime9[242] = _Xtime9[242]
XtimeB[242] = _XtimeB[242]
XtimeD[242] = _XtimeD[242]
XtimeE[242] = _XtimeE[242]
Sbox[243] = _Sbox[243]
InvSbox[243] = _InvSbox[243]
Xtime2Sbox[243] = _Xtime2Sbox[243]
Xtime3Sbox[243] = _Xtime3Sbox[243]
Xtime2[243] = _Xtime2[243]
Xtime9[243] = _Xtime9[243]
XtimeB[243] = _XtimeB[243]
XtimeD[243] = _XtimeD[243]
XtimeE[243] = _XtimeE[243]
Sbox[244] = _Sbox[244]
InvSbox[244] = _InvSbox[244]
Xtime2Sbox[244] = _Xtime2Sbox[244]
Xtime3Sbox[244] = _Xtime3Sbox[244]
Xtime2[244] = _Xtime2[244]
Xtime9[244] = _Xtime9[244]
XtimeB[244] = _XtimeB[244]
XtimeD[244] = _XtimeD[244]
XtimeE[244] = _XtimeE[244]
Sbox[245] = _Sbox[245]
InvSbox[245] = _InvSbox[245]
Xtime2Sbox[245] = _Xtime2Sbox[245]
Xtime3Sbox[245] = _Xtime3Sbox[245]
Xtime2[245] = _Xtime2[245]
Xtime9[245] = _Xtime9[245]
XtimeB[245] = _XtimeB[245]
XtimeD[245] = _XtimeD[245]
XtimeE[245] = _XtimeE[245]
Sbox[246] = _Sbox[246]
InvSbox[246] = _InvSbox[246]
Xtime2Sbox[246] = _Xtime2Sbox[246]
Xtime3Sbox[246] = _Xtime3Sbox[246]
Xtime2[246] = _Xtime2[246]
Xtime9[246] = _Xtime9[246]
XtimeB[246] = _XtimeB[246]
XtimeD[246] = _XtimeD[246]
XtimeE[246] = _XtimeE[246]
Sbox[247] = _Sbox[247]
InvSbox[247] = _InvSbox[247]
Xtime2Sbox[247] = _Xtime2Sbox[247]
Xtime3Sbox[247] = _Xtime3Sbox[247]
Xtime2[247] = _Xtime2[247]
Xtime9[247] = _Xtime9[247]
XtimeB[247] = _XtimeB[247]
XtimeD[247] = _XtimeD[247]
XtimeE[247] = _XtimeE[247]
Sbox[248] = _Sbox[248]
InvSbox[248] = _InvSbox[248]
Xtime2Sbox[248] = _Xtime2Sbox[248]
Xtime3Sbox[248] = _Xtime3Sbox[248]
Xtime2[248] = _Xtime2[248]
Xtime9[248] = _Xtime9[248]
XtimeB[248] = _XtimeB[248]
XtimeD[248] = _XtimeD[248]
XtimeE[248] = _XtimeE[248]
Sbox[249] = _Sbox[249]
InvSbox[249] = _InvSbox[249]
Xtime2Sbox[249] = _Xtime2Sbox[249]
Xtime3Sbox[249] = _Xtime3Sbox[249]
Xtime2[249] = _Xtime2[249]
Xtime9[249] = _Xtime9[249]
XtimeB[249] = _XtimeB[249]
XtimeD[249] = _XtimeD[249]
XtimeE[249] = _XtimeE[249]
Sbox[250] = _Sbox[250]
InvSbox[250] = _InvSbox[250]
Xtime2Sbox[250] = _Xtime2Sbox[250]
Xtime3Sbox[250] = _Xtime3Sbox[250]
Xtime2[250] = _Xtime2[250]
Xtime9[250] = _Xtime9[250]
XtimeB[250] = _XtimeB[250]
XtimeD[250] = _XtimeD[250]
XtimeE[250] = _XtimeE[250]
Sbox[251] = _Sbox[251]
InvSbox[251] = _InvSbox[251]
Xtime2Sbox[251] = _Xtime2Sbox[251]
Xtime3Sbox[251] = _Xtime3Sbox[251]
Xtime2[251] = _Xtime2[251]
Xtime9[251] = _Xtime9[251]
XtimeB[251] = _XtimeB[251]
XtimeD[251] = _XtimeD[251]
XtimeE[251] = _XtimeE[251]
Sbox[252] = _Sbox[252]
InvSbox[252] = _InvSbox[252]
Xtime2Sbox[252] = _Xtime2Sbox[252]
Xtime3Sbox[252] = _Xtime3Sbox[252]
Xtime2[252] = _Xtime2[252]
Xtime9[252] = _Xtime9[252]
XtimeB[252] = _XtimeB[252]
XtimeD[252] = _XtimeD[252]
XtimeE[252] = _XtimeE[252]
Sbox[253] = _Sbox[253]
InvSbox[253] = _InvSbox[253]
Xtime2Sbox[253] = _Xtime2Sbox[253]
Xtime3Sbox[253] = _Xtime3Sbox[253]
Xtime2[253] = _Xtime2[253]
Xtime9[253] = _Xtime9[253]
XtimeB[253] = _XtimeB[253]
XtimeD[253] = _XtimeD[253]
XtimeE[253] = _XtimeE[253]
Sbox[254] = _Sbox[254]
InvSbox[254] = _InvSbox[254]
Xtime2Sbox[254] = _Xtime2Sbox[254]
Xtime3Sbox[254] = _Xtime3Sbox[254]
Xtime2[254] = _Xtime2[254]
Xtime9[254] = _Xtime9[254]
XtimeB[254] = _XtimeB[254]
XtimeD[254] = _XtimeD[254]
XtimeE[254] = _XtimeE[254]
Sbox[255] = _Sbox[255]
InvSbox[255] = _InvSbox[255]
Xtime2Sbox[255] = _Xtime2Sbox[255]
Xtime3Sbox[255] = _Xtime3Sbox[255]
Xtime2[255] = _Xtime2[255]
Xtime9[255] = _Xtime9[255]
XtimeB[255] = _XtimeB[255]
XtimeD[255] = _XtimeD[255]
XtimeE[255] = _XtimeE[255]
/**
* AESKeyTest
*
* A test class for AESKey
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.prng.Random;
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.ECBMode;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import flash.utils.getTimer;
public class AESKeyTest extends TestCase
{
public function AESKeyTest(h:ITestHarness) {
super(h, "AESKey Test");
runTest(testGetBlockSize, "AES Block Size");
runTest(testECB_TBL, "AES ECB Test Vectors");
h.endTestCase();
}
public function testGetBlockSize():void {
var key:ByteArray = new ByteArray;
for (var i:uint=0;i<32;i++) {
key[i]=i;
}
var k:AESKey = new AESKey(key);
assert("128bit block size", k.getBlockSize()==16);
}
/**
* http://csrc.nist.gov/encryption/aes/rijndael/rijndael-vals.zip
* this uses ecb_tbl.txt
* we test encryption and decryption with keys of length 128,192,256 bits.
*/
public function testECB_TBL():void {
var keys:Array = [
"00010203050607080A0B0C0D0F101112",
"14151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A",
"3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F606162",
"64656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A",
"8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2",
"B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA",
"DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE010002",
"04050607090A0B0C0E0F101113141516",
"2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F505152",
"54555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A",
"7C7D7E7F81828384868788898B8C8D8E",
"A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2",
"08090A0B0D0E0F10121314151718191A",
"6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F909192",
"94959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA",
"BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2",
"E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"F8F9FAFBFDFEFE00020304050708090A",
"0C0D0E0F11121314161718191B1C1D1E",
"20212223252627282A2B2C2D2F303132",
"34353637393A3B3C3E3F404143444546",
"48494A4B4D4E4F50525354555758595A",
"5C5D5E5F61626364666768696B6C6D6E",
"70717273757677787A7B7C7D7F808182",
"84858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AA",
"ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2",
"D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA",
"FCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F202122",
"24252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A",
"4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F707172",
"74757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A",
"9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2",
"C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EA",
"ECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F101112",
"14151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A",
"3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F606162",
"64656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A",
"8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2",
"B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA",
"DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE010002",
"04050607090A0B0C0E0F101113141516",
"18191A1B1D1E1F20222324252728292A",
"2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F505152",
"54555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A",
"7C7D7E7F81828384868788898B8C8D8E",
"90919293959697989A9B9C9D9FA0A1A2",
"A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CA",
"CCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2",
"F4F5F6F7F9FAFBFCFEFE010103040506",
"08090A0B0D0E0F10121314151718191A",
"1C1D1E1F21222324262728292B2C2D2E",
"30313233353637383A3B3C3D3F404142",
"44454647494A4B4C4E4F505153545556",
"58595A5B5D5E5F60626364656768696A",
"6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F909192",
"94959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA",
"BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2",
"E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"F8F9FAFBFDFEFE00020304050708090A",
"0C0D0E0F11121314161718191B1C1D1E",
"20212223252627282A2B2C2D2F303132",
"34353637393A3B3C3E3F404143444546",
"48494A4B4D4E4F50525354555758595A",
"5C5D5E5F61626364666768696B6C6D6E",
"70717273757677787A7B7C7D7F808182",
"84858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AA",
"ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2",
"D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA",
"FCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F202122",
"24252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A",
"4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F707172",
"74757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A",
"9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2",
"C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EA",
"ECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F101112",
"14151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A",
"3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F606162",
"64656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A",
"8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2",
"00010203050607080A0B0C0D0F10111214151617191A1B1C",
"1E1F20212324252628292A2B2D2E2F30323334353738393A",
"3C3D3E3F41424344464748494B4C4D4E5051525355565758",
"5A5B5C5D5F60616264656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A8C8D8E8F91929394",
"969798999B9C9D9EA0A1A2A3A5A6A7A8AAABACADAFB0B1B2",
"B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6C8C9CACBCDCECFD0",
"D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C",
"0E0F10111314151618191A1B1D1E1F20222324252728292A",
"2C2D2E2F31323334363738393B3C3D3E4041424345464748",
"4A4B4C4D4F50515254555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A7C7D7E7F81828384",
"868788898B8C8D8E90919293959697989A9B9C9D9FA0A1A2",
"A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6B8B9BABBBDBEBFC0",
"C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFC",
"FEFE01010304050608090A0B0D0E0F10121314151718191A",
"1C1D1E1F21222324262728292B2C2D2E3031323335363738",
"3A3B3C3D3F40414244454647494A4B4C4E4F505153545556",
"58595A5B5D5E5F60626364656768696A6C6D6E6F71727374",
"767778797B7C7D7E80818283858687888A8B8C8D8F909192",
"94959697999A9B9C9E9FA0A1A3A4A5A6A8A9AAABADAEAFB0",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBEC",
"2A2B2C2D2F30313234353637393A3B3C3E3F404143444546",
"48494A4B4D4E4F50525354555758595A5C5D5E5F61626364",
"84858687898A8B8C8E8F90919394959698999A9B9D9E9FA0",
"A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDC",
"1A1B1C1D1F20212224252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A4C4D4E4F51525354",
"929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"464748494B4C4D4E50515253555657585A5B5C5D5F606162",
"828384858788898A8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBC",
"BEBFC0C1C3C4C5C6C8C9CACBCDCECFD0D2D3D4D5D7D8D9DA",
"DCDDDEDFE1E2E3E4E6E7E8E9EBECEDEEF0F1F2F3F5F6F7F8",
"FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",
"18191A1B1D1E1F20222324252728292A2C2D2E2F31323334",
"363738393B3C3D3E40414243454647484A4B4C4D4F505152",
"54555657595A5B5C5E5F60616364656668696A6B6D6E6F70",
"727374757778797A7C7D7E7F81828384868788898B8C8D8E",
"90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABAC",
"AEAFB0B1B3B4B5B6B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CA",
"CCCDCECFD1D2D3D4D6D7D8D9DBDCDDDEE0E1E2E3E5E6E7E8",
"EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",
"08090A0B0D0E0F10121314151718191A1C1D1E1F21222324",
"262728292B2C2D2E30313233353637383A3B3C3D3F404142",
"44454647494A4B4C4E4F50515354555658595A5B5D5E5F60",
"626364656768696A6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F90919294959697999A9B9C",
"9E9FA0A1A3A4A5A6A8A9AAABADAEAFB0B2B3B4B5B7B8B9BA",
"BCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCED0D1D2D3D5D6D7D8",
"DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314",
"161718191B1C1D1E20212223252627282A2B2C2D2F303132",
"34353637393A3B3C3E3F40414344454648494A4B4D4E4F50",
"525354555758595A5C5D5E5F61626364666768696B6C6D6E",
"70717273757677787A7B7C7D7F80818284858687898A8B8C",
"8E8F90919394959698999A9B9D9E9FA0A2A3A4A5A7A8A9AA",
"ACADAEAFB1B2B3B4B6B7B8B9BBBCBDBEC0C1C2C3C5C6C7C8",
"CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304",
"060708090B0C0D0E10111213151617181A1B1C1D1F202122",
"24252627292A2B2C2E2F30313334353638393A3B3D3E3F40",
"424344454748494A4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F70717274757677797A7B7C",
"7E7F80818384858688898A8B8D8E8F90929394959798999A",
"9C9D9E9FA1A2A3A4A6A7A8A9ABACADAEB0B1B2B3B5B6B7B8",
"BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4",
"F6F7F8F9FBFCFDFE00010203050607080A0B0C0D0F101112",
"14151617191A1B1C1E1F20212324252628292A2B2D2E2F30",
"323334353738393A3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F60616264656667696A6B6C",
"6E6F70717374757678797A7B7D7E7F80828384858788898A",
"8C8D8E8F91929394969798999B9C9D9EA0A1A2A3A5A6A7A8",
"AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4",
"E6E7E8E9EBECEDEEF0F1F2F3F5F6F7F8FAFBFCFDFE010002",
"04050607090A0B0C0E0F10111314151618191A1B1D1E1F20",
"222324252728292A2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F50515254555657595A5B5C",
"5E5F60616364656668696A6B6D6E6F70727374757778797A",
"7C7D7E7F81828384868788898B8C8D8E9091929395969798",
"9A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4",
"D6D7D8D9DBDCDDDEE0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2",
"F4F5F6F7F9FAFBFCFEFE01010304050608090A0B0D0E0F10",
"121314151718191A1C1D1E1F21222324262728292B2C2D2E",
"30313233353637383A3B3C3D3F40414244454647494A4B4C",
"4E4F50515354555658595A5B5D5E5F60626364656768696A",
"6C6D6E6F71727374767778797B7C7D7E8081828385868788",
"8A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4",
"C6C7C8C9CBCCCDCED0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2",
"E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6F8F9FAFBFDFEFE00",
"020304050708090A0C0D0E0F11121314161718191B1C1D1E",
"20212223252627282A2B2C2D2F30313234353637393A3B3C",
"3E3F40414344454648494A4B4D4E4F50525354555758595A",
"5C5D5E5F61626364666768696B6C6D6E7071727375767778",
"7A7B7C7D7F80818284858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4",
"B6B7B8B9BBBCBDBEC0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2",
"D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6E8E9EAEBEDEEEFF0",
"F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F20212224252627292A2B2C",
"2E2F30313334353638393A3B3D3E3F40424344454748494A",
"4C4D4E4F51525354565758595B5C5D5E6061626365666768",
"6A6B6C6D6F70717274757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4",
"A6A7A8A9ABACADAEB0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2",
"C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6D8D9DADBDDDEDFE0",
"E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F10111214151617191A1B1C",
"1E1F20212324252628292A2B2D2E2F30323334353738393A",
"3C3D3E3F41424344464748494B4C4D4E5051525355565758",
"5A5B5C5D5F60616264656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A8C8D8E8F91929394",
"969798999B9C9D9EA0A1A2A3A5A6A7A8AAABACADAFB0B1B2",
"B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6C8C9CACBCDCECFD0",
"D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C",
"0E0F10111314151618191A1B1D1E1F20222324252728292A",
"2C2D2E2F31323334363738393B3C3D3E4041424345464748",
"4A4B4C4D4F50515254555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A7C7D7E7F81828384",
"868788898B8C8D8E90919293959697989A9B9C9D9FA0A1A2",
"00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",
"18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",
"90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",
"08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",
"30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",
"58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",
"18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",
"90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",
"08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",
"30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",
"58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E",
"20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546",
"48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E",
"70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",
"18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",
"90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",
"08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",
"30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",
"58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E",
"20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546",
"48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E",
"70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576",
"78797A7B7D7E7F80828384858788898A8C8D8E8F91929394969798999B9C9D9E",
"A0A1A2A3A5A6A7A8AAABACADAFB0B1B2B4B5B6B7B9BABBBCBEBFC0C1C3C4C5C6",
"C8C9CACBCDCECFD0D2D3D4D5D7D8D9DADCDDDEDFE1E2E3E4E6E7E8E9EBECEDEE",
"F0F1F2F3F5F6F7F8FAFBFCFDFE01000204050607090A0B0C0E0F101113141516",
"18191A1B1D1E1F20222324252728292A2C2D2E2F31323334363738393B3C3D3E",
"40414243454647484A4B4C4D4F50515254555657595A5B5C5E5F606163646566",
"68696A6B6D6E6F70727374757778797A7C7D7E7F81828384868788898B8C8D8E",
"90919293959697989A9B9C9D9FA0A1A2A4A5A6A7A9AAABACAEAFB0B1B3B4B5B6",
"B8B9BABBBDBEBFC0C2C3C4C5C7C8C9CACCCDCECFD1D2D3D4D6D7D8D9DBDCDDDE",
"E0E1E2E3E5E6E7E8EAEBECEDEFF0F1F2F4F5F6F7F9FAFBFCFEFE010103040506",
"08090A0B0D0E0F10121314151718191A1C1D1E1F21222324262728292B2C2D2E",
"30313233353637383A3B3C3D3F40414244454647494A4B4C4E4F505153545556",
"58595A5B5D5E5F60626364656768696A6C6D6E6F71727374767778797B7C7D7E",
"80818283858687888A8B8C8D8F90919294959697999A9B9C9E9FA0A1A3A4A5A6",
"A8A9AAABADAEAFB0B2B3B4B5B7B8B9BABCBDBEBFC1C2C3C4C6C7C8C9CBCCCDCE",
"D0D1D2D3D5D6D7D8DADBDCDDDFE0E1E2E4E5E6E7E9EAEBECEEEFF0F1F3F4F5F6",
"F8F9FAFBFDFEFE00020304050708090A0C0D0E0F11121314161718191B1C1D1E",
"20212223252627282A2B2C2D2F30313234353637393A3B3C3E3F404143444546",
"48494A4B4D4E4F50525354555758595A5C5D5E5F61626364666768696B6C6D6E",
"70717273757677787A7B7C7D7F80818284858687898A8B8C8E8F909193949596",
"98999A9B9D9E9FA0A2A3A4A5A7A8A9AAACADAEAFB1B2B3B4B6B7B8B9BBBCBDBE",
"C0C1C2C3C5C6C7C8CACBCCCDCFD0D1D2D4D5D6D7D9DADBDCDEDFE0E1E3E4E5E6",
"E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FAFCFDFEFF01020304060708090B0C0D0E",
"10111213151617181A1B1C1D1F20212224252627292A2B2C2E2F303133343536",
"38393A3B3D3E3F40424344454748494A4C4D4E4F51525354565758595B5C5D5E",
"60616263656667686A6B6C6D6F70717274757677797A7B7C7E7F808183848586",
"88898A8B8D8E8F90929394959798999A9C9D9E9FA1A2A3A4A6A7A8A9ABACADAE",
"B0B1B2B3B5B6B7B8BABBBCBDBFC0C1C2C4C5C6C7C9CACBCCCECFD0D1D3D4D5D6",
"D8D9DADBDDDEDFE0E2E3E4E5E7E8E9EAECEDEEEFF1F2F3F4F6F7F8F9FBFCFDFE",
"00010203050607080A0B0C0D0F10111214151617191A1B1C1E1F202123242526",
"28292A2B2D2E2F30323334353738393A3C3D3E3F41424344464748494B4C4D4E",
"50515253555657585A5B5C5D5F60616264656667696A6B6C6E6F707173747576"];
var pts:Array = [
"506812A45F08C889B97F5980038B8359",
"5C6D71CA30DE8B8B00549984D2EC7D4B",
"53F3F4C64F8616E4E7C56199F48F21F6",
"A1EB65A3487165FB0F1C27FF9959F703",
"3553ECF0B1739558B08E350A98A39BFA",
"67429969490B9711AE2B01DC497AFDE8",
"93385C1F2AEC8BED192F5A8E161DD508",
"B5BF946BE19BEB8DB3983B5F4C6E8DDB",
"41321EE10E21BD907227C4450FF42324",
"00A82F59C91C8486D12C0A80124F6089",
"7CE0FD076754691B4BBD9FAF8A1372FE",
"23605A8243D07764541BC5AD355B3129",
"12A8CFA23EA764FD876232B4E842BC44",
"BCAF32415E8308B3723E5FDD853CCC80",
"89AFAE685D801AD747ACE91FC49ADDE0",
"F521D07B484357C4A69E76124A634216",
"3E23B3BC065BCC152407E23896D77783",
"79F0FBA002BE1744670E7E99290D8F52",
"DA23FE9D5BD63E1D72E3DAFBE21A6C2A",
"E3F5698BA90B6A022EFD7DB2C7E6C823",
"BDC2691D4F1B73D2700679C3BCBF9C6E",
"BA74E02093217EE1BA1B42BD5624349A",
"B5C593B5851C57FBF8B3F57715E8F680",
"3DA9BD9CEC072381788F9387C3BBF4EE",
"4197F3051121702AB65D316B3C637374",
"9F46C62EC4F6EE3F6E8C62554BC48AB7",
"0220673FE9E699A4EBC8E0DBEB6979C8",
"B2B99171337DED9BC8C2C23FF6F18867",
"A7FACF4E301E984E5EFEEFD645B23505",
"F7C762E4A9819160FD7ACFB6C4EEDCDD",
"9B64FC21EA08709F4915436FAA70F1BE",
"52AF2C3DE07EE6777F55A4ABFC100B3F",
"2FCA001224386C57AA3F968CBE2C816F",
"4149C73658A4A9C564342755EE2C132F",
"AF60005A00A1772F7C07A48A923C23D2",
"6FCCBC28363759914B6F0280AFAF20C6",
"7D82A43DDF4FEFA2FC5947499884D386",
"5D5A990EAAB9093AFE4CE254DFA49EF9",
"4CD1E2FD3F4434B553AAE453F0ED1A02",
"5A2C9A9641D4299125FA1B9363104B5E",
"B517FE34C0FA217D341740BFD4FE8DD4",
"014BAF2278A69D331D5180103643E99A",
"B529BD8164F20D0AA443D4932116841C",
"2E596DCBB2F33D4216A1176D5BD1E456",
"7274A1EA2B7EE2424E9A0E4673689143",
"AE20020BD4F13E9D90140BEE3B5D26AF",
"BAAC065DA7AC26E855E79C8849D75A02",
"7C917D8D1D45FAB9E2540E28832540CC",
"BDE6F89E16DAADB0E847A2A614566A91",
"C9DE163725F1F5BE44EBB1DB51D07FBC",
"3AF57A58F0C07DFFA669572B521E2B92",
"3D5EBAC306DDE4604F1B4FBBBFCDAE55",
"C2DFA91BCEB76A1183C995020AC0B556",
"C70F54305885E9A0746D01EC56C8596B",
"C4F81B610E98012CE000182050C0C2B2",
"EAAB86B1D02A95D7404EFF67489F97D4",
"7C55BDB40B88870B52BEC3738DE82886",
"BA6EAA88371FF0A3BD875E3F2A975CE0",
"08059130C4C24BD30CF0575E4E0373DC",
"9A8EAB004EF53093DFCF96F57E7EDA82",
"0745B589E2400C25F117B1D796C28129",
"2F1777781216CEC3F044F134B1B92BBE",
"353A779FFC541B3A3805D90CE17580FC",
"1A1EAE4415CEFCF08C4AC1C8F68BEA8F",
"E6E7E4E5B0B3B2B5D4D5AAAB16111013",
"F8F9FAFBFBF8F9E677767170EFE0E1E2",
"63626160A1A2A3A445444B4A75727370",
"717073720605040B2D2C2B2A05FAFBF9",
"78797A7BEAE9E8EF3736292891969794",
"838281803231300FDDDCDBDAA0AFAEAD",
"18191A1BBFBCBDBA75747B7A7F78797A",
"848586879B989996A3A2A5A4849B9A99",
"0001020322212027CACBF4F551565754",
"CECFCCCDAFACADB2515057564A454447",
"92939091CDCECFC813121D1C80878685",
"D2D3D0D16F6C6D6259585F5ED1EEEFEC",
"ACADAEAF878485820F0E1110D5D2D3D0",
"9091929364676619E6E7E0E1757A7B78",
"BABBB8B98A89888F74757A7B92959497",
"8D8C8F8E6E6D6C633B3A3D3CCAD5D4D7",
"86878485010203040808F7F767606162",
"8E8F8C8D656667788A8B8C8D010E0F0C",
"C8C9CACB858687807A7B7475E7E0E1E2",
"6D6C6F6E5053525D8C8D8A8BADD2D3D0",
"28292A2B393A3B3C0607181903040506",
"A5A4A7A6B0B3B28DDBDADDDCBDB2B3B0",
"323330316467666130313E3F2C2B2A29",
"27262524080B0A05171611100B141516",
"040506074142434435340B0AA3A4A5A6",
"242526271112130C61606766BDB2B3B0",
"4B4A4948252627209E9F9091CEC9C8CB",
"68696A6B6665646B9F9E9998D9E6E7E4",
"34353637C5C6C7C0F0F1EEEF7C7B7A79",
"32333031C2C1C13F0D0C0B0A050A0B08",
"CDCCCFCEBEBDBCBBABAAA5A4181F1E1D",
"212023223635343BA0A1A6A7445B5A59",
"0E0F0C0DA8ABAAAD2F2E515002050407",
"070605042A2928378E8F8889BDB2B3B0",
"CBCAC9C893909196A9A8A7A6A5A2A3A0",
"80818283C1C2C3CC9C9D9A9B0CF3F2F1",
"1213101125262720FAFBE4E5B1B6B7B4",
"7F7E7D7C3033320D97969190222D2C2F",
"4E4F4C4D484B4A4D81808F8E53545556",
"DCDDDEDFB0B3B2BD15141312A1BEBFBC",
"93929190282B2A2DC4C5FAFB92959497",
"F5F4F7F6C4C7C6D9373631307E717073",
"93929190B6B5B4B364656A6B05020300",
"BABBB8B90D0E0F00A4A5A2A3043B3A39",
"D8D9DADB7F7C7D7A10110E0F787F7E7D",
"FEFFFCFDEFECED923B3A3D3C6768696A",
"D6D7D4D58A89888F96979899A5A2A3A0",
"18191A1BA8ABAAA5303136379B848586",
"6B6A6968A4A7A6A1D6D72829B0B7B6B5",
"000102038A89889755545352A6A9A8AB",
"2D2C2F2EB3B0B1B6B6B7B8B9F2F5F4F7",
"979695943536373856575051E09F9E9D",
"A4A5A6A7989B9A9DB1B0AFAE7A7D7C7F",
"C1C0C3C2686B6A55A8A9AEAFEAE5E4E7",
"C1C0C3C2141716118C8D828364636261",
"93929190CCCFCEC196979091E0FFFEFD",
"B4B5B6B7F9FAFBFC25241B1A6E69686B",
"868784850704051AC7C6C1C08788898A",
"F4F5F6F7AAA9A8AFFDFCF3F277707172",
"D3D2D1D00605040BC3C2C5C43E010003",
"73727170424140476A6B74750D0A0B08",
"C2C3C0C10A0908F754555253A1AEAFAC",
"6D6C6F6EF8FBFAFD82838C8DF8FFFEFD",
"F5F4F7F684878689A6A7A0A1D2CDCCCF",
"2D33EEF2C0430A8A9EBF45E809C40BB6",
"6AA375D1FA155A61FB72353E0A5A8756",
"BC3736518B9490DCB8ED60EB26758ED4",
"AA214402B46CFFB9F761EC11263A311E",
"02AEA86E572EEAB66B2C3AF5E9A46FD6",
"E2AEF6ACC33B965C4FA1F91C75FF6F36",
"0659DF46427162B9434865DD9499F91D",
"49A44239C748FEB456F59C276A5658DF",
"66208F6E9D04525BDEDB2733B6A6BE37",
"3393F8DFC729C97F5480B950BC9666B0",
"606834C8CE063F3234CF1145325DBD71",
"FEC1C04F529BBD17D8CECFCC4718B17F",
"32DF99B431ED5DC5ACF8CAF6DC6CE475",
"7FDC2B746F3F665296943B83710D1F82",
"8FBA1510A3C5B87E2EAA3F7A91455CA2",
"2C9B468B1C2EED92578D41B0716B223B",
"0A2BBF0EFC6BC0034F8A03433FCA1B1A",
"25260E1F31F4104D387222E70632504B",
"C527D25A49F08A5228D338642AE65137",
"3B49FC081432F5890D0E3D87E884A69E",
"D173F9ED1E57597E166931DF2754A083",
"8C2B7CAFA5AFE7F13562DAEAE1ADEDE0",
"AAF4EC8C1A815AEB826CAB741339532C",
"40BE8C5D9108E663F38F1A2395279ECF",
"0C8AD9BC32D43E04716753AA4CFBE351",
"1407B1D5F87D63357C8DC7EBBAEBBFEE",
"E62734D1AE3378C4549E939E6F123416",
"5A752CFF2A176DB1A1DE77F2D2CDEE41",
"A9C8C3A4EABEDC80C64730DDD018CD88",
"EE9B3DBBDB86180072130834D305999A",
"A7FA8C3586B8EBDE7568EAD6F634A879",
"37E0F4A87F127D45AC936FE7AD88C10A",
"3F77D8B5D92BAC148E4E46F697A535C5",
"D25EBB686C40F7E2C4DA1014936571CA",
"4F1C769D1E5B0552C7ECA84DEA26A549",
"8548E2F882D7584D0FAFC54372B6633A",
"87D7A336CB476F177CD2A51AF2A62CDF",
"03B1FEAC668C4E485C1065DFC22B44EE",
"BDA15E66819FA72D653A6866AA287962",
"4D0C7A0D2505B80BF8B62CEB12467F0A",
"626D34C9429B37211330986466B94E5F",
"333C3E6BF00656B088A17E5FF0E7F60A",
"687ED0CDC0D2A2BC8C466D05EF9D2891",
"487830E78CC56C1693E64B2A6660C7B6",
"7A48D6B7B52B29392AA2072A32B66160",
"907320E64C8C5314D10F8D7A11C8618D",
"B561F2CA2D6E65A4A98341F3ED9FF533",
"DF769380D212792D026F049E2E3E48EF",
"79F374BC445BDABF8FCCB8843D6054C6",
"4E02F1242FA56B05C68DBAE8FE44C9D6",
"CF73C93CBFF57AC635A6F4AD2A4A1545",
"9923548E2875750725B886566784C625",
"4888336B723A022C9545320F836A4207",
"F84D9A5561B0608B1160DEE000C41BA8",
"C23192A0418E30A19B45AE3E3625BF22",
"B84E0690B28B0025381AD82A15E501A7",
"ACEF5E5C108876C4F06269F865B8F0B0",
"0F1B3603E0F5DDEA4548246153A5E064",
"FBB63893450D42B58C6D88CD3C1809E3",
"4BEF736DF150259DAE0C91354E8A5F92",
"7D2D46242056EF13D3C3FC93C128F4C7",
"E9C1BA2DF415657A256EDB33934680FD",
"E23EE277B0AA0A1DFB81F7527C3514F1",
"3E7445B0B63CAAF75E4A911E12106B4C",
"767774752023222544455A5BE6E1E0E3",
"72737475717E7F7CE9E8EBEA696A6B6C",
"DFDEDDDC25262728C9C8CFCEF1EEEFEC",
"FFFE0100707776755F5E5D5C7675746B",
"E0E1E2E3424140479F9E9190292E2F2C",
"2120272690EFEEED3B3A39384E4D4C4B",
"ECEDEEEF5350516EA1A0A7A6A3ACADAE",
"32333C3D25222320E9E8EBEACECDCCC3",
"40414243626160678A8BB4B511161714",
"94959293F5FAFBF81F1E1D1C7C7F7E79",
"BEBFBCBD191A1B14CFCEC9C8546B6A69",
"2C2D3233898E8F8CBBBAB9B8333031CE",
"84858687BFBCBDBA37363938FDFAFBF8",
"828384857669686B909192930B08090E",
"BEBFBCBD9695948B707176779E919093",
"8B8A85846067666521202322D0D3D2DD",
"76777475F1F2F3F4F8F9E6E777707172",
"A4A5A2A34F404142B4B5B6B727242522",
"94959697E1E2E3EC16171011839C9D9E",
"03023D3C06010003DEDFDCDDFFFCFDE2",
"10111213F1F2F3F4CECFC0C1DBDCDDDE",
"67666160724D4C4F1D1C1F1E73707176",
"E6E7E4E5A8ABAAD584858283909F9E9D",
"71707F7E565150537D7C7F7E6162636C",
"64656667212223245555AAAA03040506",
"9E9F9899ABA4A5A6CFCECDCC2B28292E",
"C7C6C5C4D1D2D3DC626364653A454447",
"F6F7E8E9E0E7E6E51D1C1F1E5B585966",
"BCBDBEBF5D5E5F5868696667F4F3F2F1",
"40414647B0AFAEAD9B9A99989B98999E",
"69686B6A0201001F0F0E0908B4BBBAB9",
"C7C6C9C8D8DFDEDD5A5B5859BEBDBCB3",
"DEDFDCDD787B7A7DFFFEE1E0B2B5B4B7",
"4D4C4B4A606F6E6DD0D1D2D3FBF8F9FE",
"B7B6B5B4D7D4D5DAE5E4E3E2E1FEFFFC",
"CECFB0B1F7F0F1F2AEAFACAD3E3D3C23",
"CACBC8C9CDCECFC812131C1D494E4F4C",
"9D9C9B9AD22D2C2FB1B0B3B20C0F0E09",
"7A7B787964676659959493924F404142",
"AAABA4A5CEC9C8CB1F1E1D1CABA8A9A6",
"93929190282B2A2DC4C5FAFB92959497",
"EFEEE9E8DED1D0D339383B3A888B8A8D",
"7F7E7D7CA2A1A0AF78797E7F112E2F2C",
"84859A9B2B2C2D2E868784852625245B",
"B0B1B2B3070405026869666710171615",
"ACADAAABBDA2A3A00D0C0F0E595A5B5C",
"121310115655544B5253545569666764",
"DEDFD0D166616063EAEBE8E94142434C",
"DBDAD9D81417161166677879E0E7E6E5",
"6A6B6C6DE0EFEEED2B2A2928C0C3C2C5",
"B1B0B3B21714151A1A1B1C1D5649484B",
"39380706A3A4A5A6C4C5C6C77271706F",
"5C5D5E5F1013121539383736E2E5E4E7",
"43424544EAD5D4D72E2F2C2D64676661",
"55545756989B9A65F8F9FEFF18171615",
"05040B0A525554573C3D3E3F4A494847",
"14151617595A5B5C8584FBFA8E89888B",
"7C7D7A7BFDF2F3F029282B2A51525354",
"38393A3B1E1D1C1341404746C23D3C3E",
"8D8C939240474645818083827C7F7E41",
"3B3A39381A19181F32333C3D45424340",
"F0F1F6F738272625828380817F7C7D7A",
"89888B8A0407061966676061141B1A19",
"D3D2DDDCAAADACAF9C9D9E9FE8EBEAE5",
"834EADFCCAC7E1B30664B1ABA44815AB",
"D9DC4DBA3021B05D67C0518F72B62BF1",
"A291D86301A4A739F7392173AA3C604C",
"4264B2696498DE4DF79788A9F83E9390",
"EE9932B3721804D5A83EF5949245B6F6",
"E6248F55C5FDCBCA9CBBB01C88A2EA77",
"B8358E41B9DFF65FD461D55A99266247",
"F0E2D72260AF58E21E015AB3A4C0D906",
"475B8B823CE8893DB3C44A9F2A379FF7",
"688F5281945812862F5F3076CF80412F",
"08D1D2BC750AF553365D35E75AFACEAA",
"8707121F47CC3EFCECA5F9A8474950A1",
"E51AA0B135DBA566939C3B6359A980C5",
"069A007FC76A459F98BAF917FEDF9521",
"726165C1723FBCF6C026D7D00B091027",
"D7C544DE91D55CFCDE1F84CA382200CE",
"FED3C9A161B9B5B2BD611B41DC9DA357",
"4F634CDC6551043409F30B635832CF82",
"109CE98DB0DFB36734D9F3394711B4E6",
"4EA6DFABA2D8A02FFDFFA89835987242",
"5AE094F54AF58E6E3CDBF976DAC6D9EF",
"764D8E8E0F29926DBE5122E66354FDBE",
"3F0418F888CDF29A982BF6B75410D6A9",
"E4A3E7CB12CDD56AA4A75197A9530220",
"211677684AAC1EC1A160F44C4EBF3F26",
"D21E439FF749AC8F18D6D4B105E03895",
"D9F6FF44646C4725BD4C0103FF5552A7",
"0B1256C2A00B976250CFC5B0C37ED382",
"B056447FFC6DC4523A36CC2E972A3A79",
"5E25CA78F0DE55802524D38DA3FE4456",
"A5BCF4728FA5EAAD8567C0DC24675F83",
"814E59F97ED84646B78B2CA022E9CA43",
"15478BEEC58F4775C7A7F5D4395514D7",
"253548FFCA461C67C8CBC78CD59F4756",
"FD7AD8D73B9B0F8CC41600640F503D65",
"06199DE52C6CBF8AF954CD65830BCD56",
"F17C4FFE48E44C61BD891E257E725794",
"9A5B4A402A3E8A59BE6BF5CD8154F029",
"79BD40B91A7E07DC939D441782AE6B17",
"D8CEAAF8976E5FBE1012D8C84F323799",
"3316E2751E2E388B083DA23DD6AC3FBE",
"8B7CFBE37DE7DCA793521819242C5816",
"F23F033C0EEBF8EC55752662FD58CE68",
"59EB34F6C8BDBACC5FC6AD73A59A1301",
"DCDE8B6BD5CF7CC22D9505E3CE81261A",
"E33CF7E524FED781E7042FF9F4B35DC7",
"27963C8FACDF73062867D164DF6D064C",
"77B1CE386B551B995F2F2A1DA994EEF8",
"F083388B013679EFCF0BB9B15D52AE5C",
"C5009E0DAB55DB0ABDB636F2600290C8",
"7804881E26CD532D8514D3683F00F1B9",
"46CDDCD73D1EB53E675CA012870A92A3",
"A9FB44062BB07FE130A8E8299EACB1AB",
"2B6FF8D7A5CC3A28A22D5A6F221AF26B",
"1A9527C29B8ADD4B0E3E656DBB2AF8B4",
"7F99CF2C75244DF015EB4B0C1050AEAE",
"E84FF85B0D9454071909C1381646C4ED",
"89AFD40F99521280D5399B12404F6DB4",
"A09EF32DBC5119A35AB7FA38656F0329",
"61773457F068C376C7829B93E696E716",
"A34F0CAE726CCE41DD498747D891B967",
"856F59496C7388EE2D2B1A27B7697847",
"CB090C593EF7720BD95908FB93B49DF4",
"A0AC75CD2F1923D460FC4D457AD95BAF",
"2A2B282974777689E8E9EEEF525D5C5F",
"909192939390919E0F0E09089788898A",
"777675748D8E8F907170777649464744",
"717073720605040B2D2C2B2A05FAFBF9",
"64656667FEFDFCC31B1A1D1CA5AAABA8",
"DBDAD9D86A696867B5B4B3B2C8D7D6D5",
"5C5D5E5FE3E0E1FE31303736333C3D3E",
"545556574B48494673727574546B6A69",
"ECEDEEEFC6C5C4BB56575051F5FAFBF8",
"464744452724252AC9C8CFCED2CDCCCF",
"E6E7E4E54142435C878681801C131211",
"72737071CFCCCDC2F9F8FFFE710E0F0C",
"505152537370714EC3C2C5C4010E0F0C",
"A8A9AAAB5C5F5E51AEAFA8A93D222320",
"DEDFDCDDF6F5F4EB10111617FEF1F0F3",
"BDBCBFBE5E5D5C530B0A0D0CFAC5C4C7",
"8A8B8889050606F8F4F5F2F3636C6D6E",
"A6A7A4A54D4E4F40B2B3B4B539262724",
"9C9D9E9FE9EAEBF40E0F08099B949596",
"2D2C2F2E1013121DCCCDCACBED121310",
"F4F5F6F7EDEEEFD0EAEBECEDF7F8F9FA",
"3D3C3F3E282B2A2573727574150A0B08",
"B6B7B4B5F8FBFAE5B4B5B2B3A0AFAEAD",
"B7B6B5B4989B9A95878681809BA4A5A6",
"A8A9AAABE5E6E798E9E8EFEE4748494A",
"ECEDEEEFD9DADBD4B9B8BFBE657A7B78",
"7F7E7D7C696A6B74CACBCCCD929D9C9F",
"08090A0B0605040BFFFEF9F8B9C6C7C4",
"08090A0BF1F2F3CCFCFDFAFB68676665",
"CACBC8C93A393837050403020D121310",
"E9E8EBEA8281809F8F8E8988343B3A39",
"515053524645444BD0D1D6D7340B0A09",
"42434041ECEFEE1193929594C6C9C8CB",
"EFEEEDECC2C1C0CF76777071455A5B58",
"5F5E5D5C3F3C3D221D1C1B1A19161714",
"000102034142434C1C1D1A1B8D727371",
"8E8F8C8DB1B2B38C56575051050A0B08",
"A7A6A5A4E8EBEAE57F7E7978CAD5D4D7",
"8A8B888994979689454443429F909192",
"8C8D8E8FE0E3E2ED45444342F1CECFCC",
"FFFEFDFC4C4F4E31D8D9DEDFB6B9B8BB",
"FDFCFFFECCCFCEC12F2E29286679787B",
"67666564BAB9B8A77071767719161714",
"9A9B98992D2E2F2084858283245B5A59",
"A4A5A6A70B0809365C5D5A5B2C232221",
"464744455754555AF3F2F5F4AFB0B1B2",
"323330317675746B7273747549464744",
"A8A9AAAB181B1A15808186872B141516",
"E7E6E5E4202323DDAAABACAD343B3A39",
"A8A9AAAB2221202FEDECEBEA1E010003",
"F9F8FBFA5F5C5D42424344450E010003",
"57565554F5F6F7F89697909120DFDEDD",
"F8F9FAFBCCCFCEF1DDDCDBDA0E010003",
"D9D8DBDA7073727D80818687C2DDDCDF",
"C5C4C7C6080B0A1588898E8F68676665",
"83828180DCDFDED186878081F0CFCECD",
"98999A9BDDDEDFA079787F7E0A050407",
"CECFCCCD4F4C4D429F9E9998DFC0C1C2",
"404142436665647B29282F2EABA4A5A6",
"33323130E6E5E4EB23222524DEA1A0A3",
"CFCECDCCF6F5F4CBE6E7E0E199969794",
"BABBB8B97271707FDCDDDADB29363734",
"C9C8CBCA4447465926272021545B5A59",
"050407067477767956575051221D1C1F"];
var cts:Array = [
"D8F532538289EF7D06B506A4FD5BE9C9",
"59AB30F4D4EE6E4FF9907EF65B1FB68C",
"BF1ED2FCB2AF3FD41443B56D85025CB1",
"7316632D5C32233EDCB0780560EAE8B2",
"408C073E3E2538072B72625E68B8364B",
"E1F94DFA776597BEACA262F2F6366FEA",
"F29E986C6A1C27D7B29FFD7EE92B75F1",
"131C886A57F8C2E713ABA6955E2B55B5",
"D2AB7662DF9B8C740210E5EEB61C199D",
"14C10554B2859C484CAB5869BBE7C470",
"DB4D498F0A49CF55445D502C1F9AB3B5",
"6D96FEF7D66590A77A77BB2056667F7F",
"316FB68EDBA736C53E78477BF913725C",
"6936F2B93AF8397FD3A771FC011C8C37",
"F3F92F7A9C59179C1FCC2C2BA0B082CD",
"6A95EA659EE3889158E7A9152FF04EBC",
"1959338344E945670678A5D432C90B93",
"E49BDDD2369B83EE66E6C75A1161B394",
"D3388F19057FF704B70784164A74867D",
"23AA03E2D5E4CD24F3217E596480D1E1",
"C84113D68B666AB2A50A8BDB222E91B9",
"AC02403981CD4340B507963DB65CB7B6",
"8D1299236223359474011F6BF5088414",
"5A1D6AB8605505F7977E55B9A54D9B90",
"72E9C2D519CF555E4208805AABE3B258",
"A8F3E81C4A23A39EF4D745DFFE026E80",
"546F646449D31458F9EB4EF5483AEE6C",
"4DBE4BC84AC797C0EE4EFB7F1A07401C",
"25E10BFB411BBD4D625AC8795C8CA3B3",
"315637405054EC803614E43DEF177579",
"60C5BC8A1410247295C6386C59E572A8",
"01366FC8CA52DFE055D6A00A76471BA6",
"ECC46595516EC612449C3F581E7D42FF",
"6B7FFE4C602A154B06EE9C7DAB5331C9",
"7DA234C14039A240DD02DD0FBF84EB67",
"C7DC217D9E3604FFE7E91F080ECD5A3A",
"37785901863F5C81260EA41E7580CDA5",
"A07B9338E92ED105E6AD720FCCCE9FE4",
"AE0FB9722418CC21A7DA816BBC61322C",
"C826A193080FF91FFB21F71D3373C877",
"1181B11B0E494E8D8B0AA6B1D5AC2C48",
"6743C3D1519AB4F2CD9A78AB09A511BD",
"DC55C076D52BACDF2EEFD952946A439D",
"711B17B590FFC72B5C8E342B601E8003",
"19983BB0950783A537E1339F4AA21C75",
"3BA7762E15554169C0F4FA39164C410C",
"A0564C41245AFCA7AF8AA2E0E588EA89",
"5E36A42A2E099F54AE85ECD92E2381ED",
"770036F878CD0F6CA2268172F106F2FE",
"7E4E03908B716116443CCF7C94E7C259",
"482735A48C30613A242DD494C7F9185D",
"B4C0F6C9D4D7079ADDF9369FC081061D",
"D5810FE0509AC53EDCD74F89962E6270",
"03F17A16B3F91848269ECDD38EBB2165",
"DA1248C3180348BAD4A93B4D9856C9DF",
"3D10D7B63F3452C06CDF6CCE18BE0C2C",
"4AB823E7477DFDDC0E6789018FCB6258",
"E6478BA56A77E70CFDAA5C843ABDE30E",
"1673064895FBEAF7F09C5429FF75772D",
"4488033AE9F2EFD0CA9383BFCA1A94E9",
"978F3B8C8F9D6F46626CAC3C0BCB9217",
"E08C8A7E582E15E5527F1D9E2EECB236",
"CEC155B76AC5FFDA4CF4F9CA91E49A7A",
"D5AC7165763225DD2A38CDC6862C29AD",
"03680FE19F7CE7275452020BE70E8204",
"461DF740C9781C388E94BB861CEB54F6",
"451BD60367F96483042742219786A074",
"E4DFA42671A02E57EF173B85C0EA9F2B",
"ED11B89E76274282227D854700A78B9E",
"433946EAA51EA47AF33895F2B90B3B75",
"6BC6D616A5D7D0284A5910AB35022528",
"D2A920ECFE919D354B5F49EAE9719C98",
"3A061B17F6A92885EFBD0676985B373D",
"FADEEC16E33EA2F4688499D157E20D8F",
"5CDEFEDE59601AA3C3CDA36FA6B1FA13",
"9574B00039844D92EBBA7EE8719265F8",
"9A9CF33758671787E5006928188643FA",
"2CDDD634C846BA66BB46CBFEA4A674F9",
"D28BAE029393C3E7E26E9FAFBBB4B98F",
"EC27529B1BEE0A9AB6A0D73EBC82E9B7",
"3CB25C09472AFF6EE7E2B47CCD7CCB17",
"DEE33103A7283370D725E44CA38F8FE5",
"27F9BCD1AAC64BFFC11E7815702C1A69",
"5DF534FFAD4ED0749A9988E9849D0021",
"A48BEE75DB04FB60CA2B80F752A8421B",
"024C8CF70BC86EE5CE03678CB7AF45F9",
"3C19AC0F8A3A3862CE577831301E166B",
"C5E355B796A57421D59CA6BE82E73BCA",
"D94033276417ABFB05A69D15B6E386E2",
"24B36559EA3A9B9B958FE6DA3E5B8D85",
"20FD4FEAA0E8BF0CCE7861D74EF4CB72",
"350E20D5174277B9EC314C501570A11D",
"87A29D61B7C604D238FE73045A7EFD57",
"2C3164C1CC7D0064816BDC0FAA362C52",
"195FE5E8A05A2ED594F6E4400EEE10B3",
"E4663DF19B9A21A5A284C2BD7F905025",
"21B88714CFB4E2A933BD281A2C4743FD",
"CBFC3980D704FD0FC54378AB84E17870",
"BC5144BAA48BDEB8B63E22E03DA418EF",
"5A1DBAEF1EE2984B8395DA3BDFFA3CCC",
"F0B11CD0729DFCC80CEC903D97159574",
"9F95314ACFDDC6D1914B7F19A9CC8209",
"595736F6F0F70914A94E9E007F022519",
"1F19F57892CAE586FCDFB4C694DEB183",
"540700EE1F6F3DAB0B3EDDF6CAEE1EF5",
"14A342A91019A331687A2254E6626CA2",
"7B25F3C3B2EEA18D743EF283140F29FF",
"46C2587D66E5E6FA7F7CA6411AD28047",
"09470E72229D954ED5EE73886DFEEBA9",
"D77C03DE92D4D0D79EF8D4824EF365EB",
"1D190219F290E0F1715D152D41A23593",
"A2CD332CE3A0818769616292E87F757B",
"D54AFA6CE60FBF9341A3690E21385102",
"06E5C364DED628A3F5E05E613E356F46",
"EAE63C0E62556DAC85D221099896355A",
"1FED060E2C6FC93EE764403A889985A2",
"C25235C1A30FDEC1C7CB5C5737B2A588",
"796DBEF95147D4D30873AD8B7B92EFC0",
"CBCF0FB34D98D0BD5C22CE37211A46BF",
"94B44DA6466126CAFA7C7FD09063FC24",
"D78C5B5EBF9B4DBDA6AE506C5074C8FE",
"6C27444C27204B043812CF8CF95F9769",
"BE94524EE5A2AA50BBA8B75F4C0AEBCF",
"A0AEAAE91BA9F31F51AEB3588CF3A39E",
"275297779C28266EF9FE4C6A13C08488",
"86523D92BB8672CB01CF4A77FD725882",
"4B8327640E9F33322A04DD96FCBF9A36",
"CE52AF650D088CA559425223F4D32694",
"DFF4945E0336DF4C1C56BC700EFF837F",
"B6FDDEF4752765E347D5D2DC196D1252",
"D23684E3D963B3AFCF1A114ACA90CBD6",
"3A7AC027753E2A18C2CEAB9E17C11FD0",
"8F6786BD007528BA26603C1601CDD0D8",
"D17D073B01E71502E28B47AB551168B3",
"A469DA517119FAB95876F41D06D40FFA",
"6091AA3B695C11F5C0B6AD26D3D862FF",
"70F9E67F9F8DF1294131662DC6E69364",
"D154DCAFAD8B207FA5CBC95E9996B559",
"4934D541E8B46FA339C805A7AEB9E5DA",
"62564C738F3EFE186E1A127A0C4D3C61",
"07805AA043986EB23693E23BEF8F3438",
"DF0B4931038BADE848DEE3B4B85AA44B",
"592D5FDED76582E4143C65099309477C",
"C9B8D6545580D3DFBCDD09B954ED4E92",
"5DCCD5D6EB7C1B42ACB008201DF707A0",
"A2A91682FFEB6ED1D34340946829E6F9",
"E45D185B797000348D9267960A68435D",
"45E060DAE5901CDA8089E10D4F4C246B",
"F6951AFACC0079A369C71FDCFF45DF50",
"9E95E00F351D5B3AC3D0E22E626DDAD6",
"9CB566FF26D92DAD083B51FDC18C173C",
"C9C82766176A9B228EB9A974A010B4FB",
"D8E26AA02945881D5137F1C1E1386E88",
"C0E024CCD68FF5FFA4D139C355A77C55",
"0B18B3D16F491619DA338640DF391D43",
"DBE09AC8F66027BF20CB6E434F252EFC",
"6D04E5E43C5B9CBE05FEB9606B6480FE",
"DD1D6553B96BE526D9FEE0FBD7176866",
"0260CA7E3F979FD015B0DD4690E16D2A",
"9893734DE10EDCC8A67C3B110B8B8CC6",
"93B30B750516B2D18808D710C2EE84EF",
"16F65FA47BE3CB5E6DFE7C6C37016C0E",
"F3847210D5391E2360608E5ACB560581",
"8754462CD223366D0753913E6AF2643D",
"1EA20617468D1B806A1FD58145462017",
"3B155D927355D737C6BE9DDA60136E2E",
"26144F7B66DAA91B6333DBD3850502B3",
"E4F9A4AB52CED8134C649BF319EBCC90",
"B9DDD29AC6128A6CAB121E34A4C62B36",
"6FCDDAD898F2CE4EFF51294F5EAAF5C9",
"C9A6FE2BF4028080BEA6F7FC417BD7E3",
"6A2026846D8609D60F298A9C0673127F",
"2CB25C005E26EFEA44336C4C97A4240B",
"496967AB8680DDD73D09A0E4C7DCC8AA",
"D5AF94DE93487D1F3A8C577CB84A66A4",
"84BDAC569CAE2828705F267CC8376E90",
"F7401DDA5AD5AB712B7EB5D10C6F99B6",
"1C9D54318539EBD4C3B5B7E37BF119F0",
"ACA572D65FB2764CFFD4A6ECA090EA0D",
"36D9C627B8C2A886A10CCB36EAE3DFBB",
"010EDBF5981E143A81D646E597A4A568",
"8DB44D538DC20CC2F40F3067FD298E60",
"930EB53BC71E6AC4B82972BDCD5AAFB3",
"6C42A81EDCBC9517CCD89C30C95597B4",
"DA389847AD06DF19D76EE119C71E1DD3",
"E018FDAE13D3118F9A5D1A647A3F0462",
"2AA65DB36264239D3846180FABDFAD20",
"1472163E9A4F780F1CEB44B07ECF4FDB",
"C8273FDC8F3A9F72E91097614B62397C",
"66C8427DCD733AAF7B3470CB7D976E3F",
"146131CB17F1424D4F8DA91E6F80C1D0",
"2610D0AD83659081AE085266A88770DC",
"38A2B5A974B0575C5D733917FB0D4570",
"E21D401EBC60DE20D6C486E4F39A588B",
"E51D5F88C670B079C0CA1F0C2C4405A2",
"246A94788A642FB3D1B823C8762380C8",
"B80C391C5C41A4C3B30C68E0E3D7550F",
"B77C4754FC64EB9A1154A9AF0BB1F21C",
"FB554DE520D159A06BF219FC7F34A02F",
"A89FBA152D76B4927BEED160DDB76C57",
"5676EAB4A98D2E8473B3F3D46424247C",
"4E8F068BD7EDE52A639036EC86C33568",
"F0193C4D7AFF1791EE4C07EB4A1824FC",
"AC8686EECA9BA761AFE82D67B928C33F",
"5FAF8573E33B145B6A369CD3606AB2C9",
"31587E9944AB1C16B844ECAD0DF2E7DA",
"D017FECD91148ABA37F6F3068AA67D8A",
"788EF2F021A73CBA2794B616078A8500",
"5D1EF20DCED6BCBC12131AC7C54788AA",
"B3C8CF961FAF9EA05FDDE6D1E4D8F663",
"143075C70605861C7FAC6526199E459F",
"A5AE12EADE9A87268D898BFC8FC0252A",
"0924F7CF2E877A4819F5244A360DCEA9",
"3D9E9635AFCC3E291CC7AB3F27D1C99A",
"9D80FEEBF87510E2B8FB98BB54FD788C",
"5F9D1A082A1A37985F174002ECA01309",
"A390EBB1D1403930184A44B4876646E4",
"700FE918981C3195BB6C4BCB46B74E29",
"907984406F7BF2D17FB1EB15B673D747",
"C32A956DCFC875C2AC7C7CC8B8CC26E1",
"02646E2EBFA9B820CF8424E9B9B6EB51",
"621FDA3A5BBD54C6D3C685816BD4EAD8",
"D4E216040426DFAF18B152469BC5AC2F",
"9D0635B9D33B6CDBD71F5D246EA17CC8",
"10ABAD1BD9BAE5448808765583A2CC1A",
"6891889E16544E355FF65A793C39C9A8",
"CC735582E68072C163CD9DDF46B91279",
"C5C68B9AEEB7F878DF578EFA562F9574",
"5F4764395A667A47D73452955D0D2CE8",
"701448331F66106CEFDDF1EB8267C357",
"CB3EE56D2E14B4E1941666F13379D657",
"9FE16EFD18AB6E1981191851FEDB0764",
"3DC9BA24E1B223589B147ADCEB4C8E48",
"1C333032682E7D4DE5E5AFC05C3E483C",
"D593CC99A95AFEF7E92038E05A59D00A",
"51E7F96F53B4353923452C222134E1EC",
"4075B357A1A2B473400C3B25F32F81A4",
"302E341A3EBCD74F0D55F61714570284",
"57ABDD8231280DA01C5042B78CF76522",
"17F9EA7EEA17AC1ADF0E190FEF799E92",
"2E1BDD563DD87EE5C338DD6D098D0A7A",
"EB869996E6F8BFB2BFDD9E0C4504DBB2",
"C2E01549E9DECF317468B3E018C61BA8",
"8DA875D033C01DD463B244A1770F4A22",
"8BA0DCF3A186844F026D022F8839D696",
"E9691FF9A6CC6970E51670A0FD5B88C1",
"F2BAEC06FAEED30F88EE63BA081A6E5B",
"9C39D4C459AE5753394D6094ADC21E78",
"6345B532A11904502EA43BA99C6BD2B2",
"5FFAE3061A95172E4070CEDCE1E428C8",
"0A4566BE4CDF9ADCE5DEC865B5AB34CD",
"CA17FCCE79B7404F2559B22928F126FB",
"97CA39B849ED73A6470A97C821D82F58",
"8198CB06BC684C6D3E9B7989428DCF7A",
"F53C464C705EE0F28D9A4C59374928BD",
"9ADB3D4CCA559BB98C3E2ED73DBF1154",
"1946DABF6A03A2A2C3D0B05080AED6FC",
"5ED301D747D3CC715445EBDEC62F2FB4",
"6585C8F43D13A6BEAB6419FC5935B9D0",
"2A5B56A596680FCC0E05F5E0F151ECAE",
"F5D6FF414FD2C6181494D20C37F2B8C4",
"85399C01F59FFFB5204F19F8482F00B8",
"92097B4C88A041DDF98144BC8D22E8E7",
"89BD5B73B356AB412AEF9F76CEA2D65C",
"2536969093C55FF9454692F2FAC2F530",
"07FC76A872843F3F6E0081EE9396D637",
"E38BA8EC2AA741358DCC93E8F141C491",
"D028EE23E4A89075D0B03E868D7D3A42",
"8CD9423DFC459E547155C5D1D522E540",
"080E9517EB1677719ACF728086040AE3",
"7C1700211A3991FC0ECDED0AB3E576B0",
"DABCBCC855839251DB51E224FBE87435",
"68D56FAD0406947A4DD27A7448C10F1D",
"DA9A11479844D1FFEE24BBF3719A9925",
"5E4BA572F8D23E738DA9B05BA24B8D81",
"A115A2065D667E3F0B883837A6E903F8",
"3E9E90DC33EAC2437D86AD30B137E66E",
"01CE82D8FBCDAE824CB3C48E495C3692",
"0C9CFF163CE936FAAF083CFD3DEA3117",
"5131BA9BD48F2BBA85560680DF504B52",
"9DC503BBF09823AEC8A977A5AD26CCB2",
"9A6DB0C0862E506A9E397225884041D7",
"430BF9570804185E1AB6365FC6A6860C",
"3525EBC02F4886E6A5A3762813E8CE8A",
"07FA265C763779CCE224C7BAD671027B",
"E8B72B4E8BE243438C9FFF1F0E205872",
"109D4F999A0E11ACE1F05E6B22CBCB50",
"45A5E8D4C3ED58403FF08D68A0CC4029",
"196865964DB3D417B6BD4D586BCB7634",
"60436AD45AC7D30D99195F815D98D2AE",
"BB07A23F0B61014B197620C185E2CD75",
"5BC0B2850129C854423AFF0751FE343B",
"7541A78F96738E6417D2A24BD2BECA40",
"B0A303054412882E464591F1546C5B9E",
"778C06D8A355EEEE214FCEA14B4E0EEF",
"09614206D15CBACE63227D06DB6BEEBB",
"41B97FB20E427A9FDBBB358D9262255D",
"C1940F703D845F957652C2D64ABD7ADF",
"D2D44FCDAE5332343366DB297EFCF21B",
"EA8196B79DBE167B6AA9896E287EED2B",
"D6B0B0C4BA6C7DBE5ED467A1E3F06C2D",
"EC51EB295250C22C2FB01816FB72BCAE",
"ADED6630A07CE9C7408A155D3BD0D36F",
"697C9245B9937F32F5D1C82319F0363A",
"AAD5AD50C6262AAEC30541A1B7B5B19C",
"7D34B893855341EC625BD6875AC18C0D",
"7EF05105440F83862F5D780E88F02B41",
"C377C06403382061AF2C9C93A8E70DF6",
"1DBDB3FFDC052DACC83318853ABC6DE5",
"69A6EAB00432517D0BF483C91C0963C7",
"0797F41DC217C80446E1D514BD6AB197",
"9DFD76575902A637C01343C58E011A03",
"ACF4328AE78F34B9FA9B459747CC2658",
"B0479AEA12BAC4FE2384CF98995150C6",
"9DD52789EFE3FFB99F33B3DA5030109A",
"ABBB755E4621EF8F1214C19F649FB9FD",
"DA27FB8174357BCE2BED0E7354F380F9",
"C59A0663F0993838F6E5856593BDC5EF",
"ED60B264B5213E831607A99C0CE5E57E",
"E50548746846F3EB77B8C520640884ED",
"28282CC7D21D6A2923641E52D188EF0C",
"0DFA5B02ABB18E5A815305216D6D4F8E",
"7359635C0EECEFE31D673395FB46FB99",
"73C679F7D5AEF2745C9737BB4C47FB36",
"B192BD472A4D2EAFB786E97458967626",
"0EC327F6C8A2B147598CA3FDE61DC6A4",
"FC418EB3C41B859B38D4B6F646629729",
"30249E5AC282B1C981EA64B609F3A154",
"5E6E08646D12150776BB43C2D78A9703",
"FAEB3D5DE652CD3447DCEB343F30394A",
"A8E88706823F6993EF80D05C1C7B2CF0",
"8CED86677E6E00A1A1B15968F2D3CCE6",
"9FC7C23858BE03BDEBB84E90DB6786A9",
"B4FBD65B33F70D8CF7F1111AC4649C36",
"C5C32D5ED03C4B53CC8C1BD0EF0DBBF6",
"D1A7F03B773E5C212464B63709C6A891",
"6B7161D8745947AC6950438EA138D028",
"FD47A9F7E366EE7A09BC508B00460661",
"00D40B003DC3A0D9310B659B98C7E416",
"EEA4C79DCC8E2BDA691F20AC48BE0717",
"E78F43B11C204403E5751F89D05A2509",
"D0F0E3D1F1244BB979931E38DD1786EF",
"042E639DC4E1E4DDE7B75B749EA6F765",
"BC032FDD0EFE29503A980A7D07AB46A8",
"0C93AC949C0DA6446EFFB86183B6C910",
"E0D343E14DA75C917B4A5CEC4810D7C2",
"0EAFB821748408279B937B626792E619",
"FA1AC6E02D23B106A1FEF18B274A553F",
"0DADFE019CD12368075507DF33C1A1E9",
"3A0879B414465D9FFBAF86B33A63A1B9",
"62199FADC76D0BE1805D3BA0B7D914BF",
"1B06D6C5D333E742730130CF78E719B4",
"F1F848824C32E9DCDCBF21580F069329",
"1A09050CBD684F784D8E965E0782F28A",
"79C2969E7DED2BA7D088F3F320692360",
"091A658A2F7444C16ACCB669450C7B63",
"97C1E3A72CCA65FA977D5ED0E8A7BBFC",
"70C430C6DB9A17828937305A2DF91A2A",
"629553457FBE2479098571C7C903FDE8",
"A25B25A61F612669E7D91265C7D476BA",
"EB7E4E49B8AE0F024570DDA293254FED",
"38FE15D61CCA84516E924ADCE5014F67",
"3AD208492249108C9F3EBEB167AD0583",
"299BA9F9BF5AB05C3580FC26EDD1ED12",
"19DC705B857A60FB07717B2EA5717781",
"FFC8AEB885B5EFCAD06B6DBEBF92E76B",
"F58900C5E0B385253FF2546250A0142B",
"2EE67B56280BC462429CEE6E3370CBC1",
"20DB650A9C8E9A84AB4D25F7EDC8F03F",
"3C36DA169525CF818843805F25B78AE5",
"9A781D960DB9E45E37779042FEA51922",
"6560395EC269C672A3C288226EFDBA77",
"8C772B7A189AC544453D5916EBB27B9A",
"77CA5468CC48E843D05F78EED9D6578F",
"72CDCC71DC82C60D4429C9E2D8195BAA",
"8080D68CE60E94B40B5B8B69EEB35AFA",
"44222D3CDE299C04369D58AC0EBA1E8E",
"9B8721B0A8DFC691C5BC5885DBFCB27A",
"0DC015CE9A3A3414B5E62EC643384183",
"705715448A8DA412025CE38345C2A148",
"C32B5B0B6FBAE165266C569F4B6ECF0B",
"4DCA6C75192A01DDCA9476AF2A521E87",
"058691E627ECBC36AC07B6DB423BD698",
"7444527095838FE080FC2BCDD30847EB"];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var aes:AESKey = new AESKey(key);
aes.encrypt(pt);
var out:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
// now go back to plaintext.
aes.decrypt(pt);
out = Hex.fromArray(pt).toUpperCase();
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
}
}
}
}
\ No newline at end of file
/**
* ARC4Test
*
* A test class for ARC4
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import com.hurlant.crypto.prng.ARC4;
public class ARC4Test extends TestCase
{
public function ARC4Test(h:ITestHarness)
{
super(h, "ARC4 Test");
runTest(testLameVectors,"ARC4 Test Vectors");
h.endTestCase();
}
/**
* Sad test vectors pilfered from
* http://en.wikipedia.org/wiki/RC4
*/
public function testLameVectors():void {
var keys:Array = [
Hex.fromString("Key"),
Hex.fromString("Wiki"),
Hex.fromString("Secret")];
var pts:Array = [
Hex.fromString("Plaintext"),
Hex.fromString("pedia"),
Hex.fromString("Attack at dawn")];
var cts:Array = [
"BBF316E8D940AF0AD3",
"1021BF0420",
"45A01F645FC35B383552544B9BF5"];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var rc4:ARC4 = new ARC4(key);
rc4.encrypt(pt);
var out:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
// now go back to plaintext
rc4.init(key);
rc4.decrypt(pt);
out = Hex.fromArray(pt);
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
}
}
}
}
\ No newline at end of file
/**
* BigIntegerTest
*
* A test class for BigInteger
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.math.BigInteger;
import com.hurlant.util.Hex;
public class BigIntegerTest extends TestCase
{
public function BigIntegerTest(h:ITestHarness)
{
super(h, "BigInteger Tests");
runTest(testAdd, "BigInteger Addition");
h.endTestCase();
}
public function testAdd():void {
var n1:BigInteger = BigInteger.nbv(25);
var n2:BigInteger = BigInteger.nbv(1002);
var n3:BigInteger = n1.add(n2);
var v:int = n3.valueOf();
assert("25+1002 = "+v, 25+1002==v);
var p:BigInteger = new BigInteger(Hex.toArray("e564d8b801a61f47"));
var xp:BigInteger = new BigInteger(Hex.toArray("99246db2a3507fa"));
xp = xp.add(p);
assert("xp==eef71f932bdb2741", xp.toString(16)=="eef71f932bdb2741");
}
}
}
\ No newline at end of file
/**
* BlowFishKeyTest
*
* A test class for BlowFishKey
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.symmetric.BlowFishKey;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class BlowFishKeyTest extends TestCase
{
public function BlowFishKeyTest(h:ITestHarness)
{
super(h, "BlowFishKey Test");
runTest(testECB,"BlowFish ECB Test Vectors");
h.endTestCase();
}
/**
* Test vectors from http://www.schneier.com/code/vectors.txt
*/
public function testECB():void {
var keys:Array = [
"0000000000000000",
"FFFFFFFFFFFFFFFF",
"3000000000000000",
"1111111111111111",
"0123456789ABCDEF",
"1111111111111111",
"0000000000000000",
"FEDCBA9876543210",
"7CA110454A1A6E57",
"0131D9619DC1376E",
"07A1133E4A0B2686",
"3849674C2602319E",
"04B915BA43FEB5B6",
"0113B970FD34F2CE",
"0170F175468FB5E6",
"43297FAD38E373FE",
"07A7137045DA2A16",
"04689104C2FD3B2F",
"37D06BB516CB7546",
"1F08260D1AC2465E",
"584023641ABA6176",
"025816164629B007",
"49793EBC79B3258F",
"4FB05E1515AB73A7",
"49E95D6D4CA229BF",
"018310DC409B26D6",
"1C587F1C13924FEF",
"0101010101010101",
"1F1F1F1F0E0E0E0E",
"E0FEE0FEF1FEF1FE",
"0000000000000000",
"FFFFFFFFFFFFFFFF",
"0123456789ABCDEF",
"FEDCBA9876543210" ];
var pts:Array = [
"0000000000000000",
"FFFFFFFFFFFFFFFF",
"1000000000000001",
"1111111111111111",
"1111111111111111",
"0123456789ABCDEF",
"0000000000000000",
"0123456789ABCDEF",
"01A1D6D039776742",
"5CD54CA83DEF57DA",
"0248D43806F67172",
"51454B582DDF440A",
"42FD443059577FA2",
"059B5E0851CF143A",
"0756D8E0774761D2",
"762514B829BF486A",
"3BDD119049372802",
"26955F6835AF609A",
"164D5E404F275232",
"6B056E18759F5CCA",
"004BD6EF09176062",
"480D39006EE762F2",
"437540C8698F3CFA",
"072D43A077075292",
"02FE55778117F12A",
"1D9D5C5018F728C2",
"305532286D6F295A",
"0123456789ABCDEF",
"0123456789ABCDEF",
"0123456789ABCDEF",
"FFFFFFFFFFFFFFFF",
"0000000000000000",
"0000000000000000",
"FFFFFFFFFFFFFFFF" ];
var cts:Array = [
"4EF997456198DD78",
"51866FD5B85ECB8A",
"7D856F9A613063F2",
"2466DD878B963C9D",
"61F9C3802281B096",
"7D0CC630AFDA1EC7",
"4EF997456198DD78",
"0ACEAB0FC6A0A28D",
"59C68245EB05282B",
"B1B8CC0B250F09A0",
"1730E5778BEA1DA4",
"A25E7856CF2651EB",
"353882B109CE8F1A",
"48F4D0884C379918",
"432193B78951FC98",
"13F04154D69D1AE5",
"2EEDDA93FFD39C79",
"D887E0393C2DA6E3",
"5F99D04F5B163969",
"4A057A3B24D3977B",
"452031C1E4FADA8E",
"7555AE39F59B87BD",
"53C55F9CB49FC019",
"7A8E7BFA937E89A3",
"CF9C5D7A4986ADB5",
"D1ABB290658BC778",
"55CB3774D13EF201",
"FA34EC4847B268B2",
"A790795108EA3CAE",
"C39E072D9FAC631D",
"014933E0CDAFF6E4",
"F21E9A77B71C49BC",
"245946885754369A",
"6B5C5A9C5D9E0A5A" ];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var bf:BlowFishKey = new BlowFishKey(key);
bf.encrypt(pt);
var out:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
// now go back to plaintext
bf.decrypt(pt);
out = Hex.fromArray(pt).toUpperCase();
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
}
}
}
}
\ No newline at end of file
/**
* CBCModeTest
*
* A test class for CBCMode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.CBCMode;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.crypto.symmetric.XTeaKey;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class CBCModeTest extends TestCase
{
public function CBCModeTest(h:ITestHarness) {
super(h, "CBCMode Test");
runTest(testAES,"CBC AES Test Vectors");
runTest(testXTea,"CBC XTea Test Vectors");
//
runTest(testCBC_AES128, "CBC AES-128 Test Vectors");
runTest(testCBC_AES192, "CBC AES-192 Test Vectors");
runTest(testCBC_AES256, "CBC AES-256 Test Vectors");
h.endTestCase();
}
/**
* Hawt NIST Vectors: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
* Section F.2.1 and below.
*/
public function testCBC_AES128():void {
var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"7649abac8119b246cee98e9b12e9197d" +
"5086cb9b507219ee95db113a917678b2" +
"73bed6b8e3c1743b7116e69e22229516" +
"3ff1caa1681fac09120eca307586e1a7");
var cbc:CBCMode = new CBCMode(new AESKey(key), new NullPad);
cbc.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cbc.encrypt(src);
assert("CBC_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cbc.decrypt(src);
assert("CBC_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testCBC_AES192():void {
var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"4f021db243bc633d7178183a9fa071e8" +
"b4d9ada9ad7dedf4e5e738763f69145a" +
"571b242012fb7ae07fa9baac3df102e0" +
"08b0e27988598881d920a9e64f5615cd");
var cbc:CBCMode = new CBCMode(new AESKey(key), new NullPad);
cbc.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cbc.encrypt(src);
assert("CBC_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cbc.decrypt(src);
assert("CBC_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testCBC_AES256():void {
var key:ByteArray = Hex.toArray(
"603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"f58c4c04d6e5f1ba779eabfb5f7bfbd6" +
"9cfc4e967edb808d679f777bc6702c7d" +
"39f23369a9d9bacfa530e26304231461" +
"b2eb05e2c39be9fcda6c19078c6a9d1b");
var cbc:CBCMode = new CBCMode(new AESKey(key), new NullPad);
cbc.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cbc.encrypt(src);
assert("CBC_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cbc.decrypt(src);
assert("CBC_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
/**
* For now the main goal is to show we can decrypt what we encrypt in this mode.
* Eventually, this should get correlated with some well known vectors.
*/
public function testAES():void {
var keys:Array = [
"00010203050607080A0B0C0D0F101112",
"14151617191A1B1C1E1F202123242526"];
var cts:Array = [
"D8F532538289EF7D06B506A4FD5BE9C94894C5508A8D8E29AB600DB0261F0555A8FA287B89E65C0973F1F8283E70C72863FE1C8F1F782084CE05626E961A67B3",
"59AB30F4D4EE6E4FF9907EF65B1FB68C96890CE217689B1BE0C93ED51CF21BB5A0101A8C30714EC4F52DBC9C6F4126067D363F67ABE58463005E679B68F0B496"];
var pts:Array = [
"506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359",
"5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B"];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var aes:AESKey = new AESKey(key);
var cbc:CBCMode = new CBCMode(aes);
cbc.IV = Hex.toArray("00000000000000000000000000000000");
cbc.encrypt(pt);
var str:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+str, cts[i]==str);
// back to pt
cbc.decrypt(pt);
str = Hex.fromArray(pt).toUpperCase();
assert("comparing "+pts[i]+" to "+str, pts[i]==str);
}
}
public function testXTea():void {
var keys:Array=[
"00000000000000000000000000000000",
"2b02056806144976775d0e266c287843"];
var cts:Array = [
"2dc7e8d3695b0538d8f1640d46dca717790af2ab545e11f3b08e798eb3f17b1744299d4d20b534aa",
"790958213819878370eb8251ffdac371081c5a457fc42502c63910306fea150be8674c3b8e675516"];
var pts:Array=[
"0000000000000000000000000000000000000000000000000000000000000000",
"74657374206d652e74657374206d652e74657374206d652e74657374206d652e"];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var tea:XTeaKey = new XTeaKey(key);
var cbc:CBCMode = new CBCMode(tea);
cbc.IV = Hex.toArray("0000000000000000");
cbc.encrypt(pt);
var str:String = Hex.fromArray(pt);
assert("comparing "+cts[i]+" to "+str, cts[i]==str);
// now go back to plaintext.
cbc.decrypt(pt);
str = Hex.fromArray(pt);
assert("comparing "+pts[i]+" to "+str, pts[i]==str);
}
}
}
}
\ No newline at end of file
/**
* CFB8ModeTest
*
* A test class for CFB8Mode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.crypto.symmetric.CFB8Mode;
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.NullPad;
public class CFB8ModeTest extends TestCase
{
public function CFB8ModeTest(h:ITestHarness) {
super(h,"CBF8Mode Test");
runTest(testCFB8_AES128, "CFB-8 AES-128 Test Vectors");
runTest(testCFB8_AES192, "CFB-8 AES-192 Test Vectors");
runTest(testCFB8_AES256, "CFB-8 AES-192 Test Vectors");
h.endTestCase();
}
/**
* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
*/
public function testCFB8_AES128():void {
var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");
var pt:ByteArray = Hex.toArray("6bc1bee22e409f96e93d7e117393172aae2d");
var ct:ByteArray = Hex.toArray("3b79424c9c0dd436bace9e0ed4586a4f32b9");
var cfb8:CFB8Mode = new CFB8Mode(new AESKey(key), new NullPad);
cfb8.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cfb8.encrypt(src);
assert("CFB8_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cfb8.decrypt(src);
assert("CFB8_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testCFB8_AES192():void {
var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
var pt:ByteArray = Hex.toArray("6bc1bee22e409f96e93d7e117393172aae2d");
var ct:ByteArray = Hex.toArray("cda2521ef0a905ca44cd057cbf0d47a0678a");
var cfb8:CFB8Mode = new CFB8Mode(new AESKey(key), new NullPad);
cfb8.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cfb8.encrypt(src);
assert("CFB8_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cfb8.decrypt(src);
assert("CFB8_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testCFB8_AES256():void {
var key:ByteArray = Hex.toArray("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
var pt:ByteArray = Hex.toArray("6bc1bee22e409f96e93d7e117393172aae2d");
var ct:ByteArray = Hex.toArray("dc1f1a8520a64db55fcc8ac554844e889700");
var cfb8:CFB8Mode = new CFB8Mode(new AESKey(key), new NullPad);
cfb8.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cfb8.encrypt(src);
assert("CFB8_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cfb8.decrypt(src);
assert("CFB8_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
}
}
\ No newline at end of file
/**
* CFBModeTest
*
* A test class for CFBMode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.CFBMode;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class CFBModeTest extends TestCase
{
public function CFBModeTest(h:ITestHarness)
{
super(h, "CFBMode Test");
runTest(testCFB_AES128, "CFB AES-128 Test Vectors");
runTest(testCFB_AES192, "CFB AES-192 Test Vectors");
runTest(testCFB_AES256, "CFB AES-256 Test Vectors");
h.endTestCase();
}
/**
* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
*/
public function testCFB_AES128():void {
var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"3b3fd92eb72dad20333449f8e83cfb4a" +
"c8a64537a0b3a93fcde3cdad9f1ce58b" +
"26751f67a3cbb140b1808cf187a4f4df" +
"c04b05357c5d1c0eeac4c66f9ff7f2e6");
var cfb:CFBMode = new CFBMode(new AESKey(key), new NullPad);
cfb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cfb.encrypt(src);
assert("CFB_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cfb.decrypt(src);
assert("CFB_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testCFB_AES192():void {
var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"cdc80d6fddf18cab34c25909c99a4174" +
"67ce7f7f81173621961a2b70171d3d7a" +
"2e1e8a1dd59b88b1c8e60fed1efac4c9" +
"c05f9f9ca9834fa042ae8fba584b09ff");
var cfb:CFBMode = new CFBMode(new AESKey(key), new NullPad);
cfb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cfb.encrypt(src);
assert("CFB_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cfb.decrypt(src);
assert("CFB_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testCFB_AES256():void {
var key:ByteArray = Hex.toArray(
"603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"dc7e84bfda79164b7ecd8486985d3860" +
"39ffed143b28b1c832113c6331e5407b" +
"df10132415e54b92a13ed0a8267ae2f9" +
"75a385741ab9cef82031623d55b1e471");
var cfb:CFBMode = new CFBMode(new AESKey(key), new NullPad);
cfb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
cfb.encrypt(src);
assert("CFB_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
cfb.decrypt(src);
assert("CFB_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
}
}
\ No newline at end of file
/**
* CTRModeTest
*
* A test class for CTRMode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.crypto.symmetric.CTRMode;
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.NullPad;
public class CTRModeTest extends TestCase
{
public function CTRModeTest(h:ITestHarness)
{
super(h, "CTRMode Test");
runTest(testCTR_AES128, "CTR AES-128 Test Vectors");
runTest(testCTR_AES192, "CTR AES-192 Test Vectors");
runTest(testCTR_AES256, "CTR AES-256 Test Vectors");
h.endTestCase();
}
/**
* Vectors from http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38A.pdf
* Section F.5.1 and below.
*/
public function testCTR_AES128():void {
var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"874d6191b620e3261bef6864990db6ce" +
"9806f66b7970fdff8617187bb9fffdff" +
"5ae4df3edbd5d35e5b4f09020db03eab" +
"1e031dda2fbe03d1792170a0f3009cee");
var ctr:CTRMode = new CTRMode(new AESKey(key), new NullPad);
ctr.IV = Hex.toArray("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ctr.encrypt(src);
var hsrc:String = Hex.fromArray(src);
var hct:String = Hex.fromArray(ct);
assert("CTR_AES128 test 1: "+hsrc+" != "+hct, hsrc==hct);
ctr.decrypt(src);
hsrc = Hex.fromArray(src);
var hpt:String = Hex.fromArray(pt);
assert("CTR_AES128 test 2: "+hsrc+" != "+hpt, hsrc==hpt);
}
public function testCTR_AES192():void {
var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"1abc932417521ca24f2b0459fe7e6e0b" +
"090339ec0aa6faefd5ccc2c6f4ce8e94" +
"1e36b26bd1ebc670d1bd1d665620abf7" +
"4f78a7f6d29809585a97daec58c6b050");
var ctr:CTRMode = new CTRMode(new AESKey(key), new NullPad);
ctr.IV = Hex.toArray("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ctr.encrypt(src);
var hsrc:String = Hex.fromArray(src);
var hct:String = Hex.fromArray(ct);
assert("CTR_AES192 test 1: "+hsrc+" != "+hct, hsrc==hct);
ctr.decrypt(src);
hsrc = Hex.fromArray(src);
var hpt:String = Hex.fromArray(pt);
assert("CTR_AES192 test 2: "+hsrc+" != "+hpt, hsrc==hpt);
}
public function testCTR_AES256():void {
var key:ByteArray = Hex.toArray("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"601ec313775789a5b7a7f504bbf3d228" +
"f443e3ca4d62b59aca84e990cacaf5c5" +
"2b0930daa23de94ce87017ba2d84988d" +
"dfc9c58db67aada613c2dd08457941a6");
var ctr:CTRMode = new CTRMode(new AESKey(key), new NullPad);
ctr.IV = Hex.toArray("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ctr.encrypt(src);
var hsrc:String = Hex.fromArray(src);
var hct:String = Hex.fromArray(ct);
assert("CTR_AES256 test 1: "+hsrc+" != "+hct, hsrc==hct);
ctr.decrypt(src);
hsrc = Hex.fromArray(src);
var hpt:String = Hex.fromArray(pt);
assert("CTR_AES256 test 2: "+hsrc+" != "+hpt, hsrc==hpt);
}
}
}
\ No newline at end of file
/**
* DesKeyTest
*
* A test class for DesKey
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.symmetric.DESKey;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class DESKeyTest extends TestCase
{
public function DESKeyTest(h:ITestHarness)
{
super(h, "DESKey Test");
runTest(testECB,"DES ECB Test Vectors");
h.endTestCase();
}
/**
* Test vectors mostly grabbed from
* http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf
* (Appendix A and B)
* incomplete.
*/
public function testECB():void {
var keys:Array = [
"3b3898371520f75e", // grabbed from the output of some js implementation out there
"10316E028C8F3B4A", // appendix A vector
"0101010101010101", // appendix B Table 1, round 0
"0101010101010101", // round 1
"0101010101010101", // 2
"0101010101010101",
"0101010101010101",
"0101010101010101",
"0101010101010101",
"0101010101010101",
"0101010101010101", // round 8
"8001010101010101", // app B, tbl 2, round 0
"4001010101010101",
"2001010101010101",
"1001010101010101",
"0801010101010101",
"0401010101010101",
"0201010101010101",
"0180010101010101",
"0140010101010101", // round 8
];
var pts:Array = [
"0000000000000000", // js
"0000000000000000", // App A
"8000000000000000", // App B, tbl 1, rnd0
"4000000000000000",
"2000000000000000",
"1000000000000000",
"0800000000000000", // rnd 4
"0400000000000000",
"0200000000000000",
"0100000000000000",
"0080000000000000", // round 8
"0000000000000000", // App B, tbl2, rnd0
"0000000000000000",
"0000000000000000",
"0000000000000000",
"0000000000000000",
"0000000000000000",
"0000000000000000",
"0000000000000000",
"0000000000000000", // rnd 8
];
var cts:Array = [
"83A1E814889253E0", // js
"82DCBAFBDEAB6602", // App A
"95F8A5E5DD31D900", // App b, tbl 1, rnd 0
"DD7F121CA5015619",
"2E8653104F3834EA",
"4BD388FF6CD81D4F",
"20B9E767B2FB1456",
"55579380D77138EF",
"6CC5DEFAAF04512F",
"0D9F279BA5D87260",
"D9031B0271BD5A0A", // rnd 8
"95A8D72813DAA94D", // App B, tbl 2, rnd 0
"0EEC1487DD8C26D5",
"7AD16FFB79C45926",
"D3746294CA6A6CF3",
"809F5F873C1FD761",
"C02FAFFEC989D1FC",
"4615AA1D33E72F10",
"2055123350C00858",
"DF3B99D6577397C8", // rnd 8
];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var des:DESKey = new DESKey(key);
des.encrypt(pt);
var out:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
// now go back to plaintext
des.decrypt(pt);
out = Hex.fromArray(pt).toUpperCase();
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
}
}
}
}
\ No newline at end of file
/**
* ECBModeTest
*
* A test class for ECBMode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.ECBMode;
import com.hurlant.crypto.symmetric.NullPad;
import com.hurlant.crypto.symmetric.XTeaKey;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class ECBModeTest extends TestCase
{
public function ECBModeTest(h:ITestHarness) {
super(h, "ECBMode Test");
runTest(testAES,"ECB AES Test Vectors");
runTest(testXTea,"ECB XTea Test Vectors");
runTest(testECB_AES128,"ECB AES-128 Test Vectors");
runTest(testECB_AES192,"ECB AES-192 Test Vectors");
runTest(testECB_AES256,"ECB AES-256 Test Vectors");
h.endTestCase();
}
/**
* For now the main goal is to show we can decrypt what we encrypt in this mode.
* Eventually, this should get correlated with some well known vectors.
* yay. found hawt test vectors: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
*/
public function testECB_AES128():void {
var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"3ad77bb40d7a3660a89ecaf32466ef97" +
"f5d3d58503b9699de785895a96fdbaaf" +
"43b1cd7f598ece23881b00e3ed030688" +
"7b0c785e27e8ad3f8223207104725dd4");
var ecb:ECBMode = new ECBMode(new AESKey(key), new NullPad);
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ecb.encrypt(src);
assert("ECB_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
ecb.decrypt(src);
assert("ECB_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testECB_AES192():void {
var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"bd334f1d6e45f25ff712a214571fa5cc" +
"974104846d0ad3ad7734ecb3ecee4eef" +
"ef7afd2270e2e60adce0ba2face6444e" +
"9a4b41ba738d6c72fb16691603c18e0e");
var ecb:ECBMode = new ECBMode(new AESKey(key), new NullPad);
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ecb.encrypt(src);
assert("ECB_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
ecb.decrypt(src);
assert("ECB_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testECB_AES256():void {
var key:ByteArray = Hex.toArray(
"603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"f3eed1bdb5d2a03c064b5a7e3db181f8" +
"591ccb10d410ed26dc5ba74a31362870" +
"b6ed21b99ca6f4f9f153e7b1beafed1d" +
"23304b7a39f9f3ff067d8d8f9e24ecc7");
var ecb:ECBMode = new ECBMode(new AESKey(key), new NullPad);
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ecb.encrypt(src);
assert("ECB_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
ecb.decrypt(src);
assert("ECB_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
// crappier, older testing. keeping around for no good reason.
public function testAES():void {
var keys:Array = [
"00010203050607080A0B0C0D0F101112",
"14151617191A1B1C1E1F202123242526"];
var pts:Array = [
"506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359506812A45F08C889B97F5980038B8359",
"5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B5C6D71CA30DE8B8B00549984D2EC7D4B"];
var cts:Array = [
"D8F532538289EF7D06B506A4FD5BE9C9D8F532538289EF7D06B506A4FD5BE9C9D8F532538289EF7D06B506A4FD5BE9C96DE5F607AB7EB8202F3957703B04E8B5",
"59AB30F4D4EE6E4FF9907EF65B1FB68C59AB30F4D4EE6E4FF9907EF65B1FB68C59AB30F4D4EE6E4FF9907EF65B1FB68C2993487785CB1CFDA6BB4F0F345F76C7"];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var aes:AESKey = new AESKey(key);
var ecb:ECBMode = new ECBMode(aes);
ecb.encrypt(pt);
var str:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+str, cts[i]==str);
// back to pt
ecb.decrypt(pt);
str = Hex.fromArray(pt).toUpperCase();
assert("comparing "+pts[i]+" to "+str, pts[i]==str);
}
}
public function testXTea():void {
var keys:Array=[
"00000000000000000000000000000000",
"2b02056806144976775d0e266c287843"];
var pts:Array=[
"0000000000000000000000000000000000000000000000000000000000000000",
"74657374206d652e74657374206d652e74657374206d652e74657374206d652e"];
var cts:Array=[
"2dc7e8d3695b05382dc7e8d3695b05382dc7e8d3695b05382dc7e8d3695b053820578a874233632d",
"79095821381987837909582138198783790958213819878379095821381987830e4dc3c48b2edf32"];
// self-fullfilling vectors.
// oh well, at least I can decrypt what I produce. :(
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var tea:XTeaKey = new XTeaKey(key);
var ecb:ECBMode = new ECBMode(tea);
ecb.encrypt(pt);
var str:String = Hex.fromArray(pt);
assert("comparing "+cts[i]+" to "+str, cts[i]==str);
// now go back to plaintext.
ecb.decrypt(pt);
str = Hex.fromArray(pt);
assert("comparing "+pts[i]+" to "+str, pts[i]==str);
}
}
}
}
\ No newline at end of file
/**
* HMACTest
*
* A test class for HMAC
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.crypto.hash.SHA224;
import com.hurlant.crypto.hash.SHA256;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class HMACTest extends TestCase
{
public function HMACTest(h:ITestHarness)
{
super(h, "HMAC Test");
runTest(testHMAC_MD5,"HMAC MD5 Test Vectors");
runTest(testHMAC_SHA_1,"HMAC SHA-1 Test Vectors");
runTest(testHMAC_SHA_2,"HMAC SHA-224/SHA-256 Test Vectors");
runTest(testHMAC96_MD5,"HMAC-96 MD5 Test Vectors");
runTest(testHMAC96_SHA_1,"HMAC-96 SHA-1 Test Vectors");
runTest(testHMAC128_SHA_2,"HMAC-128 SHA-224/SHA-256 Test Vectors");
h.endTestCase();
}
/**
* Test vectors taking from RFC2202
* http://tools.ietf.org/html/rfc2202
* Yes, it's from an RFC, jefe! Now waddayawant?
*/
public function testHMAC_SHA_1():void {
var keys:Array = [
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
Hex.fromString("Jefe"),
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0102030405060708090a0b0c0d0e0f10111213141516171819",
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];
var pts:Array = [
Hex.fromString("Hi There"),
Hex.fromString("what do ya want for nothing?"),
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
Hex.fromString("Test With Truncation"),
Hex.fromString("Test Using Larger Than Block-Size Key - Hash Key First"),
Hex.fromString("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data")];
var cts:Array = [
"b617318655057264e28bc0b6fb378c8ef146be00",
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79",
"125d7342b9ac11cd91a39af48aa17b4f63f175d3",
"4c9007f4026250c6bc8414f9bf50c86c2d7235da",
"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04",
"aa4ae5e15272d00e95705637ce8a3b55ed402112",
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91"];
var hmac:HMAC = new HMAC(new SHA1());
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var digest:ByteArray = hmac.compute(key, pt);
assert("HMAC-SHA-1 test "+i, Hex.fromArray(digest) == cts[i]);
}
}
public function testHMAC96_SHA_1():void {
var hmac:HMAC = new HMAC(new SHA1, 96);
var key:ByteArray = Hex.toArray("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");
var pt:ByteArray = Hex.toArray(Hex.fromString("Test With Truncation"));
var ct:String = "4c1a03424b55e07fe7f27be1";
var digest:ByteArray = hmac.compute(key, pt);
assert("HMAC96-SHA-1 test", Hex.fromArray(digest) == ct);
}
public function testHMAC_MD5():void {
var keys:Array = [
Hex.fromString("Jefe"),
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0102030405060708090a0b0c0d0e0f10111213141516171819",
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];
var pts:Array = [
Hex.fromString("what do ya want for nothing?"),
Hex.fromString("Hi There"),
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
Hex.fromString("Test With Truncation"),
Hex.fromString("Test Using Larger Than Block-Size Key - Hash Key First"),
Hex.fromString("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data")];
var cts:Array = [
"750c783e6ab0b503eaa86e310a5db738",
"9294727a3638bb1c13f48ef8158bfc9d",
"56be34521d144c88dbb8c733f0e8b3f6",
"697eaf0aca3a3aea3a75164746ffaa79",
"56461ef2342edc00f9bab995690efd4c",
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd",
"6f630fad67cda0ee1fb1f562db3aa53e"];
var hmac:HMAC = new HMAC(new MD5());
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var digest:ByteArray = hmac.compute(key, pt);
assert("HMAC-MD5 test "+i, Hex.fromArray(digest) == cts[i]);
}
}
public function testHMAC96_MD5():void {
var hmac:HMAC = new HMAC(new MD5, 96);
var key:ByteArray = Hex.toArray("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");
var pt:ByteArray = Hex.toArray(Hex.fromString("Test With Truncation"));
var ct:String = "56461ef2342edc00f9bab995";
var digest:ByteArray = hmac.compute(key, pt);
assert("HMAC96-MD5 test", Hex.fromArray(digest) == ct);
}
/**
* Test vectors for HMAC-SHA-2 taken from RFC4231
* http://www.ietf.org/rfc/rfc4231.txt
* Still the same lame strings, but hidden in hex. why not.
*/
public function testHMAC_SHA_2():void {
var keys:Array = [
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"4a656665",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"0102030405060708090a0b0c0d0e0f10111213141516171819",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"];
var pts:Array = [
"4869205468657265",
"7768617420646f2079612077616e7420666f72206e6f7468696e673f",
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
"54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374",
"5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e"];
var cts224:Array = [
"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22",
"a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44",
"7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea",
"6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a",
"95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e",
"3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1"];
var cts256:Array = [
"b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
"773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
"82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
"60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
"9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"];
// 384 and 512 will be added. someday. if I ever figure how to do 64bit computations half efficiently in as3
var hmac224:HMAC = new HMAC(new SHA224);
var hmac256:HMAC = new HMAC(new SHA256);
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var digest224:ByteArray = hmac224.compute(key, pt);
assert("HMAC-SHA-224 test "+i, Hex.fromArray(digest224) == cts224[i]);
var digest256:ByteArray = hmac256.compute(key, pt);
assert("HMAC-SHA-256 test "+i, Hex.fromArray(digest256) == cts256[i]);
}
}
public function testHMAC128_SHA_2():void {
var hmac224:HMAC = new HMAC(new SHA224,128);
var hmac256:HMAC = new HMAC(new SHA256,128);
var key:ByteArray = Hex.toArray("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");
var pt:ByteArray = Hex.toArray("546573742057697468205472756e636174696f6e");
var ct224:String = "0e2aea68a90c8d37c988bcdb9fca6fa8";
var ct256:String = "a3b6167473100ee06e0c796c2955552b";
var digest224:ByteArray = hmac224.compute(key, pt);
assert("HMAC128-SHA-224 test", Hex.fromArray(digest224) == ct224);
var digest256:ByteArray = hmac256.compute(key, pt);
assert("HMAC128-SHA-256 test", Hex.fromArray(digest256) == ct256);
}
}
}
\ No newline at end of file
/**
* ITestHarness
*
* An interface to specify what's available for test cases to use.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
public interface ITestHarness
{
function beginTestCase(name:String):void;
function endTestCase():void;
function beginTest(name:String):void;
function passTest():void;
function failTest(msg:String):void;
}
}
\ No newline at end of file
/**
* MD2Test
*
* A test class for MD2
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.hash.MD2;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class MD2Test extends TestCase
{
public function MD2Test(h:ITestHarness)
{
super(h, "MD2 Test");
runTest(testMd2, "MD2 Test Vectors");
h.endTestCase();
}
/**
* Test Vectors grabbed from
* http://www.faqs.org/rfcs/rfc1319.html
*/
public function testMd2():void {
var srcs:Array = [
"",
Hex.fromString("a"),
Hex.fromString("abc"),
Hex.fromString("message digest"),
Hex.fromString("abcdefghijklmnopqrstuvwxyz"),
Hex.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
Hex.fromString("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
];
var hashes:Array = [
"8350e5a3e24c153df2275c9f80692773",
"32ec01ec4a6dac72c0ab96fb34c0b5d1",
"da853b0d3f88d99b30283a69e6ded6bb",
"ab4f496bfb2a530b219ff33031fe06b0",
"4e8ddff3650292ab5a4108c3aa47940b",
"da33def2a42df13975352846c30338cd",
"d5976f79d83d3a0dc9806c3c66f3efd8"
];
var md2:MD2 = new MD2;
for (var i:uint=0;i<srcs.length;i++) {
var src:ByteArray = Hex.toArray(srcs[i]);
var digest:ByteArray = md2.hash(src);
assert("MD2 Test "+i, Hex.fromArray(digest) == hashes[i]);
}
}
}
}
\ No newline at end of file
/**
* MD5Test
*
* A test class for MD5
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.hash.MD5;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class MD5Test extends TestCase
{
public function MD5Test(h:ITestHarness)
{
super(h, "MD5 Test");
runTest(testMd5,"MD5 Test Vectors");
h.endTestCase();
}
/**
* Test Vectors grabbed from
* http://www.faqs.org/rfcs/rfc1321.html
*/
public function testMd5():void {
var srcs:Array = [
"",
Hex.fromString("a"),
Hex.fromString("abc"),
Hex.fromString("message digest"),
Hex.fromString("abcdefghijklmnopqrstuvwxyz"),
Hex.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
Hex.fromString("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
];
var hashes:Array = [
"d41d8cd98f00b204e9800998ecf8427e",
"0cc175b9c0f1b6a831c399e269772661",
"900150983cd24fb0d6963f7d28e17f72",
"f96b697d7cb7938d525a2f31aaf161d0",
"c3fcd3d76192e4007dfb496cca67e13b",
"d174ab98d277d9f5a5611c2c9f419d9f",
"57edf4a22be3c955ac49da2e2107b67a"
];
var md5:MD5 = new MD5;
for (var i:uint=0;i<srcs.length;i++) {
var src:ByteArray = Hex.toArray(srcs[i]);
var digest:ByteArray = md5.hash(src);
assert("MD5 Test "+i, Hex.fromArray(digest) == hashes[i]);
}
}
}
}
\ No newline at end of file
/**
* OFBModeTest
*
* A test class for OFBMode
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.crypto.symmetric.OFBMode;
import com.hurlant.crypto.symmetric.AESKey;
import com.hurlant.crypto.symmetric.NullPad;
public class OFBModeTest extends TestCase
{
public function OFBModeTest(h:ITestHarness)
{
super(h, "OFBMode Test");
runTest(testOFB_AES128,"OFB AES-128 Test Vectors");
runTest(testOFB_AES192,"OFB AES-192 Test Vectors");
runTest(testOFB_AES256,"OFB AES-256 Test Vectors");
h.endTestCase();
}
/**
* Nist Vectors: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
* Section F.4.1 and below.
*/
public function testOFB_AES128():void {
var key:ByteArray = Hex.toArray("2b7e151628aed2a6abf7158809cf4f3c");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"3b3fd92eb72dad20333449f8e83cfb4a" +
"7789508d16918f03f53c52dac54ed825" +
"9740051e9c5fecf64344f7a82260edcc" +
"304c6528f659c77866a510d9c1d6ae5e");
var ofb:OFBMode = new OFBMode(new AESKey(key), new NullPad);
ofb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ofb.encrypt(src);
assert("OFB_AES128 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
ofb.decrypt(src);
assert("OFB_AES128 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testOFB_AES192():void {
var key:ByteArray = Hex.toArray("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"cdc80d6fddf18cab34c25909c99a4174" +
"fcc28b8d4c63837c09e81700c1100401" +
"8d9a9aeac0f6596f559c6d4daf59a5f2" +
"6d9f200857ca6c3e9cac524bd9acc92a");
var ofb:OFBMode = new OFBMode(new AESKey(key), new NullPad);
ofb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ofb.encrypt(src);
assert("OFB_AES192 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
ofb.decrypt(src);
assert("OFB_AES192 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
public function testOFB_AES256():void {
var key:ByteArray = Hex.toArray(
"603deb1015ca71be2b73aef0857d7781" +
"1f352c073b6108d72d9810a30914dff4");
var pt:ByteArray = Hex.toArray(
"6bc1bee22e409f96e93d7e117393172a" +
"ae2d8a571e03ac9c9eb76fac45af8e51" +
"30c81c46a35ce411e5fbc1191a0a52ef" +
"f69f2445df4f9b17ad2b417be66c3710");
var ct:ByteArray = Hex.toArray(
"dc7e84bfda79164b7ecd8486985d3860" +
"4febdc6740d20b3ac88f6ad82a4fb08d" +
"71ab47a086e86eedf39d1c5bba97c408" +
"0126141d67f37be8538f5a8be740e484");
var ofb:OFBMode = new OFBMode(new AESKey(key), new NullPad);
ofb.IV = Hex.toArray("000102030405060708090a0b0c0d0e0f");
var src:ByteArray = new ByteArray;
src.writeBytes(pt);
ofb.encrypt(src);
assert("OFB_AES256 test 1", Hex.fromArray(src)==Hex.fromArray(ct));
ofb.decrypt(src);
assert("OFB_AES256 test 2", Hex.fromArray(src)==Hex.fromArray(pt));
}
}
}
\ No newline at end of file
/**
* RSAKeyTest
*
* A test class for RSAKey
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.rsa.RSAKey;
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
import com.hurlant.util.der.PEM;
public class RSAKeyTest extends TestCase
{
public function RSAKeyTest(h:ITestHarness)
{
super(h, "RSA Testing");
runTest(testSmoke,"RSA smoke test");
runTest(testGenerate, "RSA Key Generation test");
runTest(testPEM, "RSA Private Key PEM parsing");
runTest(testPEM2, "RSA Public Key PEM parsing");
h.endTestCase();
}
public function testSmoke():void {
var N:String ="C4E3F7212602E1E396C0B6623CF11D26204ACE3E7D26685E037AD2507DCE82FC" +
"28F2D5F8A67FC3AFAB89A6D818D1F4C28CFA548418BD9F8E7426789A67E73E41";
var E:String = "10001";
var D:String = "7cd1745aec69096129b1f42da52ac9eae0afebbe0bc2ec89253598dcf454960e" +
"3e5e4ec9f8c87202b986601dd167253ee3fb3fa047e14f1dfd5ccd37e931b29d";
var P:String = "f0e4dd1eac5622bd3932860fc749bbc48662edabdf3d2826059acc0251ac0d3b";
var Q:String = "d13cb38fbcd06ee9bca330b4000b3dae5dae12b27e5173e4d888c325cda61ab3";
var DMP1:String = "b3d5571197fc31b0eb6b4153b425e24c033b054d22b9c8282254fe69d8c8c593";
var DMQ1:String = "968ffe89e50d7b72585a79b65cfdb9c1da0963cceb56c3759e57334de5a0ac3f";
var IQMP:String = "d9bc4f420e93adad9f007d0e5744c2fe051c9ed9d3c9b65f439a18e13d6e3908";
// create a key.
var rsa:RSAKey = RSAKey.parsePrivateKey(N,E,D, P,Q,DMP1,DMQ1,IQMP);
var txt:String = "hello";
var src:ByteArray = Hex.toArray(Hex.fromString(txt));
var dst:ByteArray = new ByteArray;
var dst2:ByteArray = new ByteArray;
rsa.encrypt(src, dst, src.length);
rsa.decrypt(dst, dst2, dst.length);
var txt2:String = Hex.toString(Hex.fromArray(dst2));
assert("rsa encrypt+decrypt", txt==txt2);
}
public function testGenerate():void {
var rsa:RSAKey = RSAKey.generate(256, "10001");
// same lame smoke test here.
var txt:String = "hello";
var src:ByteArray = Hex.toArray(Hex.fromString(txt));
var dst:ByteArray = new ByteArray;
var dst2:ByteArray = new ByteArray;
rsa.encrypt(src, dst, src.length);
rsa.decrypt(dst, dst2, dst.length);
var txt2:String = Hex.toString(Hex.fromArray(dst2));
assert("rsa encrypt+decrypt", txt==txt2);
}
public function testPEM():void {
var pem:String = "-----BEGIN RSA PRIVATE KEY-----\n" +
"MGQCAQACEQDJG3bkuB9Ie7jOldQTVdzPAgMBAAECEQCOGqcPhP8t8mX8cb4cQEaR\n" +
"AgkA5WTYuAGmH0cCCQDgbrto0i7qOQIINYr5btGrtccCCQCYy4qX4JDEMQIJAJll\n" +
"OnLVtCWk\n" +
"-----END RSA PRIVATE KEY-----";
var rsa:RSAKey = PEM.readRSAPrivateKey(pem);
//trace(rsa.dump());
// obligatory use
var txt:String = "hello";
var src:ByteArray = Hex.toArray(Hex.fromString(txt));
var dst:ByteArray = new ByteArray;
var dst2:ByteArray = new ByteArray;
rsa.encrypt(src, dst, src.length);
rsa.decrypt(dst, dst2, dst.length);
var txt2:String = Hex.toString(Hex.fromArray(dst2));
assert("rsa encrypt+decrypt", txt==txt2);
}
public function testPEM2():void {
var pem:String = "-----BEGIN PUBLIC KEY-----\n" +
"MCwwDQYJKoZIhvcNAQEBBQADGwAwGAIRAMkbduS4H0h7uM6V1BNV3M8CAwEAAQ==\n" +
"-----END PUBLIC KEY-----";
var rsa:RSAKey = PEM.readRSAPublicKey(pem);
//trace(rsa.dump());
}
}
}
\ No newline at end of file
/**
* SHA1Test
*
* A test class for SHA1
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class SHA1Test extends TestCase
{
public function SHA1Test(h:ITestHarness)
{
super(h, "SHA-1 Test");
runTest(testSha1,"SHA-1 Test Vectors");
runTest(testLongSha1,"SHA-1 Long Test Vectors");
h.endTestCase();
}
/**
* Test Vectors grabbed from
* http://csrc.nist.gov/cryptval/shs.htm
*/
public function testSha1():void {
var srcs:Array = [
"",
"a8",
"3000",
"42749e",
"9fc3fe08",
"b5c1c6f1af",
"e47571e5022e",
"3e1b28839fb758",
"a81350cbb224cb90",
"c243d167923dec3ce1",
"50ac18c59d6a37a29bf4",
"98e2b611ad3b1cccf634f6",
"73fe9afb68e1e8712e5d4eec",
"9e701ed7d412a9226a2a130e66",
"6d3ee90413b0a7cbf69e5e6144ca",
"fae24d56514efcb530fd4802f5e71f",
"c5a22dd6eda3fe2bdc4ddb3ce6b35fd1",
"d98cded2adabf08fda356445c781802d95",
"bcc6d7087a84f00103ccb32e5f5487a751a2",
"36ecacb1055434190dbbc556c48bafcb0feb0d",
"5ff9edb69e8f6bbd498eb4537580b7fba7ad31d0",
"c95b441d8270822a46a798fae5defcf7b26abace36",
"83104c1d8a55b28f906f1b72cb53f68cbb097b44f860",
"755175528d55c39c56493d697b790f099a5ce741f7754b",
"088fc38128bbdb9fd7d65228b3184b3faac6c8715f07272f",
"a4a586eb9245a6c87e3adf1009ac8a49f46c07e14185016895",
"8e7c555270c006092c2a3189e2a526b873e2e269f0fb28245256",
"a5f3bfa6bb0ba3b59f6b9cbdef8a558ec565e8aa3121f405e7f2f0",
"589054f0d2bd3c2c85b466bfd8ce18e6ec3e0b87d944cd093ba36469",
"a0abb12083b5bbc78128601bf1cbdbc0fdf4b862b24d899953d8da0ff3",
"82143f4cea6fadbf998e128a8811dc75301cf1db4f079501ea568da68eeb",
"9f1231dd6df1ff7bc0b0d4f989d048672683ce35d956d2f57913046267e6f3",
"041c512b5eed791f80d3282f3a28df263bb1df95e1239a7650e5670fc2187919",
"17e81f6ae8c2e5579d69dafa6e070e7111461552d314b691e7a3e7a4feb3fae418",
"d15976b23a1d712ad28fad04d805f572026b54dd64961fda94d5355a0cc98620cf77",
"09fce4d434f6bd32a44e04b848ff50ec9f642a8a85b37a264dc73f130f22838443328f",
"f17af27d776ec82a257d8d46d2b46b639462c56984cc1be9c1222eadb8b26594a25c709d",
"b13ce635d6f8758143ffb114f2f601cb20b6276951416a2f94fbf4ad081779d79f4f195b22",
"5498793f60916ff1c918dde572cdea76da8629ba4ead6d065de3dfb48de94d234cc1c5002910",
"498a1e0b39fa49582ae688cd715c86fbaf8a81b8b11b4d1594c49c902d197c8ba8a621fd6e3be5",
"3a36ae71521f9af628b3e34dcb0d4513f84c78ee49f10416a98857150b8b15cb5c83afb4b570376e",
"dcc76b40ae0ea3ba253e92ac50fcde791662c5b6c948538cffc2d95e9de99cac34dfca38910db2678f",
"5b5ec6ec4fd3ad9c4906f65c747fd4233c11a1736b6b228b92e90cddabb0c7c2fcf9716d3fad261dff33",
"df48a37b29b1d6de4e94717d60cdb4293fcf170bba388bddf7a9035a15d433f20fd697c3e4c8b8c5f590ab",
"1f179b3b82250a65e1b0aee949e218e2f45c7a8dbfd6ba08de05c55acfc226b48c68d7f7057e5675cd96fcfc",
"ee3d72da3a44d971578972a8e6780ce64941267e0f7d0179b214fa97855e1790e888e09fbe3a70412176cb3b54",
"d4d4c7843d312b30f610b3682254c8be96d5f6684503f8fbfbcd15774fc1b084d3741afb8d24aaa8ab9c104f7258",
"32c094944f5936a190a0877fb9178a7bf60ceae36fd530671c5b38c5dbd5e6a6c0d615c2ac8ad04b213cc589541cf6",
"e5d3180c14bf27a5409fa12b104a8fd7e9639609bfde6ee82bbf9648be2546d29688a65e2e3f3da47a45ac14343c9c02",
"e7b6e4b69f724327e41e1188a37f4fe38b1dba19cbf5a7311d6e32f1038e97ab506ee05aebebc1eed09fc0e357109818b9",
"bc880cb83b8ac68ef2fedc2da95e7677ce2aa18b0e2d8b322701f67af7d5e7a0d96e9e33326ccb7747cfff0852b961bfd475",
"235ea9c2ba7af25400f2e98a47a291b0bccdaad63faa2475721fda5510cc7dad814bce8dabb611790a6abe56030b798b75c944",
"07e3e29fed63104b8410f323b975fd9fba53f636af8c4e68a53fb202ca35dd9ee07cb169ec5186292e44c27e5696a967f5e67709",
"65d2a1dd60a517eb27bfbf530cf6a5458f9d5f4730058bd9814379547f34241822bf67e6335a6d8b5ed06abf8841884c636a25733f",
"dcc86b3bd461615bab739d8daafac231c0f462e819ad29f9f14058f3ab5b75941d4241ea2f17ebb8a458831b37a9b16dead4a76a9b0e",
"4627d54f0568dc126b62a8c35fb46a9ac5024400f2995e51635636e1afc4373dbb848eb32df23914230560b82477e9c3572647a7f2bb92",
"ba531affd4381168ef24d8b275a84d9254c7f5cc55fded53aa8024b2c5c5c8aa7146fe1d1b83d62b70467e9a2e2cb67b3361830adbab28d7",
"8764dcbcf89dcf4282eb644e3d568bdccb4b13508bfa7bfe0ffc05efd1390be22109969262992d377691eb4f77f3d59ea8466a74abf57b2ef4",
"497d9df9ddb554f3d17870b1a31986c1be277bc44feff713544217a9f579623d18b5ffae306c25a45521d2759a72c0459b58957255ab592f3be4",
"72c3c2e065aefa8d9f7a65229e818176eef05da83f835107ba90ec2e95472e73e538f783b416c04654ba8909f26a12db6e5c4e376b7615e4a25819",
"7cc9894454d0055ab5069a33984e2f712bef7e3124960d33559f5f3b81906bb66fe64da13c153ca7f5cabc89667314c32c01036d12ecaf5f9a78de98",
"74e8404d5a453c5f4d306f2cfa338ca65501c840ddab3fb82117933483afd6913c56aaf8a0a0a6b2a342fc3d9dc7599f4a850dfa15d06c61966d74ea59",
"46fe5ed326c8fe376fcc92dc9e2714e2240d3253b105adfbb256ff7a19bc40975c604ad7c0071c4fd78a7cb64786e1bece548fa4833c04065fe593f6fb10",
"836dfa2524d621cf07c3d2908835de859e549d35030433c796b81272fd8bc0348e8ddbc7705a5ad1fdf2155b6bc48884ac0cd376925f069a37849c089c8645",
"7e3a4c325cb9c52b88387f93d01ae86d42098f5efa7f9457388b5e74b6d28b2438d42d8b64703324d4aa25ab6aad153ae30cd2b2af4d5e5c00a8a2d0220c6116"];
var hashes:Array = [
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
"99f2aa95e36f95c2acb0eaf23998f030638f3f15",
"f944dcd635f9801f7ac90a407fbc479964dec024",
"a444319e9b6cc1e8464c511ec0969c37d6bb2619",
"16a0ff84fcc156fd5d3ca3a744f20a232d172253",
"fec9deebfcdedaf66dda525e1be43597a73a1f93",
"8ce051181f0ed5e9d0c498f6bc4caf448d20deb5",
"67da53837d89e03bf652ef09c369a3415937cfd3",
"305e4ff9888ad855a78573cddf4c5640cce7e946",
"5902b77b3265f023f9bbc396ba1a93fa3509bde7",
"fcade5f5d156bf6f9af97bdfa9c19bccfb4ff6ab",
"1d20fbe00533c10e3cbd6b27088a5de0c632c4b5",
"7e1b7e0f7a8f3455a9c03e9580fd63ae205a2d93",
"706f0677146307b20bb0e8d6311e329966884d13",
"a7241a703aaf0d53fe142f86bf2e849251fa8dff",
"400f53546916d33ad01a5e6df66822dfbdc4e9e6",
"fac8ab93c1ae6c16f0311872b984f729dc928ccd",
"fba6d750c18da58f6e2aab10112b9a5ef3301b3b",
"29d27c2d44c205c8107f0351b05753ac708226b6",
"b971bfc1ebd6f359e8d74cb7ecfe7f898d0ba845",
"96d08c430094b9fcc164ad2fb6f72d0a24268f68",
"a287ea752a593d5209e287881a09c49fa3f0beb1",
"a06c713779cbd88519ed4a585ac0cb8a5e9d612b",
"bff7d52c13a3688132a1d407b1ab40f5b5ace298",
"c7566b91d7b6f56bdfcaa9781a7b6841aacb17e9",
"ffa30c0b5c550ea4b1e34f8a60ec9295a1e06ac1",
"29e66ed23e914351e872aa761df6e4f1a07f4b81",
"b28cf5e5b806a01491d41f69bd9248765c5dc292",
"60224fb72c46069652cd78bcd08029ef64da62f3",
"b72c4a86f72608f24c05f3b9088ef92fba431df7",
"73779ad5d6b71b9b8328ef7220ff12eb167076ac",
"a09671d4452d7cf50015c914a1e31973d20cc1a0",
"e88cdcd233d99184a6fd260b8fca1b7f7687aee0",
"010def22850deb1168d525e8c84c28116cb8a269",
"aeaa40ba1717ed5439b1e6ea901b294ba500f9ad",
"c6433791238795e34f080a5f1f1723f065463ca0",
"e21e22b89c1bb944a32932e6b2a2f20d491982c3",
"575323a9661f5d28387964d2ba6ab92c17d05a8a",
"feb44494af72f245bfe68e86c4d7986d57c11db7",
"cff2290b3648ba2831b98dde436a72f9ebf51eee",
"9b4efe9d27b965905b0c3dab67b8d7c9ebacd56c",
"afedb0ff156205bcd831cbdbda43db8b0588c113",
"8deb1e858f88293a5e5e4d521a34b2a4efa70fc4",
"95cbdac0f74afa69cebd0e5c7defbc6faf0cbeaf",
"f0307bcb92842e5ae0cd4f4f14f3df7f877fbef2",
"7b13bb0dbf14964bd63b133ac85e22100542ef55",
"c314d2b6cf439be678d2a74e890d96cfac1c02ed",
"4d0be361e410b47a9d67d8ce0bb6a8e01c53c078",
"e5353431ffae097f675cbf498869f6fbb6e1c9f2",
"b8720a7068a085c018ab18961de2765aa6cd9ac4",
"b0732181568543ba85f2b6da602b4b065d9931aa",
"9c22674cf3222c3ba921672694aafee4ce67b96b",
"d128335f4cecca9066cdae08958ce656ff0b4cfc",
"0b67c57ac578de88a2ae055caeaec8bb9b0085a0",
"c766f912a89d4ccda88e0cce6a713ef5f178b596",
"9aa3925a9dcb177b15ccff9b78e70cf344858779",
"4811fa30042fc076acf37c8e2274d025307e5943",
"6743018450c9730761ee2b130df9b91c1e118150",
"71ad4a19d37d92a5e6ef3694ddbeb5aa61ada645",
"a7d9dc68dacefb7d6116186048cb355cc548e11d",
"142e429f0522ba5abf5131fa81df82d355b96909",
"ef72db70dcbcab991e9637976c6faf00d22caae9",
"f220a7457f4588d639dc21407c942e9843f8e26b",
"ddd2117b6e309c233ede85f962a0c2fc215e5c69",
"a3054427cdb13f164a610b348702724c808a0dcc"];
// ok. let's loop.
var sha1:SHA1 = new SHA1;
for (var i:uint=0;i<srcs.length;i++) {
var src:ByteArray = Hex.toArray(srcs[i]);
var digest:ByteArray = sha1.hash(src);
assert("SHA1 Test "+i, Hex.fromArray(digest) == hashes[i]);
}
}
/**
* A few long SHA-1, from the same page
*/
public function testLongSha1():void {
var srcs:Array = [
"ec29561244ede706b6eb30a1c371d74450a105c3f9735f7fa9fe38cf67f304a5736a106e92e17139a6813b1c81a4f3d3fb9546ab4296fa9f722826c066869edacd73b2548035185813e22634a9da44000d95a281ff9f264ecce0a931222162d021cca28db5f3c2aa24945ab1e31cb413ae29810fd794cad5dfaf29ec43cb38d198fe4ae1da2359780221405bd6712a5305da4b1b737fce7cd21c0eb7728d08235a9011",
"5fc2c3f6a7e79dc94be526e5166a238899d54927ce470018fbfd668fd9dd97cbf64e2c91584d01da63be3cc9fdff8adfefc3ac728e1e335b9cdc87f069172e323d094b47fa1e652afe4d6aa147a9f46fda33cacb65f3aa12234746b9007a8c85fe982afed7815221e43dba553d8fe8a022cdac1b99eeeea359e5a9d2e72e382dffa6d19f359f4f27dc3434cd27daeeda8e38594873398678065fbb23665aba9309d946135da0e4a4afdadff14db18e85e71dd93c3bf9faf7f25c8194c4269b1ee3d9934097ab990025d9c3aaf63d5109f52335dd3959d38ae485050e4bbb6235574fc0102be8f7a306d6e8de6ba6becf80f37415b57f9898a5824e77414197422be3d36a6080",
"0f865f46a8f3aed2da18482aa09a8f390dc9da07d51d1bd10fe0bf5f3928d5927d08733d32075535a6d1c8ac1b2dc6ba0f2f633dc1af68e3f0fa3d85e6c60cb7b56c239dc1519a007ea536a07b518ecca02a6c31b46b76f021620ef3fc6976804018380e5ab9c558ebfc5cb1c9ed2d974722bf8ab6398f1f2b82fa5083f85c16a5767a3a07271d67743f00850ce8ec428c7f22f1cf01f99895c0c844845b06a06cecb0c6cf83eb55a1d4ebc44c2c13f6f7aa5e0e08abfd84e7864279057abc471ee4a45dbbb5774afa24e51791a0eada11093b88681fe30baa3b2e94113dc63342c51ca5d1a6096d0897b626e42cb91761058008f746f35465465540ad8c6b8b60f7e1461b3ce9e6529625984cb8c7d46f07f735be067588a0117f23e34ff57800e2bbe9a1605fde6087fb15d22c5d3ac47566b8c448b0cee40373e5ba6eaa21abee71366afbb27dbbd300477d70c371e7b8963812f5ed4fb784fb2f3bd1d3afe883cdd47ef32beaea",
"4893f1c763625f2c6ce53aacf28026f14b3cd8687e1a1d3b60a81e80fcd1e2b038f9145ab64a0718f948f7c3c9ac92e3d86fb669a5257da1a18c776291653688338210a3242120f101788e8acc9110db9258b1554bf3d26602516ea93606a25a7f566c0c758fb39ecd9d876bc5d8abc1c3205095382c2474cb1f8bbdb45c2c0e659cb0fc703ec607a5de6bcc7a28687db1ee1c8f34797bb2441d5706d210df8c2d7d65dbded36414d063c117b52a51f7a4eb9cac0782e008b47459ed5acac0bc1f20121087f992ad985511b33c866d18e63f585478ee5a5e654b19d81231d98683ae3f0533565aba43dce408d7e3c4c6be11d8f05165f29c9dcb2030c4ee31d3a04e7421aa92c3231a1fc07e50e95fea7389a5e65891afaba51cf55e36a9d089bf293accb356d5d06547307d6e41456d4ed146a056179971c56521c83109bf922866186e184a99a96c7bb96df8937e35970e438412a2b8d744cf2ad87cb605d4232e976f9f15169776e4e5b6b786132c966b25fc56d815c56c819af5e159aa39f8a93d38115f5580cda93bc073c30b39920e726fe861b72483a3f886269ab7a8eefe952f35d25c4eb7f443f4f3f26e43d51fb54591e6a6dad25fcdf5142033084e5624bdd51435e77dea86b8",
"cf494c18a4e17bf03910631471bca5ba7edea8b9a63381e3463517961749848eb03abefd4ce676dece3740860255f57c261a558aa9c7f11432f549a9e4ce31d8e17c79450ce2ccfc148ad904aedfb138219d7052088520495355dadd90f72e6f69f9c6176d3d45f113f275b7fbc2a295784d41384cd7d629b23d1459a22e45fd5097ec9bf65fa965d3555ec77367903c32141065fc24da5c56963d46a2da3c279e4035fb2fb1c0025d9dda5b9e3443d457d92401a0d3f58b48469ecb1862dc975cdbe75ca099526db8b0329b03928206f084c633c04eef5e8e377f118d30edf592504be9d2802651ec78aeb02aea167a03fc3e23e5fc907c324f283f89ab37e84687a9c74ccf055402db95c29ba2c8d79b2bd4fa96459f8e3b78e07e923b81198267492196ecb71e01c331f8df245ec5bdf8d0e05c91e63bb299f0f6324895304dda721d39410458f117c87b7dd6a0ee734b79fcbe482b2c9e9aa0cef03a39d4b0c86de3bc34b4aadabfa373fd2258f7c40c187744d237080762382f547a36adb117839ca72f8ebbc5a20a07e86f4c8bb923f5787698d278f6db0040e76e54645bb0f97083995b34b9aa445fc424455058795828dd00c32471ec402a307f5aa1b37b1a86d6dae3bcbfbe9ba41cab0beeabf489af0073d4b3837d3f14b815120bc3602d072b5aeefcdec655fe756b660eba7dcf34675acbce317746270599424b9248791a0780449c1eabbb9459cc1e588bfd74df9b1b711c85c09d8aa171b309281947e8f4b6ac438753158f4f36fa"];
var hashes:Array = [
"970111c4e77bcc88cc20459c02b69b4aa8f58217",
"0423dc76a8791107d14e13f5265b343f24cc0f19",
"6692a71d73e00f27df976bc56df4970650d90e45",
"dc5859dd5163c4354d5d577b855fa98e37f04384",
"4c17926feb6e87f5bca7890d8a5cde744f231dab"];
// ok. let's loop.
var sha1:SHA1 = new SHA1;
for (var i:uint=0;i<srcs.length;i++) {
var src:ByteArray = Hex.toArray(srcs[i]);
var digest:ByteArray = sha1.hash(src);
assert("SHA1 Long Test "+i, Hex.fromArray(digest) == hashes[i]);
}
}
}
}
\ No newline at end of file
/**
* SHA224Test
*
* A test class for SHA224
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.hash.SHA224;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class SHA224Test extends TestCase
{
public function SHA224Test(h:ITestHarness)
{
super(h,"SHA-224 Test");
runTest(testSha224,"SHA-224 Test Vectors");
// takes a few seconds, but uncomment if you must.
//runTest(testLongSha224,"SHA-224 Long Test Vectors");
h.endTestCase();
}
/**
* Test vectors courtesy of
* http://www.ietf.org/rfc/rfc3874.txt
*/
public function testSha224():void {
var srcs:Array = [
Hex.fromString("abc"),
Hex.fromString("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")];
var hashes:Array = [
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"];
var sha224:SHA224 = new SHA224;
for (var i:uint=0;i<srcs.length;i++) {
var src:ByteArray = Hex.toArray(srcs[i]);
var digest:ByteArray = sha224.hash(src);
assert("SHA224 Test "+i, Hex.fromArray(digest) == hashes[i]);
}
}
public function testLongSha224():void {
var src:ByteArray = new ByteArray;
var a:uint = "a".charCodeAt(0);
for (var i:uint=0;i<1e6;i++) {
src[i] = a;
}
var sha224:SHA224 = new SHA224;
var digest:ByteArray = sha224.hash(src);
var hash:String = "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67";
assert("SHA224 Long Test", Hex.fromArray(digest) == hash);
}
}
}
\ No newline at end of file
/**
* SHA256Test
*
* A test class for SHA256
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.hash.SHA256;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class SHA256Test extends TestCase
{
public function SHA256Test(h:ITestHarness)
{
super(h,"SHA-256 Test");
runTest(testSha256,"SHA-256 Test Vectors");
h.endTestCase();
}
/**
* Test vectors courtesy of
* https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/sha/Sha-2-256.unverified.test-vectors
*/
public function testSha256():void {
var srcs:Array = [
Hex.fromString(""),
Hex.fromString("a"),
Hex.fromString("abc"),
Hex.fromString("message digest"),
Hex.fromString("abcdefghijklmnopqrstuvwxyz"),
Hex.fromString("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
Hex.fromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
Hex.fromString("12345678901234567890123456789012345678901234567890123456789012345678901234567890"),
];
var hashes:Array = [
"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"CA978112CA1BBDCAFAC231B39A23DC4DA786EFF8147C4E72B9807785AFEE48BB",
"BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD",
"F7846F55CF23E14EEBEAB5B4E1550CAD5B509E3348FBC4EFA3A1413D393CB650",
"71C480DF93D6AE2F1EFAD1447C66C9525E316218CF51FC8D9ED832F2DAF18B73",
"248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1",
"DB4BFCBD4DA0CD85A60C3C37D3FBD8805C77F15FC6B1FDFE614EE0A7C8FDB4C0",
"F371BC4A311F2B009EEF952DD83CA80E2B60026C8E935592D0F9C308453C813E"];
// loop.
var sha256:SHA256 = new SHA256;
for (var i:uint=0;i<srcs.length;i++) {
var src:ByteArray = Hex.toArray(srcs[i]);
var digest:ByteArray = sha256.hash(src);
assert("SHA256 Test "+i, Hex.fromArray(digest) == hashes[i].toLowerCase());
}
}
}
}
\ No newline at end of file
/**
* TLSPRFTest
*
* A test class for TLFPRF
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import flash.utils.ByteArray;
import com.hurlant.crypto.prng.TLSPRF;
import com.hurlant.util.Hex;
public class TLSPRFTest extends TestCase
{
public function TLSPRFTest(h:ITestHarness) {
super(h, "TLS-PRF Testing");
runTest(testVector, "TLF-PRF Test Vector");
h.endTestCase()
}
/**
* Test Vector as defined in
* http://www.imc.org/ietf-tls/mail-archive/msg01589.html
*/
private function testVector():void {
var secret:ByteArray = new ByteArray;
for (var i:uint=0;i<48;i++) {
secret[i]= 0xab;
}
var label:String = "PRF Testvector";
var seed:ByteArray = new ByteArray;
for (i=0;i<64;i++) {
seed[i] = 0xcd;
}
var prf:TLSPRF = new TLSPRF(secret, label, seed);
var out:ByteArray = new ByteArray;
prf.nextBytes(out, 104);
var expected:String = "D3 D4 D1 E3 49 B5 D5 15 04 46 66 D5 1D E3 2B AB" +
"25 8C B5 21 B6 B0 53 46 3E 35 48 32 FD 97 67 54" +
"44 3B CF 9A 29 65 19 BC 28 9A BC BC 11 87 E4 EB" +
"D3 1E 60 23 53 77 6C 40 8A AF B7 4C BC 85 EF F6" +
"92 55 F9 78 8F AA 18 4C BB 95 7A 98 19 D8 4A 5D" +
"7E B0 06 EB 45 9D 3A E8 DE 98 10 45 4B 8B 2D 8F" +
"1A FB C6 55 A8 C9 A0 13";
var expect:String = Hex.fromArray(Hex.toArray(expected));
assert("out == expected", Hex.fromArray(out)==expect);
}
}
}
\ No newline at end of file
/**
* TestCase
*
* Embryonic unit test support class.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
public class TestCase
{
public var harness:ITestHarness;
public function TestCase(h:ITestHarness, title:String) {
harness = h;
harness.beginTestCase(title);
}
public function assert(msg:String, value:Boolean):void {
if (value) {
// TestHarness.print("+ ",msg);
return;
}
throw new Error("Test Failure:"+msg);
}
public function runTest(f:Function, title:String):void {
harness.beginTest(title);
try {
f();
} catch (e:Error) {
trace("EXCEPTION THROWN: "+e);
trace(e.getStackTrace());
harness.failTest(e.toString());
return;
}
harness.passTest();
}
}
}
\ No newline at end of file
/**
* TripleDESKeyTest
*
* A test class for TripleDESKey
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.symmetric.TripleDESKey;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.ECBMode;
public class TripleDESKeyTest extends TestCase
{
public function TripleDESKeyTest(h:ITestHarness)
{
super(h, "Triped Des Test");
runTest(testECB,"Triple DES ECB Test Vectors");
h.endTestCase();
}
/**
* Lots of vectors at http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf
* XXX move them in here.
*/
public function testECB():void {
var keys:Array = [
"010101010101010101010101010101010101010101010101",
"dd24b3aafcc69278d650dad234956b01e371384619492ac4",
];
var pts:Array = [
"8000000000000000",
"F36B21045A030303",
];
var cts:Array = [
"95F8A5E5DD31D900",
"E823A43DEEA4D0A4",
];
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var ede:TripleDESKey = new TripleDESKey(key);
ede.encrypt(pt);
var out:String = Hex.fromArray(pt).toUpperCase();
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
// now go back to plaintext
ede.decrypt(pt);
out = Hex.fromArray(pt).toUpperCase();
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
}
}
}
}
\ No newline at end of file
/**
* XTeaKeyTest
*
* A test class for XTeaKey
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tests
{
import com.hurlant.crypto.prng.Random;
import com.hurlant.crypto.symmetric.ECBMode;
import com.hurlant.crypto.symmetric.XTeaKey;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import flash.utils.getTimer;
public class XTeaKeyTest extends TestCase
{
public function XTeaKeyTest(h:ITestHarness) {
super(h, "XTeaKey Test");
runTest(testGetBlockSize, "XTea Block Size");
runTest(testVectors, "XTea Test Vectors");
h.endTestCase();
}
public function testGetBlockSize():void {
var tea:XTeaKey = new XTeaKey(Hex.toArray("deadbabecafebeefdeadbabecafebeef"));
assert("tea blocksize", tea.getBlockSize()==8);
}
public function testVectors():void {
// blah.
// can't find working test vectors.
// algorithms should not get published without vectors :(
var keys:Array=[
"00000000000000000000000000000000",
"2b02056806144976775d0e266c287843"];
var pts:Array=[
"0000000000000000",
"74657374206d652e"];
var cts:Array=[
"2dc7e8d3695b0538",
"7909582138198783"];
// self-fullfilling vectors.
// oh well, at least I can decrypt what I produce. :(
for (var i:uint=0;i<keys.length;i++) {
var key:ByteArray = Hex.toArray(keys[i]);
var pt:ByteArray = Hex.toArray(pts[i]);
var tea:XTeaKey = new XTeaKey(key);
tea.encrypt(pt);
var out:String = Hex.fromArray(pt);
assert("comparing "+cts[i]+" to "+out, cts[i]==out);
// now go back to plaintext.
pt.position=0;
tea.decrypt(pt);
out = Hex.fromArray(pt);
assert("comparing "+pts[i]+" to "+out, pts[i]==out);
}
}
}
}
\ No newline at end of file
K 25
svn:wc:ra_dav:version-url
V 59
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls
END
SSLSecurityParameters.as
K 25
svn:wc:ra_dav:version-url
V 84
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/SSLSecurityParameters.as
END
TLSSocketEvent.as
K 25
svn:wc:ra_dav:version-url
V 77
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSSocketEvent.as
END
KeyExchanges.as
K 25
svn:wc:ra_dav:version-url
V 74
/svn/!svn/ver/5/trunk/as3crypto/src/com/hurlant/crypto/tls/KeyExchanges.as
END
TLSSecurityParameters.as
K 25
svn:wc:ra_dav:version-url
V 84
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSSecurityParameters.as
END
SSLConnectionState.as
K 25
svn:wc:ra_dav:version-url
V 81
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/SSLConnectionState.as
END
TLSConnectionState.as
K 25
svn:wc:ra_dav:version-url
V 81
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSConnectionState.as
END
MACs.as
K 25
svn:wc:ra_dav:version-url
V 67
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/MACs.as
END
TLSEngine.as
K 25
svn:wc:ra_dav:version-url
V 72
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSEngine.as
END
TLSConfig.as
K 25
svn:wc:ra_dav:version-url
V 72
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSConfig.as
END
TLSTest.as
K 25
svn:wc:ra_dav:version-url
V 70
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSTest.as
END
SSLEvent.as
K 25
svn:wc:ra_dav:version-url
V 71
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/SSLEvent.as
END
ISecurityParameters.as
K 25
svn:wc:ra_dav:version-url
V 82
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/ISecurityParameters.as
END
TLSEvent.as
K 25
svn:wc:ra_dav:version-url
V 71
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSEvent.as
END
CipherSuites.as
K 25
svn:wc:ra_dav:version-url
V 74
/svn/!svn/ver/5/trunk/as3crypto/src/com/hurlant/crypto/tls/CipherSuites.as
END
IConnectionState.as
K 25
svn:wc:ra_dav:version-url
V 79
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/IConnectionState.as
END
TLSSocket.as
K 25
svn:wc:ra_dav:version-url
V 72
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSSocket.as
END
BulkCiphers.as
K 25
svn:wc:ra_dav:version-url
V 74
/svn/!svn/ver/28/trunk/as3crypto/src/com/hurlant/crypto/tls/BulkCiphers.as
END
TLSError.as
K 25
svn:wc:ra_dav:version-url
V 70
/svn/!svn/ver/5/trunk/as3crypto/src/com/hurlant/crypto/tls/TLSError.as
END
10
dir
28
http://as3crypto.googlecode.com/svn/trunk/as3crypto/src/com/hurlant/crypto/tls
http://as3crypto.googlecode.com/svn
2009-06-04T23:35:21.192697Z
28
sh0rtwave
395c722c-794e-0410-9327-f1aa524df581
SSLSecurityParameters.as
file
2009-11-07T06:59:45.000000Z
6c5697914664d25c3948e4a3433d7db4
2009-06-04T23:35:21.192697Z
28
sh0rtwave
has-props
11174
TLSSocketEvent.as
file
2009-11-07T06:59:45.000000Z
2b65fc207d2e4dde7730c5cde6ff29fc
2009-06-04T23:35:21.192697Z
28
sh0rtwave
710
KeyExchanges.as
file
2009-11-07T06:59:45.000000Z
8e8bafc736c3bdcf9893f3d88e147eb0
2008-06-22T06:30:28.854933Z
5
henrit
664
TLSSecurityParameters.as
file
2009-11-07T06:59:45.000000Z
685ca3101ce7de74856a3a40fd2cc405
2009-06-04T23:35:21.192697Z
28
sh0rtwave
7210
SSLConnectionState.as
file
2009-11-07T06:59:45.000000Z
02301bb3725990f16ecb8c67e1fb5693
2009-06-04T23:35:21.192697Z
28
sh0rtwave
4442
TLSConnectionState.as
file
2009-11-07T06:59:45.000000Z
35c7fe1ed260e406c8f3c21ffda7ba03
2009-06-04T23:35:21.192697Z
28
sh0rtwave
4222
MACs.as
file
2009-11-07T06:59:45.000000Z
62c9883a26d68969193b6e0ea77e1e3f
2009-06-04T23:35:21.192697Z
28
sh0rtwave
921
TLSEngine.as
file
2009-11-07T06:59:45.000000Z
3fb6a935051b057372c029bfcb5e4164
2009-06-04T23:35:21.192697Z
28
sh0rtwave
30929
TLSConfig.as
file
2009-11-07T06:59:45.000000Z
b5d0f6023a346c1b559c6505fa9dc5d5
2009-06-04T23:35:21.192697Z
28
sh0rtwave
2301
TLSTest.as
file
2009-11-07T06:59:45.000000Z
dbc1fcb838a012c8b1b1e373db775f83
2009-06-04T23:35:21.192697Z
28
sh0rtwave
5907
SSLEvent.as
file
2009-11-07T06:59:45.000000Z
7069acbae6e5ecf830536417e2c44643
2009-06-04T23:35:21.192697Z
28
sh0rtwave
has-props
679
ISecurityParameters.as
file
2009-11-07T06:59:45.000000Z
c4e2d436dea6058f8eb66dd03ecb1181
2009-06-04T23:35:21.192697Z
28
sh0rtwave
has-props
1053
TLSEvent.as
file
2009-11-07T06:59:45.000000Z
e0f7f72e8b49432359f99722729cd15b
2009-06-04T23:35:21.192697Z
28
sh0rtwave
726
CipherSuites.as
file
2009-11-07T06:59:45.000000Z
57a6f5055bc96953e79c7ce9a8b560b0
2008-06-22T06:30:28.854933Z
5
henrit
4928
IConnectionState.as
file
2009-11-07T06:59:45.000000Z
d7fd97b9bce831fde2e7dc47276b7a10
2009-06-04T23:35:21.192697Z
28
sh0rtwave
374
TLSSocket.as
file
2009-11-07T06:59:45.000000Z
8440bdbbb1e3bc1f04400893029af570
2009-06-04T23:35:21.192697Z
28
sh0rtwave
11269
BulkCiphers.as
file
2009-11-07T06:59:45.000000Z
86925f2e6696668849fa4c5d64a986b4
2009-06-04T23:35:21.192697Z
28
sh0rtwave
3571
TLSError.as
file
2009-11-07T06:59:45.000000Z
3adf5bdb71ddf25b5bbda6ba672d2caf
2008-06-22T06:30:28.854933Z
5
henrit
1711
/**
* BulkCiphers
*
* An enumeration of bulk ciphers available for TLS, along with their properties,
* with a few convenience methods to go with it.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.TLSPad;
import com.hurlant.crypto.symmetric.SSLPad;
public class BulkCiphers {
public static const STREAM_CIPHER:uint = 0;
public static const BLOCK_CIPHER:uint = 1;
public static const NULL:uint = 0;
public static const RC4_40:uint = 1;
public static const RC4_128:uint = 2
public static const RC2_CBC_40:uint = 3; // XXX I don't have that one.
public static const DES_CBC:uint = 4;
public static const DES3_EDE_CBC:uint = 5;
public static const DES40_CBC:uint = 6;
public static const IDEA_CBC:uint = 7; // XXX I don't have that one.
public static const AES_128:uint = 8;
public static const AES_256:uint = 9;
private static const algos:Array =
['', 'rc4', 'rc4', '', 'des-cbc', '3des-cbc', 'des-cbc', '', 'aes', 'aes'];
private static var _props:Array;
init();
private static function init():void {
_props = [];
_props[NULL] = new BulkCiphers(STREAM_CIPHER, 0, 0, 0, 0, 0);
_props[RC4_40] = new BulkCiphers(STREAM_CIPHER, 5, 16, 40, 0, 0);
_props[RC4_128] = new BulkCiphers(STREAM_CIPHER, 16, 16, 128, 0, 0);
_props[RC2_CBC_40] = new BulkCiphers( BLOCK_CIPHER, 5, 16, 40, 8, 8);
_props[DES_CBC] = new BulkCiphers( BLOCK_CIPHER, 8, 8, 56, 8, 8);
_props[DES3_EDE_CBC] = new BulkCiphers( BLOCK_CIPHER, 24, 24, 168, 8, 8);
_props[DES40_CBC] = new BulkCiphers( BLOCK_CIPHER, 5, 8, 40, 8, 8);
_props[IDEA_CBC] = new BulkCiphers( BLOCK_CIPHER, 16, 16, 128, 8, 8);
_props[AES_128] = new BulkCiphers( BLOCK_CIPHER, 16, 16, 128, 16, 16);
_props[AES_256] = new BulkCiphers( BLOCK_CIPHER, 32, 32, 256, 16, 16);
}
private static function getProp(cipher:uint):BulkCiphers {
var p:BulkCiphers = _props[cipher];
if (p==null) {
throw new Error("Unknown bulk cipher "+cipher.toString(16));
}
return p;
}
public static function getType(cipher:uint):uint {
return getProp(cipher).type;
}
public static function getKeyBytes(cipher:uint):uint {
return getProp(cipher).keyBytes;
}
public static function getExpandedKeyBytes(cipher:uint):uint {
return getProp(cipher).expandedKeyBytes;
}
public static function getEffectiveKeyBits(cipher:uint):uint {
return getProp(cipher).effectiveKeyBits;
}
public static function getIVSize(cipher:uint):uint {
return getProp(cipher).IVSize;
}
public static function getBlockSize(cipher:uint):uint {
return getProp(cipher).blockSize;
}
public static function getCipher(cipher:uint, key:ByteArray, proto:uint):ICipher {
if (proto == TLSSecurityParameters.PROTOCOL_VERSION) {
return Crypto.getCipher(algos[cipher], key, new TLSPad);
} else {
return Crypto.getCipher(algos[cipher], key, new SSLPad);
}
}
private var type:uint;
private var keyBytes:uint;
private var expandedKeyBytes:uint;
private var effectiveKeyBits:uint;
private var IVSize:uint;
private var blockSize:uint;
public function BulkCiphers(t:uint, kb:uint, ekb:uint, fkb:uint, ivs:uint, bs:uint) {
type = t;
keyBytes = kb;
expandedKeyBytes = ekb;
effectiveKeyBits = fkb;
IVSize = ivs;
blockSize = bs;
}
}
}
/**
* CipherSuites
*
* An enumeration of cipher-suites available for TLS to use, along with
* their properties, and some convenience methods
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
public class CipherSuites {
// only the lines marked "ok" are currently implemented.
// rfc 2246
public static const TLS_NULL_WITH_NULL_NULL:uint = 0x0000; // ok
public static const TLS_RSA_WITH_NULL_MD5:uint = 0x0001; // ok
public static const TLS_RSA_WITH_NULL_SHA:uint = 0x0002; // ok
public static const TLS_RSA_WITH_RC4_128_MD5:uint = 0x0004; // ok
public static const TLS_RSA_WITH_RC4_128_SHA:uint = 0x0005; // ok
public static const TLS_RSA_WITH_IDEA_CBC_SHA:uint = 0x0007;
public static const TLS_RSA_WITH_DES_CBC_SHA:uint = 0x0009; // ok
public static const TLS_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x000A; // ok
public static const TLS_DH_DSS_WITH_DES_CBC_SHA:uint = 0x000C;
public static const TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:uint = 0x000D;
public static const TLS_DH_RSA_WITH_DES_CBC_SHA:uint = 0x000F;
public static const TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x0010;
public static const TLS_DHE_DSS_WITH_DES_CBC_SHA:uint = 0x0012;
public static const TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:uint = 0x0013;
public static const TLS_DHE_RSA_WITH_DES_CBC_SHA:uint = 0x0015;
public static const TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x0016;
public static const TLS_DH_anon_WITH_RC4_128_MD5:uint = 0x0018;
public static const TLS_DH_anon_WITH_DES_CBC_SHA:uint = 0x001A;
public static const TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:uint = 0x001B;
// rfc3268
public static const TLS_RSA_WITH_AES_128_CBC_SHA:uint = 0x002F; // ok
public static const TLS_DH_DSS_WITH_AES_128_CBC_SHA:uint = 0x0030;
public static const TLS_DH_RSA_WITH_AES_128_CBC_SHA:uint = 0x0031;
public static const TLS_DHE_DSS_WITH_AES_128_CBC_SHA:uint = 0x0032;
public static const TLS_DHE_RSA_WITH_AES_128_CBC_SHA:uint = 0x0033;
public static const TLS_DH_anon_WITH_AES_128_CBC_SHA:uint = 0x0034;
public static const TLS_RSA_WITH_AES_256_CBC_SHA:uint = 0x0035; // ok
public static const TLS_DH_DSS_WITH_AES_256_CBC_SHA:uint = 0x0036;
public static const TLS_DH_RSA_WITH_AES_256_CBC_SHA:uint = 0x0037;
public static const TLS_DHE_DSS_WITH_AES_256_CBC_SHA:uint = 0x0038;
public static const TLS_DHE_RSA_WITH_AES_256_CBC_SHA:uint = 0x0039;
public static const TLS_DH_anon_WITH_AES_256_CBC_SHA:uint = 0x003A;
private static var _props:Array;
init();
private static function init():void {
_props = [];
_props[TLS_NULL_WITH_NULL_NULL] = new CipherSuites(BulkCiphers.NULL, MACs.NULL, KeyExchanges.NULL);
_props[TLS_RSA_WITH_NULL_MD5] = new CipherSuites(BulkCiphers.NULL, MACs.MD5, KeyExchanges.RSA);
_props[TLS_RSA_WITH_NULL_SHA] = new CipherSuites(BulkCiphers.NULL, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_RC4_128_MD5] = new CipherSuites(BulkCiphers.RC4_128, MACs.MD5, KeyExchanges.RSA);
_props[TLS_RSA_WITH_RC4_128_SHA] = new CipherSuites(BulkCiphers.RC4_128, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_DES_CBC_SHA] = new CipherSuites(BulkCiphers.DES_CBC, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_3DES_EDE_CBC_SHA] = new CipherSuites(BulkCiphers.DES3_EDE_CBC, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_AES_128_CBC_SHA] = new CipherSuites(BulkCiphers.AES_128, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_AES_256_CBC_SHA] = new CipherSuites(BulkCiphers.AES_256, MACs.SHA1, KeyExchanges.RSA);
// ...
// more later
}
private static function getProp(cipher:uint):CipherSuites {
var p:CipherSuites = _props[cipher];
if (p==null) {
throw new Error("Unknown cipher "+cipher.toString(16));
}
return p;
}
public static function getBulkCipher(cipher:uint):uint {
return getProp(cipher).cipher;
}
public static function getMac(cipher:uint):uint {
return getProp(cipher).hash;
}
public static function getKeyExchange(cipher:uint):uint {
return getProp(cipher).key;
}
public static function getDefaultSuites():Array {
// a list of acceptable ciphers, sorted by preference.
return [
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_MD5,
TLS_RSA_WITH_DES_CBC_SHA
];
}
public var cipher:uint;
public var hash:uint;
public var key:uint;
public function CipherSuites(cipher:uint, hash:uint, key:uint) {
this.cipher = cipher;
this.hash = hash;
this.key = key;
}
}
}
/**
* IConnectionState
*
* Interface for TLS/SSL Connection states.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.ByteArray;
public interface IConnectionState {
function decrypt(type:uint, length:uint, p:ByteArray) : ByteArray;
function encrypt(type:uint, p:ByteArray) : ByteArray;
}
}
\ No newline at end of file
/**
* ISecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.ByteArray;
public interface ISecurityParameters {
function get version() : uint;
function reset():void;
function getBulkCipher():uint;
function getCipherType():uint;
function getMacAlgorithm():uint;
function setCipher(cipher:uint):void;
function setCompression(algo:uint):void;
function setPreMasterSecret(secret:ByteArray):void;
function setClientRandom(secret:ByteArray):void;
function setServerRandom(secret:ByteArray):void;
function get useRSA():Boolean;
function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray;
function computeCertificateVerify( side:uint, handshakeRecords:ByteArray):ByteArray;
function getConnectionStates():Object;
}
}
\ No newline at end of file
/**
* KeyExchanges
*
* An enumeration of key exchange methods defined by TLS
* ( right now, only RSA is actually implemented )
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
public class KeyExchanges {
public static const NULL:uint = 0;
public static const RSA:uint = 1;
public static const DH_DSS:uint = 2;
public static const DH_RSA:uint = 3;
public static const DHE_DSS:uint = 4;
public static const DHE_RSA:uint = 5;
public static const DH_anon:uint = 6;
public static function useRSA(p:uint):Boolean {
return (p==RSA);
}
}
}
\ No newline at end of file
/**
* MACs
*
* An enumeration of MACs implemented for TLS 1.0/SSL 3.0
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.MAC;
public class MACs {
public static const NULL:uint = 0;
public static const MD5:uint = 1;
public static const SHA1:uint = 2;
public static function getHashSize(hash:uint):uint {
return [0,16,20][hash];
}
public static function getPadSize(hash:uint):int {
return [0, 48, 40][hash];
}
public static function getHMAC(hash:uint):HMAC {
if (hash==NULL) return null;
return Crypto.getHMAC(['',"md5","sha1"][hash]);
}
public static function getMAC(hash:uint):MAC {
return Crypto.getMAC(['', "md5", "sha1"][hash]);
}
}
}
\ No newline at end of file
/**
* TLSConnectionState
*
* This class encapsulates the read or write state of a TLS connection,
* and implementes the encrypting and hashing of packets.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.IDataInput;
import flash.utils.ByteArray;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.MAC;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.util.Hex;
import com.hurlant.util.ArrayUtil;
public class SSLConnectionState implements IConnectionState {
// compression state
// cipher state
private var bulkCipher:uint;
private var cipherType:uint;
private var CIPHER_key:ByteArray;
private var CIPHER_IV:ByteArray;
private var cipher:ICipher;
private var ivmode:IVMode;
// mac secret
private var macAlgorithm:uint;
private var MAC_write_secret:ByteArray;
private var mac:MAC;
// sequence number. uint64
private var seq_lo:uint = 0x0;
private var seq_hi:uint = 0x0;
public function SSLConnectionState(
bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,
mac_enc:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {
this.bulkCipher = bulkCipher;
this.cipherType = cipherType;
this.macAlgorithm = macAlgorithm;
MAC_write_secret = mac_enc;
mac = MACs.getMAC(macAlgorithm);
CIPHER_key = key;
CIPHER_IV = IV;
cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0300);
if (cipher is IVMode) {
ivmode = cipher as IVMode;
ivmode.IV = IV;
}
}
public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {
// decompression is a nop.
if (cipherType == BulkCiphers.STREAM_CIPHER) {
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.decrypt(p);
}
} else {
p.position = 0;
// block cipher
if (bulkCipher == BulkCiphers.NULL) {
} else {
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
p.position = 0;
cipher.decrypt(p);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
}
if (macAlgorithm!=MACs.NULL) {
// there will be CTX delay here as well,
// I should probably optmize the hell out of it
var data:ByteArray = new ByteArray;
var len:uint = p.length - mac.getHashSize();
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
data.writeByte(type);
data.writeShort(len);
if (len!=0) {
data.writeBytes(p, 0, len);
}
var mac_enc:ByteArray = mac.compute(MAC_write_secret, data);
// compare "mac" with the last X bytes of p.
var mac_received:ByteArray = new ByteArray;
mac_received.writeBytes(p, len, mac.getHashSize());
if (ArrayUtil.equals(mac_enc, mac_received)) {
// happy happy joy joy
} else {
throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);
}
p.length = len;
p.position = 0;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
return p;
}
public function encrypt(type:uint, p:ByteArray):ByteArray {
var mac_enc:ByteArray = null;
if (macAlgorithm!=MACs.NULL) {
var data:ByteArray = new ByteArray;
// data.writeUnsignedInt(seq);
// Sequence
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
// Type
data.writeByte(type);
// Length
data.writeShort(p.length);
// The data
if (p.length!=0) {
data.writeBytes(p);
}
// trace("data for the MAC: " + Hex.fromArray(data));
mac_enc = mac.compute(MAC_write_secret, data);
// trace("MAC: " + Hex.fromArray( mac_enc ));
p.position = p.length;
p.writeBytes(mac_enc);
}
// trace("Record to encrypt: " + Hex.fromArray(p));
p.position = 0;
if (cipherType == BulkCiphers.STREAM_CIPHER) {
// stream cipher
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.encrypt(p);
}
} else {
// block cipher
cipher.encrypt(p);
// adjust IV
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
return p;
}
}
}
\ No newline at end of file
/**
* SSLEvent
*
* This is used by TLSEngine to let the application layer know
* when we're ready for sending, or have received application data
* This Event was created by Bobby Parker to support SSL 3.0.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.utils.ByteArray;
public class SSLEvent extends Event {
static public const DATA:String = "data";
static public const READY:String = "ready";
public var data:ByteArray;
public function SSLEvent(type:String, data:ByteArray = null) {
this.data = data;
super(type, false, false);
}
}
}
\ No newline at end of file
/**
* TLSSecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class SSLSecurityParameters implements ISecurityParameters {
// COMPRESSION
public static const COMPRESSION_NULL:uint = 0;
private var entity:uint; // SERVER | CLIENT
private var bulkCipher:uint; // BULK_CIPHER_*
private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER
private var keySize:uint;
private var keyMaterialLength:uint;
private var keyBlock:ByteArray;
private var IVSize:uint;
private var MAC_length:uint;
private var macAlgorithm:uint; // MAC_*
private var hashSize:uint;
private var compression:uint; // COMPRESSION_NULL
private var masterSecret:ByteArray; // 48 bytes
private var clientRandom:ByteArray; // 32 bytes
private var serverRandom:ByteArray; // 32 bytes
private var pad_1:ByteArray; // varies
private var pad_2:ByteArray; // varies
private var ignoreCNMismatch:Boolean = true;
private var trustAllCerts:Boolean = false;
private var trustSelfSigned:Boolean = false;
public static const PROTOCOL_VERSION:uint = 0x0300;
// not strictly speaking part of this, but yeah.
public var keyExchange:uint;
public function get version() : uint {
return PROTOCOL_VERSION;
}
public function SSLSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:ByteArray = null) {
this.entity = entity;
reset();
}
public function reset():void {
bulkCipher = BulkCiphers.NULL;
cipherType = BulkCiphers.BLOCK_CIPHER;
macAlgorithm = MACs.NULL;
compression = COMPRESSION_NULL;
masterSecret = null;
}
public function getBulkCipher():uint {
return bulkCipher;
}
public function getCipherType():uint {
return cipherType;
}
public function getMacAlgorithm():uint {
return macAlgorithm;
}
public function setCipher(cipher:uint):void {
bulkCipher = CipherSuites.getBulkCipher(cipher);
cipherType = BulkCiphers.getType(bulkCipher);
keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8
keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5
IVSize = BulkCiphers.getIVSize(bulkCipher);
keyExchange = CipherSuites.getKeyExchange(cipher);
macAlgorithm = CipherSuites.getMac(cipher);
hashSize = MACs.getHashSize(macAlgorithm);
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < 48; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
public function setCompression(algo:uint):void {
compression = algo;
}
public function setPreMasterSecret(secret:ByteArray):void {
/* Warning! Following code may cause madness
Tread not here, unless ye be men of valor.
***** Official Prophylactic Comment ******
(to protect the unwary...this code actually works, that's all you need to know)
This does two things, computes the master secret, and generates the keyBlock
To compute the master_secret, the following algorithm is used.
for SSL 3, this means
master = MD5( premaster + SHA1('A' + premaster + client_random + server_random ) ) +
MD5( premaster + SHA1('BB' + premaster + client_random + server_random ) ) +
MD5( premaster + SHA1('CCC' + premaster + client_random + server_random ) )
*/
var tempHashA:ByteArray = new ByteArray(); // temporary hash, gets reused a lot
var tempHashB:ByteArray = new ByteArray(); // temporary hash, gets reused a lot
var shaHash:ByteArray;
var mdHash:ByteArray;
var i:int;
var j:int;
var sha:SHA1 = new SHA1();
var md:MD5 = new MD5();
var k:ByteArray = new ByteArray();
k.writeBytes(secret);
k.writeBytes(clientRandom);
k.writeBytes(serverRandom);
masterSecret = new ByteArray();
var pad_char:uint = 0x41;
for ( i = 0; i < 3; i++) {
// SHA portion
tempHashA.position = 0;
for ( j = 0; j < i + 1; j++) {
tempHashA.writeByte(pad_char);
}
pad_char++;
tempHashA.writeBytes(k);
shaHash = sha.hash(tempHashA);
// MD5 portion
tempHashB.position = 0;
tempHashB.writeBytes(secret);
tempHashB.writeBytes(shaHash);
mdHash = md.hash(tempHashB);
// copy into my key
masterSecret.writeBytes(mdHash);
}
// *************** END MASTER SECRET **************
// More prophylactic comments
// *************** START KEY BLOCK ****************
// So here, I'm setting up the keyBlock array that I will derive MACs, keys, and IVs from.
// Rebuild k (hash seed)
k.position = 0;
k.writeBytes(masterSecret);
k.writeBytes(serverRandom);
k.writeBytes(clientRandom);
keyBlock = new ByteArray();
tempHashA = new ByteArray();
tempHashB = new ByteArray();
// now for 16 iterations to get 256 bytes (16 * 16), better to have more than not enough
pad_char = 0x41;
for ( i = 0; i < 16; i++) {
tempHashA.position = 0;
for ( j = 0; j < i + 1; j++) {
tempHashA.writeByte(pad_char);
}
pad_char++;
tempHashA.writeBytes(k);
shaHash = sha.hash(tempHashA);
tempHashB.position = 0;
tempHashB.writeBytes(masterSecret);
tempHashB.writeBytes(shaHash, 0);
mdHash = md.hash(tempHashB);
keyBlock.writeBytes(mdHash);
}
}
public function setClientRandom(secret:ByteArray):void {
clientRandom = secret;
}
public function setServerRandom(secret:ByteArray):void {
serverRandom = secret;
}
public function get useRSA():Boolean {
return KeyExchanges.useRSA(keyExchange);
}
// This is the Finished message
// if you value your sanity, stay away...far away
public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
// for SSL 3.0, this consists of
// finished = md5( masterSecret + pad2 + md5( handshake + sender + masterSecret + pad1 ) ) +
// sha1( masterSecret + pad2 + sha1( handshake + sender + masterSecret + pad1 ) )
// trace("Handshake messages: " + Hex.fromArray(handshakeMessages));
var sha:SHA1 = new SHA1();
var md:MD5 = new MD5();
var k:ByteArray = new ByteArray(); // handshake + sender + masterSecret + pad1
var j:ByteArray = new ByteArray(); // masterSecret + pad2 + k
var innerKey:ByteArray;
var outerKey:ByteArray = new ByteArray();
var hashSha:ByteArray;
var hashMD:ByteArray;
var sideBytes:ByteArray = new ByteArray();
if (side == TLSEngine.CLIENT) {
sideBytes.writeUnsignedInt(0x434C4E54);
} else {
sideBytes.writeUnsignedInt(0x53525652);
}
// Do the SHA1 part of the routine first
masterSecret.position = 0;
k.writeBytes(handshakeMessages);
k.writeBytes(sideBytes);
k.writeBytes(masterSecret);
k.writeBytes(pad_1, 0, 40); // limited to 40 chars for SHA1
innerKey = sha.hash(k);
// trace("Inner SHA Key: " + Hex.fromArray(innerKey));
j.writeBytes(masterSecret);
j.writeBytes(pad_2, 0, 40); // limited to 40 chars for SHA1
j.writeBytes(innerKey);
hashSha = sha.hash(j);
// trace("Outer SHA Key: " + Hex.fromArray(hashSha));
// Rebuild k for MD5
k = new ByteArray();
k.writeBytes(handshakeMessages);
k.writeBytes(sideBytes);
k.writeBytes(masterSecret);
k.writeBytes(pad_1); // Take the whole length of pad_1 & pad_2 for MD5
innerKey = md.hash(k);
// trace("Inner MD5 Key: " + Hex.fromArray(innerKey));
j = new ByteArray();
j.writeBytes(masterSecret);
j.writeBytes(pad_2); // see above re: 48 byte pad
j.writeBytes(innerKey);
hashMD = md.hash(j);
// trace("Outer MD5 Key: " + Hex.fromArray(hashMD));
outerKey.writeBytes(hashMD, 0, hashMD.length);
outerKey.writeBytes(hashSha, 0, hashSha.length);
var out:String = Hex.fromArray(outerKey);
// trace("Finished Message: " + out);
outerKey.position = 0;
return outerKey;
}
public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
// TODO: Implement this, but I don't forsee it being necessary at this point in time, since for purposes
// of the override, I'm only going to use TLS
return null;
}
public function getConnectionStates():Object {
if (masterSecret != null) {
// so now, I have to derive the actual keys from the keyblock that I generated in setPremasterSecret.
// for MY purposes, I need RSA-AES 128/256 + SHA
// so I'm gonna have keylen = 32, minlen = 32, mac_length = 20, iv_length = 16
// but...I can get this data from the settings returned in the constructor when this object is
// It strikes me that TLS does this more elegantly...
var mac_length:int = hashSize as Number;
var key_length:int = keySize as Number;
var iv_length:int = IVSize as Number;
var client_write_MAC:ByteArray = new ByteArray();
var server_write_MAC:ByteArray = new ByteArray();
var client_write_key:ByteArray = new ByteArray();
var server_write_key:ByteArray = new ByteArray();
var client_write_IV:ByteArray = new ByteArray();
var server_write_IV:ByteArray = new ByteArray();
// Derive the keys from the keyblock
// Get the MACs first
keyBlock.position = 0;
keyBlock.readBytes(client_write_MAC, 0, mac_length);
keyBlock.readBytes(server_write_MAC, 0, mac_length);
// keyBlock.position is now at MAC_length * 2
// then get the keys
keyBlock.readBytes(client_write_key, 0, key_length);
keyBlock.readBytes(server_write_key, 0, key_length);
// keyBlock.position is now at (MAC_length * 2) + (keySize * 2)
// and then the IVs
keyBlock.readBytes(client_write_IV, 0, iv_length);
keyBlock.readBytes(server_write_IV, 0, iv_length);
// reset this in case it's needed, for some reason or another, but I doubt it
keyBlock.position = 0;
var client_write:SSLConnectionState = new SSLConnectionState(
bulkCipher, cipherType, macAlgorithm,
client_write_MAC, client_write_key, client_write_IV);
var server_write:SSLConnectionState = new SSLConnectionState(
bulkCipher, cipherType, macAlgorithm,
server_write_MAC, server_write_key, server_write_IV);
if (entity == TLSEngine.CLIENT) {
return {read:server_write, write:client_write};
} else {
return {read:client_write, write:server_write};
}
} else {
return {read:new SSLConnectionState, write:new SSLConnectionState};
}
}
}
}
\ No newline at end of file
/**
* TLSConfig
*
* A set of configuration parameters for use by a TLSSocket or a TLSEngine.
* Most parameters are optional and will be set to appropriate default values for most use.
*
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.ByteArray;
import com.hurlant.util.der.PEM;
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.crypto.cert.X509CertificateCollection;
import com.hurlant.crypto.cert.MozillaRootCertificates;
public class TLSConfig {
public var entity:uint; // SERVER | CLIENT
public var certificate:ByteArray;
public var privateKey:RSAKey;
public var cipherSuites:Array;
public var compressions:Array;
public var ignoreCommonNameMismatch:Boolean = false;
public var trustAllCertificates:Boolean = false;
public var trustSelfSignedCertificates:Boolean = false;
public var promptUserForAcceptCert:Boolean = false;
public var CAStore:X509CertificateCollection;
public var localKeyStore:X509CertificateCollection;
public var version:uint;
public function TLSConfig( entity:uint, cipherSuites:Array = null, compressions:Array = null,
certificate:ByteArray = null, privateKey:RSAKey = null, CAStore:X509CertificateCollection = null, ver:uint = 0x00) {
this.entity = entity;
this.cipherSuites = cipherSuites;
this.compressions = compressions;
this.certificate = certificate;
this.privateKey = privateKey;
this.CAStore = CAStore;
this.version = ver;
// default settings.
if (cipherSuites==null) {
this.cipherSuites = CipherSuites.getDefaultSuites();
}
if (compressions==null) {
this.compressions = [TLSSecurityParameters.COMPRESSION_NULL];
}
if (CAStore==null) {
this.CAStore = new MozillaRootCertificates;
}
if (ver==0x00) {
// Default to TLS
this.version = TLSSecurityParameters.PROTOCOL_VERSION;
}
}
public function setPEMCertificate(cert:String, key:String = null):void {
if (key == null) {
key = cert; // for folks who like to concat those two in one file.
}
certificate = PEM.readCertIntoArray(cert);
privateKey = PEM.readRSAPrivateKey(key);
}
}
}
\ No newline at end of file
/**
* TLSConnectionState
*
* This class encapsulates the read or write state of a TLS connection,
* and implementes the encrypting and hashing of packets.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.IDataInput;
import flash.utils.ByteArray;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.util.Hex;
import com.hurlant.util.ArrayUtil;
public class TLSConnectionState implements IConnectionState {
// compression state
// cipher state
private var bulkCipher:uint;
private var cipherType:uint;
private var CIPHER_key:ByteArray;
private var CIPHER_IV:ByteArray;
private var cipher:ICipher;
private var ivmode:IVMode;
// mac secret
private var macAlgorithm:uint;
private var MAC_write_secret:ByteArray;
private var hmac:HMAC;
// sequence number. uint64
private var seq_lo:uint;
private var seq_hi:uint;
public function TLSConnectionState(
bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,
mac:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {
this.bulkCipher = bulkCipher;
this.cipherType = cipherType;
this.macAlgorithm = macAlgorithm;
MAC_write_secret = mac;
hmac = MACs.getHMAC(macAlgorithm);
CIPHER_key = key;
CIPHER_IV = IV;
cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0301);
if (cipher is IVMode) {
ivmode = cipher as IVMode;
ivmode.IV = IV;
}
}
public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {
// decompression is a nop.
if (cipherType == BulkCiphers.STREAM_CIPHER) {
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.decrypt(p);
}
} else {
// block cipher
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
cipher.decrypt(p);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
if (macAlgorithm!=MACs.NULL) {
var data:ByteArray = new ByteArray;
var len:uint = p.length - hmac.getHashSize();
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
data.writeByte(type);
data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);
data.writeShort(len);
if (len!=0) {
data.writeBytes(p, 0, len);
}
var mac:ByteArray = hmac.compute(MAC_write_secret, data);
// compare "mac" with the last X bytes of p.
var mac_received:ByteArray = new ByteArray;
mac_received.writeBytes(p, len, hmac.getHashSize());
if (ArrayUtil.equals(mac, mac_received)) {
// happy happy joy joy
} else {
throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);
}
p.length = len;
p.position = 0;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
return p;
}
public function encrypt(type:uint, p:ByteArray):ByteArray {
var mac:ByteArray = null;
if (macAlgorithm!=MACs.NULL) {
var data:ByteArray = new ByteArray;
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
data.writeByte(type);
data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);
data.writeShort(p.length);
if (p.length!=0) {
data.writeBytes(p, 0, p.length);
}
mac = hmac.compute(MAC_write_secret, data);
p.position = p.length;
p.writeBytes(mac);
}
p.position = 0;
if (cipherType == BulkCiphers.STREAM_CIPHER) {
// stream cipher
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.encrypt(p);
}
} else {
// block cipher
cipher.encrypt(p);
// adjust IV
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
// compression is a nop.
return p;
}
}
}
\ No newline at end of file
/**
* TLSEngine
*
* A TLS protocol implementation.
* See comment below for some details.
* Copyright (c) 2007 Henri Torgemane
*
* Patched(heavily) by Bobby Parker (shortwave@gmail.com)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.cert.X509Certificate;
import com.hurlant.crypto.cert.X509CertificateCollection;
import com.hurlant.crypto.prng.Random;
import com.hurlant.util.ArrayUtil;
import com.hurlant.util.Hex;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.ProgressEvent;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
import com.hurlant.crypto.prng.ARC4;
[Event(name="close", type="flash.events.Event")]
[Event(name="socketData", type="flash.events.ProgressEvent")]
[Event(name="ready", type="com.hurlant.crypto.tls.TLSEvent")]
[Event(name="data", type="com.hurlant.crypto.tls.TLSEvent")]
/**
* The heart of the TLS protocol.
* This class can work in server or client mode.
*
* This doesn't fully implement the TLS protocol.
*
* Things missing that I'd like to add:
* - support for client-side certificates
* - general code clean-up to make sure we don't have gaping securite holes
*
* Things that aren't there that I won't add:
* - support for "export" cypher suites (deprecated in later TLS versions)
* - support for "anon" cypher suites (deprecated in later TLS versions)
*
* Things that I'm unsure about adding later:
* - compression. Compressing encrypted streams is barely worth the CPU cycles.
* - diffie-hellman based key exchange mechanisms. Nifty, but would we miss it?
*
* @author henri
*
*/
public class TLSEngine extends EventDispatcher {
public static const SERVER:uint = 0;
public static const CLIENT:uint = 1;
public var protocol_version:uint;
private static const PROTOCOL_HANDSHAKE:uint = 22;
private static const PROTOCOL_ALERT:uint = 21;
private static const PROTOCOL_CHANGE_CIPHER_SPEC:uint = 20;
private static const PROTOCOL_APPLICATION_DATA:uint = 23;
private static const STATE_NEW:uint = 0; // brand new. nothing happened yet
private static const STATE_NEGOTIATING:uint = 1; // we're figuring out what to use
private static const STATE_READY:uint = 2; // we're ready for AppData stuff to go over us.
private static const STATE_CLOSED:uint = 3; // we're done done.
private var _entity:uint; // SERVER | CLIENT
private var _config:TLSConfig;
private var _state:uint;
private var _securityParameters:ISecurityParameters;
private var _currentReadState:IConnectionState;
private var _currentWriteState:IConnectionState;
private var _pendingReadState:IConnectionState;
private var _pendingWriteState:IConnectionState;
private var _handshakePayloads:ByteArray;
private var _handshakeRecords:ByteArray; // For client-side certificate verify
private var _iStream:IDataInput;
private var _oStream:IDataOutput;
// temporary store for X509 certs received by this engine.
private var _store:X509CertificateCollection;
// the main certificate received from the other side.
private var _otherCertificate:X509Certificate;
public function get peerCertificate() : X509Certificate {
return _otherCertificate;
}
// If this isn't null, we expect this identity to be found in the Cert's Subject CN.
private var _otherIdentity:String;
// The client-side cert
private var _myCertficate:X509Certificate;
// My Identity
private var _myIdentity:String;
/**
*
* @param config A TLSConfig instance describing how we're supposed to work
* @param iStream An input stream to read TLS data from
* @param oStream An output stream to write TLS data to
* @param otherIdentity An optional identifier. If set, this will be checked against the Subject CN of the other side's certificate.
*
*/
function TLSEngine(config:TLSConfig, iStream:IDataInput, oStream:IDataOutput, otherIdentity:String = null) {
_entity = config.entity;
_config = config;
_iStream = iStream;
_oStream = oStream;
_otherIdentity = otherIdentity;
_state = STATE_NEW;
// Pick the right set of callbacks
_entityHandshakeHandlers = _entity == CLIENT ? handshakeHandlersClient : handshakeHandlersServer;
// setting up new security parameters needs to be controlled by...something.
if (_config.version == SSLSecurityParameters.PROTOCOL_VERSION) {
_securityParameters = new SSLSecurityParameters(_entity);
} else {
_securityParameters = new TLSSecurityParameters(_entity, _config.certificate, _config.privateKey);
}
protocol_version = _config.version;
// So this...why is it here, other than to preclude a possible null pointer situation?
var states:Object = _securityParameters.getConnectionStates();
_currentReadState = states.read;
_currentWriteState = states.write;
_handshakePayloads = new ByteArray;
_store = new X509CertificateCollection;
}
/**
* This starts the TLS negotiation for a TLS Client.
*
* This is a no-op for a TLS Server.
*
*/
public function start():void {
if (_entity == CLIENT) {
try {
startHandshake();
} catch (e:TLSError) {
handleTLSError(e);
}
}
}
public function dataAvailable(e:* = null):void {
if (_state == STATE_CLOSED) return; // ignore
try {
parseRecord(_iStream);
} catch (e:TLSError) {
handleTLSError(e);
}
}
public function close(e:TLSError = null):void {
if (_state == STATE_CLOSED) return; // ignore
// ok. send an Alert to let the peer know
var rec:ByteArray = new ByteArray;
if (e==null && _state != STATE_READY) {
// use canceled while handshaking. be nice about it
rec[0] = 1;
rec[1] = TLSError.user_canceled;
sendRecord(PROTOCOL_ALERT, rec);
}
rec[0] = 2;
if (e == null) {
rec[1] = TLSError.close_notify;
} else {
rec[1] = e.errorID;
trace("TLSEngine shutdown triggered by "+e);
}
sendRecord(PROTOCOL_ALERT, rec);
_state = STATE_CLOSED;
dispatchEvent(new Event(Event.CLOSE));
}
private var _packetQueue:Array = [];
private function parseRecord(stream:IDataInput):void {
var p:ByteArray;
while(_state!=STATE_CLOSED && stream.bytesAvailable>4) {
if (_packetQueue.length>0) {
var packet:Object = _packetQueue.shift();
p = packet.data;
if (stream.bytesAvailable+p.length>=packet.length) {
// we have a whole packet. put together.
stream.readBytes(p, p.length, packet.length-p.length);
parseOneRecord(packet.type, packet.length, p);
// do another loop to parse any leftover record
continue;
} else {
// not enough. grab the data and park it.
stream.readBytes(p, p.length, stream.bytesAvailable);
_packetQueue.push(packet);
continue;
}
}
var type:uint = stream.readByte();
var ver:uint = stream.readShort();
var length:uint = stream.readShort();
if (length>16384+2048) { // support compression and encryption overhead.
throw new TLSError("Excessive TLS Record length: "+length, TLSError.record_overflow);
}
// Can pretty much assume that if I'm here, I've got a default config, so let's use it.
if (ver != _securityParameters.version ) {
throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
}
p = new ByteArray;
var actualLength:uint = Math.min(stream.bytesAvailable, length);
stream.readBytes(p, 0, actualLength);
if (actualLength == length) {
parseOneRecord(type, length, p);
} else {
_packetQueue.push({type:type, length:length, data:p});
}
}
}
// Protocol handler map, provides a mapping of protocol types to individual packet handlers
private var protocolHandlers:Object = { 23 : parseApplicationData, // PROTOCOL_APPLICATION_DATA
22 : parseHandshake, // PROTOCOL_HANDSHAKE
21 : parseAlert, // PROTOCOL_ALERT
20 : parseChangeCipherSpec }; // PROTOCOL_CHANGE_CIPHER_SPEC
/**
* Modified to support the notion of a handler map(see above ), since it makes for better clarity (IMHO of course).
*/
private function parseOneRecord(type:uint, length:uint, p:ByteArray):void {
p = _currentReadState.decrypt(type, length, p);
if (p.length>16384) {
throw new TLSError("Excessive Decrypted TLS Record length: "+p.length, TLSError.record_overflow);
}
if (protocolHandlers.hasOwnProperty( type )) {
while( p != null)
p = protocolHandlers[ type ]( p );
} else {
throw new TLSError("Unsupported TLS Record Content Type: "+type.toString( 16 ), TLSError.unexpected_message);
}
}
///////// handshake handling
// session identifier
// peer certificate
// compression method
// cipher spec
// master secret
// is resumable
private static const HANDSHAKE_HELLO_REQUEST:uint = 0;
private static const HANDSHAKE_CLIENT_HELLO:uint = 1;
private static const HANDSHAKE_SERVER_HELLO:uint = 2;
private static const HANDSHAKE_CERTIFICATE:uint = 11;
private static const HANDSHAKE_SERVER_KEY_EXCHANGE:uint = 12;
private static const HANDSHAKE_CERTIFICATE_REQUEST:uint = 13;
private static const HANDSHAKE_HELLO_DONE:uint = 14;
private static const HANDSHAKE_CERTIFICATE_VERIFY:uint = 15;
private static const HANDSHAKE_CLIENT_KEY_EXCHANGE:uint = 16;
private static const HANDSHAKE_FINISHED:uint = 20;
// Server handshake handler map
private var handshakeHandlersServer:Object = { 0 : notifyStateError, // HANDSHAKE_HELLO_REQUEST
1 : parseHandshakeClientHello, // HANDSHAKE_CLIENT_HELLO
2 : notifyStateError, // HANDSHAKE_SERVER_HELLO
11 : loadCertificates, // HANDSHAKE_CERTIFICATE
12 : notifyStateError, // HANDSHAKE_SERVER_KEY_EXCHANGE
13 : notifyStateError, // HANDSHAKE_CERTIFICATE_REQUEST
14 : notifyStateError, // HANDSHAKE_HELLO_DONE
15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
16 : parseHandshakeClientKeyExchange, // HANDSHAKE_CLIENT_KEY_EXCHANGE
20 : verifyHandshake // HANDSHAKE_FINISHED
};
// Client handshake handler map
private var handshakeHandlersClient:Object = { 0 : parseHandshakeHello, // HANDSHAKE_HELLO_REQUEST
1 : notifyStateError, // HANDSHAKE_CLIENT_HELLO
2 : parseHandshakeServerHello, // HANDSHAKE_SERVER_HELLO
11 : loadCertificates, // HANDSHAKE_CERTIFICATE
12 : parseServerKeyExchange, // HANDSHAKE_SERVER_KEY_EXCHANGE
13 : setStateRespondWithCertificate, // HANDSHAKE_CERTIFICATE
14 : sendClientAck, // HANDSHAKE_HELLO_DONE
15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
16 : notifyStateError, // HANDSHAKE_CLIENT_KEY_EXCHANGE
20 : verifyHandshake // HANDSHAKE_FINISHED
};
private var _entityHandshakeHandlers:Object;
private var _handshakeCanContinue:Boolean = true; // For handling cases where I might need to pause processing during a handshake (cert issues, etc.).
private var _handshakeQueue:Array = [];
/**
* The handshake is always started by the client.
*/
private function startHandshake():void {
_state = STATE_NEGOTIATING;
// reset some other handshake state. XXX
sendClientHello();
}
/**
* Handle the incoming handshake packet.
*
*/
private function parseHandshake(p:ByteArray):ByteArray {
if (p.length<4) {
trace("Handshake packet is way too short. bailing.");
return null;
}
p.position = 0;
var rec:ByteArray = p;
var type:uint = rec.readUnsignedByte();
var tmp:uint = rec.readUnsignedByte();
var length:uint = (tmp<<16) | rec.readUnsignedShort();
if (length+4>p.length) {
// partial read.
trace("Handshake packet is incomplete. bailing.");
return null;
}
// we need to copy the record, to have a valid FINISHED exchange.
if (type!=HANDSHAKE_FINISHED) {
_handshakePayloads.writeBytes(p, 0, length+4);
}
// Surf the handler map and find the right handler for this handshake packet type.
// I modified the individual handlers so they encapsulate all possible knowledge
// about the incoming packet type, so no previous handling or massaging of the data
// is required, as was the case using the switch statement. BP
if (_entityHandshakeHandlers.hasOwnProperty( type )) {
if (_entityHandshakeHandlers[ type ] is Function)
_entityHandshakeHandlers[ type ]( rec );
} else {
throw new TLSError( "Unimplemented or unknown handshake type!", TLSError.internal_error );
}
// Get set up for the next packet.
if (length+4<p.length) {
var n:ByteArray = new ByteArray;
n.writeBytes(p,length+4, p.length-(length+4));
return n;
} else {
return null;
}
}
/**
* Throw an error when the detected handshake state isn't a valid state for the given entity type (client vs. server, etc. ).
* This really should abort the handshake, since there's no case in which a server should EVER be confused about the type of entity it is. BP
*/
private function notifyStateError( rec:ByteArray ) : void {
throw new TLSError( "Invalid handshake state for a TLS Entity type of " + _entity, TLSError.internal_error );
}
/**
* two unimplemented functions
*/
private function parseClientKeyExchange( rec:ByteArray ) : void {
throw new TLSError( "ClientKeyExchange is currently unimplemented!", TLSError.internal_error );
}
private function parseServerKeyExchange( rec:ByteArray ) : void {
throw new TLSError( "ServerKeyExchange is currently unimplemented!", TLSError.internal_error );
}
/**
* Test the server's Finished message for validity against the data we know about. Only slightly rewritten. BP
*/
private function verifyHandshake( rec:ByteArray):void {
// Get the Finished message
var verifyData:ByteArray = new ByteArray;
// This, in the vain hope that noboby is using SSL 2 anymore
if (_securityParameters.version == SSLSecurityParameters.PROTOCOL_VERSION) {
rec.readBytes(verifyData, 0, 36); // length should be (in fact, better be) 16 + 20 (md5-size + sha1-size)
} else { // presuming TLS
rec.readBytes(verifyData, 0, 12);
}
var data:ByteArray = _securityParameters.computeVerifyData(1-_entity, _handshakePayloads);
if (ArrayUtil.equals(verifyData, data)) {
_state = STATE_READY;
dispatchEvent(new TLSEvent(TLSEvent.READY));
} else {
throw new TLSError("Invalid Finished mac.", TLSError.bad_record_mac);
}
}
// enforceClient/enforceServer removed in favor of state-driven function maps
/**
* Handle a HANDSHAKE_HELLO
*/
private function parseHandshakeHello( rec:ByteArray ) : void {
if (_state != STATE_READY) {
trace("Received an HELLO_REQUEST before being in state READY. ignoring.");
return;
}
_handshakePayloads = new ByteArray;
startHandshake();
}
/**
* Handle a HANDSHAKE_CLIENT_KEY_EXCHANGE
*/
private function parseHandshakeClientKeyExchange(rec:ByteArray):void {
if (_securityParameters.useRSA) {
// skip 2 bytes for length.
var len:uint = rec.readShort();
var cipher:ByteArray = new ByteArray;
rec.readBytes(cipher, 0, len);
var preMasterSecret:ByteArray = new ByteArray;
_config.privateKey.decrypt(cipher, preMasterSecret, len);
_securityParameters.setPreMasterSecret(preMasterSecret);
// now is a good time to get our pending states
var o:Object = _securityParameters.getConnectionStates();
_pendingReadState = o.read;
_pendingWriteState = o.write;
} else {
throw new TLSError("parseHandshakeClientKeyExchange not implemented for DH modes.", TLSError.internal_error);
}
}
/**
* Handle HANDSHAKE_SERVER_HELLO - client-side
*/
private function parseHandshakeServerHello( rec:IDataInput ) : void {
var ver:uint = rec.readShort();
if (ver != _securityParameters.version) {
throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
}
var random:ByteArray = new ByteArray;
rec.readBytes(random, 0, 32);
var session_length:uint = rec.readByte();
var session:ByteArray = new ByteArray;
if (session_length > 0) {
// some implementations don't assign a session ID
rec.readBytes(session, 0, session_length);
}
_securityParameters.setCipher(rec.readShort());
_securityParameters.setCompression(rec.readByte());
_securityParameters.setServerRandom(random);
}
/**
* Handle HANDSHAKE_CLIENT_HELLO - server side
*/
private function parseHandshakeClientHello( rec:IDataInput ) : void {
var ret:Object;
var ver:uint = rec.readShort();
if (ver != _securityParameters.version) {
throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
}
var random:ByteArray = new ByteArray;
rec.readBytes(random, 0, 32);
var session_length:uint = rec.readByte();
var session:ByteArray = new ByteArray;
if (session_length > 0) {
// some implementations don't assign a session ID
rec.readBytes(session, 0, session_length);
}
var suites:Array = [];
var suites_length:uint = rec.readShort();
for (var i:uint=0;i<suites_length/2;i++) {
suites.push(rec.readShort());
}
var compressions:Array = [];
var comp_length:uint = rec.readByte();
for (i=0;i<comp_length;i++) {
compressions.push(rec.readByte());
}
ret = {random:random, session:session, suites:suites, compressions:compressions};
var sofar:uint = 2+32+1+session_length+2+suites_length+1+comp_length;
var extensions:Array = [];
if (sofar<length) {
// we have extensions. great.
var ext_total_length:uint = rec.readShort();
while (ext_total_length>0) {
var ext_type:uint = rec.readShort();
var ext_length:uint = rec.readShort();
var ext_data:ByteArray = new ByteArray;
rec.readBytes(ext_data, 0, ext_length);
ext_total_length -= 4+ext_length;
extensions.push({type:ext_type, length:ext_length, data:ext_data});
}
}
ret.ext = extensions;
sendServerHello(ret);
sendCertificate();
// TODO: Modify to handle case of requesting a certificate from the client, for "client authentication",
// and testing purposes, will probably never actually need it.
sendServerHelloDone();
}
private function sendClientHello():void {
var rec:ByteArray = new ByteArray;
// version - modified to support version attribute from ISecurityParameters
rec.writeShort(_securityParameters.version);
// random
var prng:Random = new Random;
var clientRandom:ByteArray = new ByteArray;
prng.nextBytes(clientRandom, 32);
_securityParameters.setClientRandom(clientRandom);
rec.writeBytes(clientRandom,0,32);
// session
rec.writeByte(32);
prng.nextBytes(rec, 32);
// Cipher suites
var cs:Array = _config.cipherSuites;
rec.writeShort(2* cs.length);
for (var i:int=0;i<cs.length;i++) {
rec.writeShort(cs[i]);
}
// Compression
cs = _config.compressions;
rec.writeByte(cs.length);
for (i=0;i<cs.length;i++) {
rec.writeByte(cs[i]);
}
// no extensions, yet.
rec.position = 0;
sendHandshake(HANDSHAKE_CLIENT_HELLO, rec.length, rec);
}
private function findMatch(a1:Array, a2:Array):int {
for (var i:int=0;i<a1.length;i++) {
var e:uint = a1[i];
if (a2.indexOf(e)>-1) {
return e;
}
}
return -1;
}
private function sendServerHello(v:Object):void {
var cipher:int = findMatch(_config.cipherSuites, v.suites);
if (cipher == -1) {
throw new TLSError("No compatible cipher found.", TLSError.handshake_failure);
}
_securityParameters.setCipher(cipher);
var comp:int = findMatch(_config.compressions, v.compressions);
if (comp == 01) {
throw new TLSError("No compatible compression method found.", TLSError.handshake_failure);
}
_securityParameters.setCompression(comp);
_securityParameters.setClientRandom(v.random);
var rec:ByteArray = new ByteArray;
rec.writeShort(_securityParameters.version);
var prng:Random = new Random;
var serverRandom:ByteArray = new ByteArray;
prng.nextBytes(serverRandom, 32);
_securityParameters.setServerRandom(serverRandom);
rec.writeBytes(serverRandom,0,32);
// session
rec.writeByte(32);
prng.nextBytes(rec, 32);
// Cipher suite
rec.writeShort(v.suites[0]);
// Compression
rec.writeByte(v.compressions[0]);
rec.position = 0;
sendHandshake(HANDSHAKE_SERVER_HELLO, rec.length, rec);
}
private var sendClientCert:Boolean = false;
private function setStateRespondWithCertificate( r:ByteArray = null) : void {
sendClientCert = true;
}
private function sendCertificate( r:ByteArray = null ):void {
var cert:ByteArray = _config.certificate;
var len:uint;
var len2:uint;
var rec:ByteArray = new ByteArray;
// Look for a certficate chain, if we have one, send it, if we don't, send an empty record.
if (cert != null) {
len = cert.length;
len2 = cert.length + 3;
rec.writeByte(len2>>16);
rec.writeShort(len2&65535);
rec.writeByte(len>>16);
rec.writeShort(len&65535);
rec.writeBytes(cert);
} else {
rec.writeShort( 0 );
rec.writeByte( 0 );
}
rec.position = 0;
sendHandshake(HANDSHAKE_CERTIFICATE, rec.length, rec);
}
private function sendCertificateVerify():void {
var rec:ByteArray = new ByteArray();
// Encrypt the handshake payloads here
var data:ByteArray = _securityParameters.computeCertificateVerify(_entity, _handshakePayloads);
data.position=0;
sendHandshake(HANDSHAKE_CERTIFICATE_VERIFY, data.length, data);
}
private function sendServerHelloDone():void {
var rec:ByteArray = new ByteArray;
sendHandshake(HANDSHAKE_HELLO_DONE, rec.length, rec);
}
private function sendClientKeyExchange():void {
if (_securityParameters.useRSA) {
var p:ByteArray = new ByteArray;
p.writeShort(_securityParameters.version);
var prng:Random = new Random;
prng.nextBytes(p, 46);
p.position = 0;
var preMasterSecret:ByteArray = new ByteArray;
preMasterSecret.writeBytes(p, 0, p.length);
preMasterSecret.position = 0;
_securityParameters.setPreMasterSecret(preMasterSecret);
var enc_key:ByteArray = new ByteArray;
_otherCertificate.getPublicKey().encrypt(preMasterSecret, enc_key, preMasterSecret.length);
enc_key.position = 0;
var rec:ByteArray = new ByteArray;
// TLS requires the size of the premaster key be sent BUT
// SSL 3.0 does not
if (_securityParameters.version > 0x0300) {
rec.writeShort(enc_key.length);
}
rec.writeBytes(enc_key, 0, enc_key.length);
rec.position=0;
sendHandshake(HANDSHAKE_CLIENT_KEY_EXCHANGE, rec.length, rec);
// now is a good time to get our pending states
var o:Object = _securityParameters.getConnectionStates();
_pendingReadState = o.read;
_pendingWriteState = o.write;
} else {
throw new TLSError("Non-RSA Client Key Exchange not implemented.", TLSError.internal_error);
}
}
private function sendFinished():void {
var data:ByteArray = _securityParameters.computeVerifyData(_entity, _handshakePayloads);
data.position=0;
sendHandshake(HANDSHAKE_FINISHED, data.length, data);
}
private function sendHandshake(type:uint, len:uint, payload:IDataInput):void {
var rec:ByteArray = new ByteArray;
rec.writeByte(type);
rec.writeByte(0);
rec.writeShort(len);
payload.readBytes(rec, rec.position, len);
_handshakePayloads.writeBytes(rec, 0, rec.length);
sendRecord(PROTOCOL_HANDSHAKE, rec);
}
private function sendChangeCipherSpec():void {
var rec:ByteArray = new ByteArray;
rec[0] = 1;
sendRecord(PROTOCOL_CHANGE_CIPHER_SPEC, rec);
// right after, switch the cipher for writing.
_currentWriteState = _pendingWriteState;
_pendingWriteState = null;
}
public function sendApplicationData(data:ByteArray, offset:uint=0, length:uint=0):void {
var rec:ByteArray = new ByteArray;
var len:uint = length;
// BIG FAT WARNING: Patch from Arlen Cuss ALA As3crypto group on Google code.
// This addresses data overflow issues when the packet size hits the max length boundary.
if (len == 0) len = data.length;
while (len>16384) {
rec.position = 0;
rec.writeBytes(data, offset, 16384);
rec.position = 0;
sendRecord(PROTOCOL_APPLICATION_DATA, rec);
offset += 16384;
len -= 16384;
}
rec.position = 0;
rec.writeBytes(data, offset, len);
// trace("Data I'm sending..." + Hex.fromArray( data ));
rec.position = 0;
sendRecord(PROTOCOL_APPLICATION_DATA, rec);
}
private function sendRecord(type:uint, payload:ByteArray):void {
// encrypt
payload = _currentWriteState.encrypt(type, payload);
_oStream.writeByte(type);
_oStream.writeShort(_securityParameters.version);
_oStream.writeShort(payload.length);
_oStream.writeBytes(payload, 0, payload.length);
scheduleWrite();
}
private var _writeScheduler:uint;
private function scheduleWrite():void {
if (_writeScheduler!=0) return;
_writeScheduler = setTimeout(commitWrite, 0);
}
private function commitWrite():void {
clearTimeout(_writeScheduler);
_writeScheduler = 0;
if (_state != STATE_CLOSED) {
dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
}
}
private function sendClientAck( rec:ByteArray ):void {
if ( _handshakeCanContinue ) {
// If I have a pending cert request, send it
if (sendClientCert)
sendCertificate();
// send a client key exchange
sendClientKeyExchange();
// Send the certificate verify, if we have one
if (_config.certificate != null)
sendCertificateVerify();
// send a change cipher spec
sendChangeCipherSpec();
// send a finished
sendFinished();
}
}
/**
* Vaguely gross function that parses a RSA key out of a certificate.
*
* As long as that certificate looks just the way we expect it to.
*
*/
private function loadCertificates( rec:ByteArray ):void {
var tmp:uint = rec.readByte();
var certs_len:uint = (tmp<<16) | rec.readShort();
var certs:Array = [];
while (certs_len>0) {
tmp = rec.readByte();
var cert_len:uint = (tmp<<16) | rec.readShort();
var cert:ByteArray = new ByteArray;
rec.readBytes(cert, 0, cert_len);
certs.push(cert);
certs_len -= 3 + cert_len;
}
var firstCert:X509Certificate = null;
for (var i:int=0;i<certs.length;i++) {
var x509:X509Certificate = new X509Certificate(certs[i]);
_store.addCertificate(x509);
if (firstCert==null) {
firstCert = x509;
}
}
// Test first for trust override parameters
// This nice trust override stuff comes from Joey Parrish via As3crypto forums
var certTrusted:Boolean;
if (_config.trustAllCertificates) {
certTrusted = true; // Blatantly trust everything
} else if (_config.trustSelfSignedCertificates ) {
// Self-signed certs
certTrusted = firstCert.isSelfSigned(new Date);
} else {
// Certs with a signer in the CA store - realistically, I should setup an event chain to handle this
certTrusted = firstCert.isSigned(_store, _config.CAStore );
}
// Good so far
if (certTrusted) {
// ok, that's encouraging. now for the hostname match.
if (_otherIdentity==null || _config.ignoreCommonNameMismatch ) {
// we don't care who we're talking with. groovy.
_otherCertificate = firstCert;
} else {
// use regex to handle wildcard certs
var commonName:String = firstCert.getCommonName();
// replace all regex special characters with escaped version, except for asterisk
// replace the asterisk with a regex sequence to match one or more non-dot characters
var commonNameRegex:RegExp = new RegExp( commonName.replace(/[\^\\\-$.[\]|()?+{}]/g, "\\$&").replace(/\*/g, "[^.]+"), "gi");
if (commonNameRegex.exec(_otherIdentity)) {
_otherCertificate = firstCert;
} else {
if (_config.promptUserForAcceptCert ) {
_handshakeCanContinue = false;
dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
} else {
throw new TLSError("Invalid common name: "+firstCert.getCommonName()+", expected "+_otherIdentity, TLSError.bad_certificate);
}
}
}
} else {
// Let's ask the user if we can accept this cert. I'm not certain of the behaviour in case of timeouts,
// so I probably need to handle the case by killing and restarting the connection rather than continuing if it becomes
// an issue. We shall see. BP
if (_config.promptUserForAcceptCert) {
_handshakeCanContinue = false;
dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
} else {
// Cannot continue, die.
throw new TLSError("Cannot verify certificate", TLSError.bad_certificate);
}
}
}
// Accept the peer cert, and keep going
public function acceptPeerCertificate() : void {
_handshakeCanContinue = true;
sendClientAck( null );
}
// Step off biotch! No trust for you!
public function rejectPeerCertificate() : void {
throw new TLSError("Peer certificate not accepted!", TLSError.bad_certificate);
}
private function parseAlert(p:ByteArray):void {
//throw new Error("Alert not implemented.");
// 7.2
trace("GOT ALERT! type="+p[1]);
close();
}
private function parseChangeCipherSpec(p:ByteArray):void {
p.readUnsignedByte();
if (_pendingReadState==null) {
throw new TLSError("Not ready to Change Cipher Spec, damnit.", TLSError.unexpected_message);
}
_currentReadState = _pendingReadState;
_pendingReadState = null;
// 7.1
}
private function parseApplicationData(p:ByteArray):void {
if (_state != STATE_READY) {
throw new TLSError("Too soon for data!", TLSError.unexpected_message);
return;
}
dispatchEvent(new TLSEvent(TLSEvent.DATA, p));
}
private function handleTLSError(e:TLSError):void {
// basic rules to keep things simple:
// - Make a good faith attempt at notifying peers
// - TLSErrors are always fatal.
// BP: Meh...not always. Common Name mismatches appear to be common on servers. Instead of closing, let's pause, and ask for confirmation
// before we tear the connection down.
close(e);
}
}
}
\ No newline at end of file
/**
* TLSError
*
* A error that can be thrown when something wrong happens in the TLS protocol.
* This is handled in TLSEngine by generating a TLS ALERT as appropriate.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
public class TLSError extends Error {
public static const close_notify:uint = 0;
public static const unexpected_message:uint = 10;
public static const bad_record_mac:uint = 20;
public static const decryption_failed:uint = 21;
public static const record_overflow:uint = 22;
public static const decompression_failure:uint = 30;
public static const handshake_failure:uint = 40;
public static const bad_certificate:uint = 42;
public static const unsupported_certificate:uint = 43;
public static const certificate_revoked:uint = 44;
public static const certificate_expired:uint = 45;
public static const certificate_unknown:uint = 46;
public static const illegal_parameter:uint = 47;
public static const unknown_ca:uint = 48;
public static const access_denied:uint = 49;
public static const decode_error:uint = 50;
public static const decrypt_error:uint = 51;
public static const protocol_version:uint = 70;
public static const insufficient_security:uint = 71;
public static const internal_error:uint = 80;
public static const user_canceled:uint = 90;
public static const no_renegotiation:uint = 100;
public function TLSError(message:String, id:int) {
super(message,id);
}
}
}
\ No newline at end of file
/**
* TLSEvent
*
* This is used by TLSEngine to let the application layer know
* when we're ready for sending, or have received application data
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.utils.ByteArray;
public class TLSEvent extends Event {
static public const DATA:String = "data";
static public const READY:String = "ready";
static public const PROMPT_ACCEPT_CERT:String = "promptAcceptCert";
public var data:ByteArray;
public function TLSEvent(type:String, data:ByteArray = null) {
this.data = data;
super(type, false, false);
}
}
}
\ No newline at end of file
/**
* TLSSecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* Patched by Bobby Parker (sh0rtwave@gmail.com)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.crypto.prng.TLSPRF;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import com.hurlant.crypto.rsa.RSAKey;
public class TLSSecurityParameters implements ISecurityParameters {
// COMPRESSION
public static const COMPRESSION_NULL:uint = 0;
// This is probably not smart. Revise this to use all settings from TLSConfig, since this shouldn't really know about
// user settings, those are best handled from the engine at a session level.
public static var IGNORE_CN_MISMATCH:Boolean = true;
public static var ENABLE_USER_CLIENT_CERTIFICATE:Boolean = false;
public static var USER_CERTIFICATE:String;
private var cert:ByteArray; // Local Cert
private var key:RSAKey; // local key
private var entity:uint; // SERVER | CLIENT
private var bulkCipher:uint; // BULK_CIPHER_*
private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER
private var keySize:uint;
private var keyMaterialLength:uint;
private var IVSize:uint;
private var macAlgorithm:uint; // MAC_*
private var hashSize:uint;
private var compression:uint; // COMPRESSION_NULL
private var masterSecret:ByteArray; // 48 bytes
private var clientRandom:ByteArray; // 32 bytes
private var serverRandom:ByteArray; // 32 bytes
private var ignoreCNMismatch:Boolean = true;
private var trustAllCerts:Boolean = false;
private var trustSelfSigned:Boolean = false;
public static const PROTOCOL_VERSION:uint = 0x0301;
private var tlsDebug:Boolean = false;
// not strictly speaking part of this, but yeah.
public var keyExchange:uint;
public function TLSSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:RSAKey = null) {
this.entity = entity;
reset();
key = localKey;
cert = localCert;
}
public function get version() : uint {
return PROTOCOL_VERSION;
}
public function reset():void {
bulkCipher = BulkCiphers.NULL;
cipherType = BulkCiphers.BLOCK_CIPHER;
macAlgorithm = MACs.NULL;
compression = COMPRESSION_NULL;
masterSecret = null;
}
public function getBulkCipher():uint {
return bulkCipher;
}
public function getCipherType():uint {
return cipherType;
}
public function getMacAlgorithm():uint {
return macAlgorithm;
}
public function setCipher(cipher:uint):void {
bulkCipher = CipherSuites.getBulkCipher(cipher);
cipherType = BulkCiphers.getType(bulkCipher);
keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8
keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5
IVSize = BulkCiphers.getIVSize(bulkCipher);
keyExchange = CipherSuites.getKeyExchange(cipher);
macAlgorithm = CipherSuites.getMac(cipher);
hashSize = MACs.getHashSize(macAlgorithm);
}
public function setCompression(algo:uint):void {
compression = algo;
}
public function setPreMasterSecret(secret:ByteArray):void {
// compute master_secret
var seed:ByteArray = new ByteArray;
seed.writeBytes(clientRandom, 0, clientRandom.length);
seed.writeBytes(serverRandom, 0, serverRandom.length);
var prf:TLSPRF = new TLSPRF(secret, "master secret", seed);
masterSecret = new ByteArray;
prf.nextBytes(masterSecret, 48);
if (tlsDebug)
trace("Master Secret: " + Hex.fromArray( masterSecret, true ));
}
public function setClientRandom(secret:ByteArray):void {
clientRandom = secret;
}
public function setServerRandom(secret:ByteArray):void {
serverRandom = secret;
}
public function get useRSA():Boolean {
return KeyExchanges.useRSA(keyExchange);
}
public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
var seed:ByteArray = new ByteArray;
var md5:MD5 = new MD5;
if (tlsDebug)
trace("Handshake value: " + Hex.fromArray(handshakeMessages, true ));
seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());
var sha:SHA1 = new SHA1;
seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());
if (tlsDebug)
trace("Seed in: " + Hex.fromArray(seed, true ));
var prf:TLSPRF = new TLSPRF(masterSecret, (side==TLSEngine.CLIENT) ? "client finished" : "server finished", seed);
var out:ByteArray = new ByteArray;
prf.nextBytes(out, 12);
if (tlsDebug)
trace("Finished out: " + Hex.fromArray(out, true ));
out.position = 0;
return out;
}
// client side certficate check - This is probably incorrect somehow
public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
var seed:ByteArray = new ByteArray;
var md5:MD5 = new MD5;
seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());
var sha:SHA1 = new SHA1;
seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());
// Now that I have my hashes of existing handshake messages (which I'm not sure about the length of yet) then
// Sign that with my private key
seed.position = 0;
var out:ByteArray = new ByteArray();
key.sign( seed, out, seed.bytesAvailable);
out.position = 0;
return out;
}
public function getConnectionStates():Object {
if (masterSecret != null) {
var seed:ByteArray = new ByteArray;
seed.writeBytes(serverRandom, 0, serverRandom.length);
seed.writeBytes(clientRandom, 0, clientRandom.length);
var prf:TLSPRF = new TLSPRF(masterSecret, "key expansion", seed);
var client_write_MAC:ByteArray = new ByteArray;
prf.nextBytes(client_write_MAC, hashSize);
var server_write_MAC:ByteArray = new ByteArray;
prf.nextBytes(server_write_MAC, hashSize);
var client_write_key:ByteArray = new ByteArray;
prf.nextBytes(client_write_key, keyMaterialLength);
var server_write_key:ByteArray = new ByteArray;
prf.nextBytes(server_write_key, keyMaterialLength);
var client_write_IV:ByteArray = new ByteArray;
prf.nextBytes(client_write_IV, IVSize);
var server_write_IV:ByteArray = new ByteArray;
prf.nextBytes(server_write_IV, IVSize);
var client_write:TLSConnectionState = new TLSConnectionState(
bulkCipher, cipherType, macAlgorithm,
client_write_MAC, client_write_key, client_write_IV);
var server_write:TLSConnectionState = new TLSConnectionState(
bulkCipher, cipherType, macAlgorithm,
server_write_MAC, server_write_key, server_write_IV);
if (entity == TLSEngine.CLIENT) {
return {read:server_write, write:client_write};
} else {
return {read:client_write, write:server_write};
}
} else {
return {read:new TLSConnectionState, write:new TLSConnectionState};
}
}
}
}
\ No newline at end of file
/**
* TLSSocket
*
* This is the "end-user" TLS class.
* It works just like a Socket, by encapsulating a Socket and
* wrapping the TLS protocol around the data that passes over it.
* This class can either create a socket connection, or reuse an
* existing connected socket. The later is useful for STARTTLS flows.
*
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.ObjectEncoding;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.Endian;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
import com.hurlant.crypto.cert.X509Certificate;
[Event(name="close", type="flash.events.Event")]
[Event(name="connect", type="flash.events.Event")]
[Event(name="ioError", type="flash.events.IOErrorEvent")]
[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
[Event(name="socketData", type="flash.events.ProgressEvent")]
[Event(name="acceptPeerCertificatePrompt", type="flash.events.Event")]
/**
* It feels like a socket, but it wraps the stream
* over TLS 1.0
*
* That's all.
*
*/
public class TLSSocket extends Socket implements IDataInput, IDataOutput {
private var _endian:String;
private var _objectEncoding:uint;
private var _iStream:ByteArray;
private var _oStream:ByteArray;
private var _iStream_cursor:uint;
private var _socket:Socket;
private var _config:TLSConfig;
private var _engine:TLSEngine;
public static const ACCEPT_PEER_CERT_PROMPT:String = "acceptPeerCertificatePrompt"
public function TLSSocket(host:String = null, port:int = 0, config:TLSConfig = null) {
_config = config;
if (host!=null && port!=0) {
connect(host, port);
}
}
override public function get bytesAvailable():uint {
return _iStream.bytesAvailable;
}
override public function get connected():Boolean {
return _socket.connected;
}
override public function get endian():String {
return _endian;
}
override public function set endian(value:String):void {
_endian = value;
_iStream.endian = value;
_oStream.endian = value;
}
override public function get objectEncoding():uint {
return _objectEncoding;
}
override public function set objectEncoding(value:uint):void {
_objectEncoding = value;
_iStream.objectEncoding = value;
_oStream.objectEncoding = value;
}
private function onTLSData(event:TLSEvent):void {
if (_iStream.position == _iStream.length) {
_iStream.position = 0;
_iStream.length = 0;
_iStream_cursor = 0;
}
var cursor:uint = _iStream.position;
_iStream.position = _iStream_cursor;
_iStream.writeBytes(event.data);
_iStream_cursor = _iStream.position;
_iStream.position = cursor;
dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, event.data.length));
}
private function onTLSReady(event:TLSEvent):void {
_ready = true;
scheduleWrite();
}
private function onTLSClose(event:Event):void {
dispatchEvent(event);
// trace("Received TLS close");
close();
}
private var _ready:Boolean;
private var _writeScheduler:uint;
private function scheduleWrite():void {
if (_writeScheduler!=0) return;
_writeScheduler = setTimeout(commitWrite, 0);
}
private function commitWrite():void {
clearTimeout(_writeScheduler);
_writeScheduler = 0;
if (_ready) {
_engine.sendApplicationData(_oStream);
_oStream.length = 0;
}
}
override public function close():void {
_ready = false;
_engine.close();
if (_socket.connected) {
_socket.flush();
_socket.close();
}
}
public function setTLSConfig( config:TLSConfig) : void {
_config = config;
}
override public function connect(host:String, port:int):void {
init(new Socket, _config, host);
_socket.connect(host, port);
_engine.start();
}
public function releaseSocket() : void {
_socket.removeEventListener(Event.CONNECT, dispatchEvent);
_socket.removeEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_socket.removeEventListener(Event.CLOSE, dispatchEvent);
_socket.removeEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);
_socket = null;
}
public function reinitialize(host:String, config:TLSConfig) : void {
// Reinitialize the connection using new values
// but re-use the existing socket
// Doubt this is useful in any valid context other than my specific case (VMWare)
var ba:ByteArray = new ByteArray;
if (_socket.bytesAvailable > 0) {
_socket.readBytes(ba, 0, _socket.bytesAvailable);
}
// Do nothing with it.
_iStream = new ByteArray;
_oStream = new ByteArray;
_iStream_cursor = 0;
objectEncoding = ObjectEncoding.DEFAULT;
endian = Endian.BIG_ENDIAN;
/*
_socket.addEventListener(Event.CONNECT, dispatchEvent);
_socket.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_socket.addEventListener(Event.CLOSE, dispatchEvent);
*/
if (config == null) {
config = new TLSConfig(TLSEngine.CLIENT);
}
_engine = new TLSEngine(config, _socket, _socket, host);
_engine.addEventListener(TLSEvent.DATA, onTLSData);
_engine.addEventListener(TLSEvent.READY, onTLSReady);
_engine.addEventListener(Event.CLOSE, onTLSClose);
_engine.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { _socket.flush(); });
_socket.addEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);
_engine.addEventListener( TLSEvent.PROMPT_ACCEPT_CERT, onAcceptCert );
_ready = false;
_engine.start();
}
public function startTLS(socket:Socket, host:String, config:TLSConfig = null):void {
if (!socket.connected) {
throw new Error("Cannot STARTTLS on a socket that isn't connected.");
}
init(socket, config, host);
_engine.start();
}
private function init(socket:Socket, config:TLSConfig, host:String):void {
_iStream = new ByteArray;
_oStream = new ByteArray;
_iStream_cursor = 0;
objectEncoding = ObjectEncoding.DEFAULT;
endian = Endian.BIG_ENDIAN;
_socket = socket;
_socket.addEventListener(Event.CONNECT, dispatchEvent);
_socket.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_socket.addEventListener(Event.CLOSE, dispatchEvent);
if (config == null) {
config = new TLSConfig(TLSEngine.CLIENT);
}
_engine = new TLSEngine(config, _socket, _socket, host);
_engine.addEventListener(TLSEvent.DATA, onTLSData);
_engine.addEventListener( TLSEvent.PROMPT_ACCEPT_CERT, onAcceptCert );
_engine.addEventListener(TLSEvent.READY, onTLSReady);
_engine.addEventListener(Event.CLOSE, onTLSClose);
_engine.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { if(connected) _socket.flush(); });
_socket.addEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);
_ready = false;
}
override public function flush():void {
commitWrite();
_socket.flush();
}
override public function readBoolean():Boolean {
return _iStream.readBoolean();
}
override public function readByte():int {
return _iStream.readByte();
}
override public function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void {
return _iStream.readBytes(bytes, offset, length);
}
override public function readDouble():Number {
return _iStream.readDouble();
}
override public function readFloat():Number {
return _iStream.readFloat();
}
override public function readInt():int {
return _iStream.readInt();
}
override public function readMultiByte(length:uint, charSet:String):String {
return _iStream.readMultiByte(length, charSet);
}
override public function readObject():* {
return _iStream.readObject();
}
override public function readShort():int {
return _iStream.readShort();
}
override public function readUnsignedByte():uint {
return _iStream.readUnsignedByte();
}
override public function readUnsignedInt():uint {
return _iStream.readUnsignedInt();
}
override public function readUnsignedShort():uint {
return _iStream.readUnsignedShort();
}
override public function readUTF():String {
return _iStream.readUTF();
}
override public function readUTFBytes(length:uint):String {
return _iStream.readUTFBytes(length);
}
override public function writeBoolean(value:Boolean):void {
_oStream.writeBoolean(value);
scheduleWrite();
}
override public function writeByte(value:int):void {
_oStream.writeByte(value);
scheduleWrite();
}
override public function writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void {
_oStream.writeBytes(bytes, offset, length);
scheduleWrite();
}
override public function writeDouble(value:Number):void {
_oStream.writeDouble(value);
scheduleWrite();
}
override public function writeFloat(value:Number):void {
_oStream.writeFloat(value);
scheduleWrite();
}
override public function writeInt(value:int):void {
_oStream.writeInt(value);
scheduleWrite();
}
override public function writeMultiByte(value:String, charSet:String):void {
_oStream.writeMultiByte(value, charSet);
scheduleWrite();
}
override public function writeObject(object:*):void {
_oStream.writeObject(object);
scheduleWrite();
}
override public function writeShort(value:int):void {
_oStream.writeShort(value);
scheduleWrite();
}
override public function writeUnsignedInt(value:uint):void {
_oStream.writeUnsignedInt(value);
scheduleWrite();
}
override public function writeUTF(value:String):void {
_oStream.writeUTF(value);
scheduleWrite();
}
override public function writeUTFBytes(value:String):void {
_oStream.writeUTFBytes(value);
scheduleWrite();
}
public function getPeerCertificate() : X509Certificate {
return _engine.peerCertificate;
}
public function onAcceptCert( event:TLSEvent ) : void {
dispatchEvent( new TLSSocketEvent( _engine.peerCertificate ) );
}
// These are just a passthroughs to the engine. Encapsulation, et al
public function acceptPeerCertificate( event:Event ) : void {
_engine.acceptPeerCertificate();
}
public function rejectPeerCertificate( event:Event ) : void {
_engine.rejectPeerCertificate();
}
}
}
/**
* TLSEvent
*
* This is used by TLSEngine to let the application layer know
* when we're ready for sending, or have received application data
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.utils.ByteArray;
import com.hurlant.crypto.cert.X509Certificate;
public class TLSSocketEvent extends Event {
static public const PROMPT_ACCEPT_CERT:String = "promptAcceptCert";
public var cert:X509Certificate;
public function TLSSocketEvent( cert:X509Certificate = null) {
super(PROMPT_ACCEPT_CERT, false, false);
this.cert = cert;
}
}
}
\ No newline at end of file
/**
* TLSTest
*
* A test class for TLS. Not a finished product.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.cert.X509Certificate;
import com.hurlant.crypto.cert.X509CertificateCollection;
import com.hurlant.util.Hex;
import com.hurlant.util.der.PEM;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.getTimer;
public class TLSTest {
public var myDebugData:String;
//[Embed(source="/src/host.cert",mimeType="application/octet-stream")]
public var myCert:Class;
//[Embed(source="/src/host.key",mimeType="application/octet-stream")]
public var myKey:Class;
public function TLSTest(host:String = null, port:int = 0, type:int = 0 ) {
//loopback();
if (host != null) {
if (type == 0) { // SSL 3.0
connectLoginYahooCom();
// connectLocalSSL(host, port);
} else {
connectLocalTLS(host, port);
}
} else {
testSocket();
}
}
public function connectLoginYahooCom():void {
trace("Connecting test socket");
var s:Socket = new Socket("esx.bluebearllc.net", 903);
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT,
null,
null,
null,
null,
null,
SSLSecurityParameters.PROTOCOL_VERSION);
var client:TLSEngine = new TLSEngine(clientConfig, s, s);
// hook some events.
s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
client.start();
}
public function connectLocalTLS(host:String, port:int):void {
var s:Socket = new Socket(host, port);
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT);
var client:TLSEngine = new TLSEngine(clientConfig, s, s);
// hook some events.
s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
client.start();
}
public function connectLocalSSL(host:String, port:int):void {
var s:Socket = new Socket(host, port);
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT,
null,
null,
null,
null,
null,
SSLSecurityParameters.PROTOCOL_VERSION);
var client:TLSEngine = new TLSEngine(clientConfig, s, s);
// hook some events.
s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
client.start();
}
public function loopback():void {
var server_write:ByteArray = new ByteArray;
var client_write:ByteArray = new ByteArray;
var server_write_cursor:uint = 0;
var client_write_cursor:uint = 0;
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
var serverConfig:TLSConfig = new TLSConfig(TLSEngine.SERVER, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
var cert:ByteArray = new myCert;
var key:ByteArray = new myKey;
serverConfig.setPEMCertificate(cert.readUTFBytes(cert.length), key.readUTFBytes(key.length));
// tmp, for debugging. currently useless
cert.position = 0;
key.position = 0;
clientConfig.setPEMCertificate(cert.readUTFBytes(cert.length), key.readUTFBytes(key.length));
// put the server cert in the client's trusted store, to keep things happy.
clientConfig.CAStore = new X509CertificateCollection;
cert.position = 0;
var x509:X509Certificate = new X509Certificate(PEM.readCertIntoArray(cert.readUTFBytes(cert.length)));
clientConfig.CAStore.addCertificate(x509);
var server:TLSEngine = new TLSEngine(serverConfig, client_write, server_write);
var client:TLSEngine = new TLSEngine(clientConfig, server_write, client_write);
server.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*=null):void {
trace("server wrote something!");
trace(Hex.fromArray(server_write));
var l:uint = server_write.position;
server_write.position = server_write_cursor;
client.dataAvailable(e);
server_write.position = l;
server_write_cursor = l;
});
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*=null):void {
trace("client wrote something!");
trace(Hex.fromArray(client_write));
var l:uint = client_write.position;
client_write.position = client_write_cursor;
server.dataAvailable(e);
client_write.position = l;
client_write_cursor = l;
});
server.start();
client.start();
}
public function testSocket():void {
var hosts:Array = [
"bugs.adobe.com", // apache
"login.yahoo.com", // apache, bigger response
"login.live.com", // IIS-6, chain of 3 certs
"banking.wellsfargo.com", // custom, sends its CA cert along for the ride.
"www.bankofamerica.com" // sun-one, chain of 3 certs
];
var i:int =0;
(function next():void {
testHost(hosts[i++], next);
})();
}
private function testHost(host:String, next:Function):void {
if (host==null) return;
var t1:int = getTimer();
var host:String = host;
var t:TLSSocket = new TLSSocket;
t.connect(host, 4433);
t.writeUTFBytes("GET / HTTP/1.0\nHost: "+host+"\n\n");
t.addEventListener(Event.CLOSE, function(e:*):void {
var s:String = t.readUTFBytes(t.bytesAvailable);
trace("Response from "+host+": "+s.length+" characters");
var bytes:ByteArray = new ByteArray();
t.readBytes(bytes, 0, t.bytesAvailable);
trace(Hex.fromArray(bytes));
trace("Time used = "+(getTimer()-t1)+"ms");
next();
});
}
}
}
\ No newline at end of file
/**
* BulkCiphers
*
* An enumeration of bulk ciphers available for TLS, along with their properties,
* with a few convenience methods to go with it.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.TLSPad;
import com.hurlant.crypto.symmetric.SSLPad;
public class BulkCiphers {
public static const STREAM_CIPHER:uint = 0;
public static const BLOCK_CIPHER:uint = 1;
public static const NULL:uint = 0;
public static const RC4_40:uint = 1;
public static const RC4_128:uint = 2
public static const RC2_CBC_40:uint = 3; // XXX I don't have that one.
public static const DES_CBC:uint = 4;
public static const DES3_EDE_CBC:uint = 5;
public static const DES40_CBC:uint = 6;
public static const IDEA_CBC:uint = 7; // XXX I don't have that one.
public static const AES_128:uint = 8;
public static const AES_256:uint = 9;
private static const algos:Array =
['', 'rc4', 'rc4', '', 'des-cbc', '3des-cbc', 'des-cbc', '', 'aes', 'aes'];
private static var _props:Array;
init();
private static function init():void {
_props = [];
_props[NULL] = new BulkCiphers(STREAM_CIPHER, 0, 0, 0, 0, 0);
_props[RC4_40] = new BulkCiphers(STREAM_CIPHER, 5, 16, 40, 0, 0);
_props[RC4_128] = new BulkCiphers(STREAM_CIPHER, 16, 16, 128, 0, 0);
_props[RC2_CBC_40] = new BulkCiphers( BLOCK_CIPHER, 5, 16, 40, 8, 8);
_props[DES_CBC] = new BulkCiphers( BLOCK_CIPHER, 8, 8, 56, 8, 8);
_props[DES3_EDE_CBC] = new BulkCiphers( BLOCK_CIPHER, 24, 24, 168, 8, 8);
_props[DES40_CBC] = new BulkCiphers( BLOCK_CIPHER, 5, 8, 40, 8, 8);
_props[IDEA_CBC] = new BulkCiphers( BLOCK_CIPHER, 16, 16, 128, 8, 8);
_props[AES_128] = new BulkCiphers( BLOCK_CIPHER, 16, 16, 128, 16, 16);
_props[AES_256] = new BulkCiphers( BLOCK_CIPHER, 32, 32, 256, 16, 16);
}
private static function getProp(cipher:uint):BulkCiphers {
var p:BulkCiphers = _props[cipher];
if (p==null) {
throw new Error("Unknown bulk cipher "+cipher.toString(16));
}
return p;
}
public static function getType(cipher:uint):uint {
return getProp(cipher).type;
}
public static function getKeyBytes(cipher:uint):uint {
return getProp(cipher).keyBytes;
}
public static function getExpandedKeyBytes(cipher:uint):uint {
return getProp(cipher).expandedKeyBytes;
}
public static function getEffectiveKeyBits(cipher:uint):uint {
return getProp(cipher).effectiveKeyBits;
}
public static function getIVSize(cipher:uint):uint {
return getProp(cipher).IVSize;
}
public static function getBlockSize(cipher:uint):uint {
return getProp(cipher).blockSize;
}
public static function getCipher(cipher:uint, key:ByteArray, proto:uint):ICipher {
if (proto == TLSSecurityParameters.PROTOCOL_VERSION) {
return Crypto.getCipher(algos[cipher], key, new TLSPad);
} else {
return Crypto.getCipher(algos[cipher], key, new SSLPad);
}
}
private var type:uint;
private var keyBytes:uint;
private var expandedKeyBytes:uint;
private var effectiveKeyBits:uint;
private var IVSize:uint;
private var blockSize:uint;
public function BulkCiphers(t:uint, kb:uint, ekb:uint, fkb:uint, ivs:uint, bs:uint) {
type = t;
keyBytes = kb;
expandedKeyBytes = ekb;
effectiveKeyBits = fkb;
IVSize = ivs;
blockSize = bs;
}
}
}
/**
* CipherSuites
*
* An enumeration of cipher-suites available for TLS to use, along with
* their properties, and some convenience methods
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
public class CipherSuites {
// only the lines marked "ok" are currently implemented.
// rfc 2246
public static const TLS_NULL_WITH_NULL_NULL:uint = 0x0000; // ok
public static const TLS_RSA_WITH_NULL_MD5:uint = 0x0001; // ok
public static const TLS_RSA_WITH_NULL_SHA:uint = 0x0002; // ok
public static const TLS_RSA_WITH_RC4_128_MD5:uint = 0x0004; // ok
public static const TLS_RSA_WITH_RC4_128_SHA:uint = 0x0005; // ok
public static const TLS_RSA_WITH_IDEA_CBC_SHA:uint = 0x0007;
public static const TLS_RSA_WITH_DES_CBC_SHA:uint = 0x0009; // ok
public static const TLS_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x000A; // ok
public static const TLS_DH_DSS_WITH_DES_CBC_SHA:uint = 0x000C;
public static const TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:uint = 0x000D;
public static const TLS_DH_RSA_WITH_DES_CBC_SHA:uint = 0x000F;
public static const TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x0010;
public static const TLS_DHE_DSS_WITH_DES_CBC_SHA:uint = 0x0012;
public static const TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:uint = 0x0013;
public static const TLS_DHE_RSA_WITH_DES_CBC_SHA:uint = 0x0015;
public static const TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:uint = 0x0016;
public static const TLS_DH_anon_WITH_RC4_128_MD5:uint = 0x0018;
public static const TLS_DH_anon_WITH_DES_CBC_SHA:uint = 0x001A;
public static const TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:uint = 0x001B;
// rfc3268
public static const TLS_RSA_WITH_AES_128_CBC_SHA:uint = 0x002F; // ok
public static const TLS_DH_DSS_WITH_AES_128_CBC_SHA:uint = 0x0030;
public static const TLS_DH_RSA_WITH_AES_128_CBC_SHA:uint = 0x0031;
public static const TLS_DHE_DSS_WITH_AES_128_CBC_SHA:uint = 0x0032;
public static const TLS_DHE_RSA_WITH_AES_128_CBC_SHA:uint = 0x0033;
public static const TLS_DH_anon_WITH_AES_128_CBC_SHA:uint = 0x0034;
public static const TLS_RSA_WITH_AES_256_CBC_SHA:uint = 0x0035; // ok
public static const TLS_DH_DSS_WITH_AES_256_CBC_SHA:uint = 0x0036;
public static const TLS_DH_RSA_WITH_AES_256_CBC_SHA:uint = 0x0037;
public static const TLS_DHE_DSS_WITH_AES_256_CBC_SHA:uint = 0x0038;
public static const TLS_DHE_RSA_WITH_AES_256_CBC_SHA:uint = 0x0039;
public static const TLS_DH_anon_WITH_AES_256_CBC_SHA:uint = 0x003A;
private static var _props:Array;
init();
private static function init():void {
_props = [];
_props[TLS_NULL_WITH_NULL_NULL] = new CipherSuites(BulkCiphers.NULL, MACs.NULL, KeyExchanges.NULL);
_props[TLS_RSA_WITH_NULL_MD5] = new CipherSuites(BulkCiphers.NULL, MACs.MD5, KeyExchanges.RSA);
_props[TLS_RSA_WITH_NULL_SHA] = new CipherSuites(BulkCiphers.NULL, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_RC4_128_MD5] = new CipherSuites(BulkCiphers.RC4_128, MACs.MD5, KeyExchanges.RSA);
_props[TLS_RSA_WITH_RC4_128_SHA] = new CipherSuites(BulkCiphers.RC4_128, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_DES_CBC_SHA] = new CipherSuites(BulkCiphers.DES_CBC, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_3DES_EDE_CBC_SHA] = new CipherSuites(BulkCiphers.DES3_EDE_CBC, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_AES_128_CBC_SHA] = new CipherSuites(BulkCiphers.AES_128, MACs.SHA1, KeyExchanges.RSA);
_props[TLS_RSA_WITH_AES_256_CBC_SHA] = new CipherSuites(BulkCiphers.AES_256, MACs.SHA1, KeyExchanges.RSA);
// ...
// more later
}
private static function getProp(cipher:uint):CipherSuites {
var p:CipherSuites = _props[cipher];
if (p==null) {
throw new Error("Unknown cipher "+cipher.toString(16));
}
return p;
}
public static function getBulkCipher(cipher:uint):uint {
return getProp(cipher).cipher;
}
public static function getMac(cipher:uint):uint {
return getProp(cipher).hash;
}
public static function getKeyExchange(cipher:uint):uint {
return getProp(cipher).key;
}
public static function getDefaultSuites():Array {
// a list of acceptable ciphers, sorted by preference.
return [
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_3DES_EDE_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
TLS_RSA_WITH_RC4_128_SHA,
TLS_RSA_WITH_RC4_128_MD5,
TLS_RSA_WITH_DES_CBC_SHA
];
}
public var cipher:uint;
public var hash:uint;
public var key:uint;
public function CipherSuites(cipher:uint, hash:uint, key:uint) {
this.cipher = cipher;
this.hash = hash;
this.key = key;
}
}
}
/**
* IConnectionState
*
* Interface for TLS/SSL Connection states.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.ByteArray;
public interface IConnectionState {
function decrypt(type:uint, length:uint, p:ByteArray) : ByteArray;
function encrypt(type:uint, p:ByteArray) : ByteArray;
}
}
\ No newline at end of file
/**
* ISecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.ByteArray;
public interface ISecurityParameters {
function get version() : uint;
function reset():void;
function getBulkCipher():uint;
function getCipherType():uint;
function getMacAlgorithm():uint;
function setCipher(cipher:uint):void;
function setCompression(algo:uint):void;
function setPreMasterSecret(secret:ByteArray):void;
function setClientRandom(secret:ByteArray):void;
function setServerRandom(secret:ByteArray):void;
function get useRSA():Boolean;
function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray;
function computeCertificateVerify( side:uint, handshakeRecords:ByteArray):ByteArray;
function getConnectionStates():Object;
}
}
\ No newline at end of file
/**
* KeyExchanges
*
* An enumeration of key exchange methods defined by TLS
* ( right now, only RSA is actually implemented )
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
public class KeyExchanges {
public static const NULL:uint = 0;
public static const RSA:uint = 1;
public static const DH_DSS:uint = 2;
public static const DH_RSA:uint = 3;
public static const DHE_DSS:uint = 4;
public static const DHE_RSA:uint = 5;
public static const DH_anon:uint = 6;
public static function useRSA(p:uint):Boolean {
return (p==RSA);
}
}
}
\ No newline at end of file
/**
* MACs
*
* An enumeration of MACs implemented for TLS 1.0/SSL 3.0
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.Crypto;
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.MAC;
public class MACs {
public static const NULL:uint = 0;
public static const MD5:uint = 1;
public static const SHA1:uint = 2;
public static function getHashSize(hash:uint):uint {
return [0,16,20][hash];
}
public static function getPadSize(hash:uint):int {
return [0, 48, 40][hash];
}
public static function getHMAC(hash:uint):HMAC {
if (hash==NULL) return null;
return Crypto.getHMAC(['',"md5","sha1"][hash]);
}
public static function getMAC(hash:uint):MAC {
return Crypto.getMAC(['', "md5", "sha1"][hash]);
}
}
}
\ No newline at end of file
/**
* TLSConnectionState
*
* This class encapsulates the read or write state of a TLS connection,
* and implementes the encrypting and hashing of packets.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.IDataInput;
import flash.utils.ByteArray;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.MAC;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.util.Hex;
import com.hurlant.util.ArrayUtil;
public class SSLConnectionState implements IConnectionState {
// compression state
// cipher state
private var bulkCipher:uint;
private var cipherType:uint;
private var CIPHER_key:ByteArray;
private var CIPHER_IV:ByteArray;
private var cipher:ICipher;
private var ivmode:IVMode;
// mac secret
private var macAlgorithm:uint;
private var MAC_write_secret:ByteArray;
private var mac:MAC;
// sequence number. uint64
private var seq_lo:uint = 0x0;
private var seq_hi:uint = 0x0;
public function SSLConnectionState(
bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,
mac_enc:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {
this.bulkCipher = bulkCipher;
this.cipherType = cipherType;
this.macAlgorithm = macAlgorithm;
MAC_write_secret = mac_enc;
mac = MACs.getMAC(macAlgorithm);
CIPHER_key = key;
CIPHER_IV = IV;
cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0300);
if (cipher is IVMode) {
ivmode = cipher as IVMode;
ivmode.IV = IV;
}
}
public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {
// decompression is a nop.
if (cipherType == BulkCiphers.STREAM_CIPHER) {
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.decrypt(p);
}
} else {
p.position = 0;
// block cipher
if (bulkCipher == BulkCiphers.NULL) {
} else {
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
p.position = 0;
cipher.decrypt(p);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
}
if (macAlgorithm!=MACs.NULL) {
// there will be CTX delay here as well,
// I should probably optmize the hell out of it
var data:ByteArray = new ByteArray;
var len:uint = p.length - mac.getHashSize();
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
data.writeByte(type);
data.writeShort(len);
if (len!=0) {
data.writeBytes(p, 0, len);
}
var mac_enc:ByteArray = mac.compute(MAC_write_secret, data);
// compare "mac" with the last X bytes of p.
var mac_received:ByteArray = new ByteArray;
mac_received.writeBytes(p, len, mac.getHashSize());
if (ArrayUtil.equals(mac_enc, mac_received)) {
// happy happy joy joy
} else {
throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);
}
p.length = len;
p.position = 0;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
return p;
}
public function encrypt(type:uint, p:ByteArray):ByteArray {
var mac_enc:ByteArray = null;
if (macAlgorithm!=MACs.NULL) {
var data:ByteArray = new ByteArray;
// data.writeUnsignedInt(seq);
// Sequence
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
// Type
data.writeByte(type);
// Length
data.writeShort(p.length);
// The data
if (p.length!=0) {
data.writeBytes(p);
}
// trace("data for the MAC: " + Hex.fromArray(data));
mac_enc = mac.compute(MAC_write_secret, data);
// trace("MAC: " + Hex.fromArray( mac_enc ));
p.position = p.length;
p.writeBytes(mac_enc);
}
// trace("Record to encrypt: " + Hex.fromArray(p));
p.position = 0;
if (cipherType == BulkCiphers.STREAM_CIPHER) {
// stream cipher
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.encrypt(p);
}
} else {
// block cipher
cipher.encrypt(p);
// adjust IV
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
return p;
}
}
}
\ No newline at end of file
/**
* SSLEvent
*
* This is used by TLSEngine to let the application layer know
* when we're ready for sending, or have received application data
* This Event was created by Bobby Parker to support SSL 3.0.
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.utils.ByteArray;
public class SSLEvent extends Event {
static public const DATA:String = "data";
static public const READY:String = "ready";
public var data:ByteArray;
public function SSLEvent(type:String, data:ByteArray = null) {
this.data = data;
super(type, false, false);
}
}
}
\ No newline at end of file
/**
* TLSSecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
public class SSLSecurityParameters implements ISecurityParameters {
// COMPRESSION
public static const COMPRESSION_NULL:uint = 0;
private var entity:uint; // SERVER | CLIENT
private var bulkCipher:uint; // BULK_CIPHER_*
private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER
private var keySize:uint;
private var keyMaterialLength:uint;
private var keyBlock:ByteArray;
private var IVSize:uint;
private var MAC_length:uint;
private var macAlgorithm:uint; // MAC_*
private var hashSize:uint;
private var compression:uint; // COMPRESSION_NULL
private var masterSecret:ByteArray; // 48 bytes
private var clientRandom:ByteArray; // 32 bytes
private var serverRandom:ByteArray; // 32 bytes
private var pad_1:ByteArray; // varies
private var pad_2:ByteArray; // varies
private var ignoreCNMismatch:Boolean = true;
private var trustAllCerts:Boolean = false;
private var trustSelfSigned:Boolean = false;
public static const PROTOCOL_VERSION:uint = 0x0300;
// not strictly speaking part of this, but yeah.
public var keyExchange:uint;
public function get version() : uint {
return PROTOCOL_VERSION;
}
public function SSLSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:ByteArray = null) {
this.entity = entity;
reset();
}
public function reset():void {
bulkCipher = BulkCiphers.NULL;
cipherType = BulkCiphers.BLOCK_CIPHER;
macAlgorithm = MACs.NULL;
compression = COMPRESSION_NULL;
masterSecret = null;
}
public function getBulkCipher():uint {
return bulkCipher;
}
public function getCipherType():uint {
return cipherType;
}
public function getMacAlgorithm():uint {
return macAlgorithm;
}
public function setCipher(cipher:uint):void {
bulkCipher = CipherSuites.getBulkCipher(cipher);
cipherType = BulkCiphers.getType(bulkCipher);
keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8
keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5
IVSize = BulkCiphers.getIVSize(bulkCipher);
keyExchange = CipherSuites.getKeyExchange(cipher);
macAlgorithm = CipherSuites.getMac(cipher);
hashSize = MACs.getHashSize(macAlgorithm);
pad_1 = new ByteArray();
pad_2 = new ByteArray();
for (var x:int = 0; x < 48; x++) {
pad_1.writeByte(0x36);
pad_2.writeByte(0x5c);
}
}
public function setCompression(algo:uint):void {
compression = algo;
}
public function setPreMasterSecret(secret:ByteArray):void {
/* Warning! Following code may cause madness
Tread not here, unless ye be men of valor.
***** Official Prophylactic Comment ******
(to protect the unwary...this code actually works, that's all you need to know)
This does two things, computes the master secret, and generates the keyBlock
To compute the master_secret, the following algorithm is used.
for SSL 3, this means
master = MD5( premaster + SHA1('A' + premaster + client_random + server_random ) ) +
MD5( premaster + SHA1('BB' + premaster + client_random + server_random ) ) +
MD5( premaster + SHA1('CCC' + premaster + client_random + server_random ) )
*/
var tempHashA:ByteArray = new ByteArray(); // temporary hash, gets reused a lot
var tempHashB:ByteArray = new ByteArray(); // temporary hash, gets reused a lot
var shaHash:ByteArray;
var mdHash:ByteArray;
var i:int;
var j:int;
var sha:SHA1 = new SHA1();
var md:MD5 = new MD5();
var k:ByteArray = new ByteArray();
k.writeBytes(secret);
k.writeBytes(clientRandom);
k.writeBytes(serverRandom);
masterSecret = new ByteArray();
var pad_char:uint = 0x41;
for ( i = 0; i < 3; i++) {
// SHA portion
tempHashA.position = 0;
for ( j = 0; j < i + 1; j++) {
tempHashA.writeByte(pad_char);
}
pad_char++;
tempHashA.writeBytes(k);
shaHash = sha.hash(tempHashA);
// MD5 portion
tempHashB.position = 0;
tempHashB.writeBytes(secret);
tempHashB.writeBytes(shaHash);
mdHash = md.hash(tempHashB);
// copy into my key
masterSecret.writeBytes(mdHash);
}
// *************** END MASTER SECRET **************
// More prophylactic comments
// *************** START KEY BLOCK ****************
// So here, I'm setting up the keyBlock array that I will derive MACs, keys, and IVs from.
// Rebuild k (hash seed)
k.position = 0;
k.writeBytes(masterSecret);
k.writeBytes(serverRandom);
k.writeBytes(clientRandom);
keyBlock = new ByteArray();
tempHashA = new ByteArray();
tempHashB = new ByteArray();
// now for 16 iterations to get 256 bytes (16 * 16), better to have more than not enough
pad_char = 0x41;
for ( i = 0; i < 16; i++) {
tempHashA.position = 0;
for ( j = 0; j < i + 1; j++) {
tempHashA.writeByte(pad_char);
}
pad_char++;
tempHashA.writeBytes(k);
shaHash = sha.hash(tempHashA);
tempHashB.position = 0;
tempHashB.writeBytes(masterSecret);
tempHashB.writeBytes(shaHash, 0);
mdHash = md.hash(tempHashB);
keyBlock.writeBytes(mdHash);
}
}
public function setClientRandom(secret:ByteArray):void {
clientRandom = secret;
}
public function setServerRandom(secret:ByteArray):void {
serverRandom = secret;
}
public function get useRSA():Boolean {
return KeyExchanges.useRSA(keyExchange);
}
// This is the Finished message
// if you value your sanity, stay away...far away
public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
// for SSL 3.0, this consists of
// finished = md5( masterSecret + pad2 + md5( handshake + sender + masterSecret + pad1 ) ) +
// sha1( masterSecret + pad2 + sha1( handshake + sender + masterSecret + pad1 ) )
// trace("Handshake messages: " + Hex.fromArray(handshakeMessages));
var sha:SHA1 = new SHA1();
var md:MD5 = new MD5();
var k:ByteArray = new ByteArray(); // handshake + sender + masterSecret + pad1
var j:ByteArray = new ByteArray(); // masterSecret + pad2 + k
var innerKey:ByteArray;
var outerKey:ByteArray = new ByteArray();
var hashSha:ByteArray;
var hashMD:ByteArray;
var sideBytes:ByteArray = new ByteArray();
if (side == TLSEngine.CLIENT) {
sideBytes.writeUnsignedInt(0x434C4E54);
} else {
sideBytes.writeUnsignedInt(0x53525652);
}
// Do the SHA1 part of the routine first
masterSecret.position = 0;
k.writeBytes(handshakeMessages);
k.writeBytes(sideBytes);
k.writeBytes(masterSecret);
k.writeBytes(pad_1, 0, 40); // limited to 40 chars for SHA1
innerKey = sha.hash(k);
// trace("Inner SHA Key: " + Hex.fromArray(innerKey));
j.writeBytes(masterSecret);
j.writeBytes(pad_2, 0, 40); // limited to 40 chars for SHA1
j.writeBytes(innerKey);
hashSha = sha.hash(j);
// trace("Outer SHA Key: " + Hex.fromArray(hashSha));
// Rebuild k for MD5
k = new ByteArray();
k.writeBytes(handshakeMessages);
k.writeBytes(sideBytes);
k.writeBytes(masterSecret);
k.writeBytes(pad_1); // Take the whole length of pad_1 & pad_2 for MD5
innerKey = md.hash(k);
// trace("Inner MD5 Key: " + Hex.fromArray(innerKey));
j = new ByteArray();
j.writeBytes(masterSecret);
j.writeBytes(pad_2); // see above re: 48 byte pad
j.writeBytes(innerKey);
hashMD = md.hash(j);
// trace("Outer MD5 Key: " + Hex.fromArray(hashMD));
outerKey.writeBytes(hashMD, 0, hashMD.length);
outerKey.writeBytes(hashSha, 0, hashSha.length);
var out:String = Hex.fromArray(outerKey);
// trace("Finished Message: " + out);
outerKey.position = 0;
return outerKey;
}
public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
// TODO: Implement this, but I don't forsee it being necessary at this point in time, since for purposes
// of the override, I'm only going to use TLS
return null;
}
public function getConnectionStates():Object {
if (masterSecret != null) {
// so now, I have to derive the actual keys from the keyblock that I generated in setPremasterSecret.
// for MY purposes, I need RSA-AES 128/256 + SHA
// so I'm gonna have keylen = 32, minlen = 32, mac_length = 20, iv_length = 16
// but...I can get this data from the settings returned in the constructor when this object is
// It strikes me that TLS does this more elegantly...
var mac_length:int = hashSize as Number;
var key_length:int = keySize as Number;
var iv_length:int = IVSize as Number;
var client_write_MAC:ByteArray = new ByteArray();
var server_write_MAC:ByteArray = new ByteArray();
var client_write_key:ByteArray = new ByteArray();
var server_write_key:ByteArray = new ByteArray();
var client_write_IV:ByteArray = new ByteArray();
var server_write_IV:ByteArray = new ByteArray();
// Derive the keys from the keyblock
// Get the MACs first
keyBlock.position = 0;
keyBlock.readBytes(client_write_MAC, 0, mac_length);
keyBlock.readBytes(server_write_MAC, 0, mac_length);
// keyBlock.position is now at MAC_length * 2
// then get the keys
keyBlock.readBytes(client_write_key, 0, key_length);
keyBlock.readBytes(server_write_key, 0, key_length);
// keyBlock.position is now at (MAC_length * 2) + (keySize * 2)
// and then the IVs
keyBlock.readBytes(client_write_IV, 0, iv_length);
keyBlock.readBytes(server_write_IV, 0, iv_length);
// reset this in case it's needed, for some reason or another, but I doubt it
keyBlock.position = 0;
var client_write:SSLConnectionState = new SSLConnectionState(
bulkCipher, cipherType, macAlgorithm,
client_write_MAC, client_write_key, client_write_IV);
var server_write:SSLConnectionState = new SSLConnectionState(
bulkCipher, cipherType, macAlgorithm,
server_write_MAC, server_write_key, server_write_IV);
if (entity == TLSEngine.CLIENT) {
return {read:server_write, write:client_write};
} else {
return {read:client_write, write:server_write};
}
} else {
return {read:new SSLConnectionState, write:new SSLConnectionState};
}
}
}
}
\ No newline at end of file
/**
* TLSConfig
*
* A set of configuration parameters for use by a TLSSocket or a TLSEngine.
* Most parameters are optional and will be set to appropriate default values for most use.
*
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.ByteArray;
import com.hurlant.util.der.PEM;
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.crypto.cert.X509CertificateCollection;
import com.hurlant.crypto.cert.MozillaRootCertificates;
public class TLSConfig {
public var entity:uint; // SERVER | CLIENT
public var certificate:ByteArray;
public var privateKey:RSAKey;
public var cipherSuites:Array;
public var compressions:Array;
public var ignoreCommonNameMismatch:Boolean = false;
public var trustAllCertificates:Boolean = false;
public var trustSelfSignedCertificates:Boolean = false;
public var promptUserForAcceptCert:Boolean = false;
public var CAStore:X509CertificateCollection;
public var localKeyStore:X509CertificateCollection;
public var version:uint;
public function TLSConfig( entity:uint, cipherSuites:Array = null, compressions:Array = null,
certificate:ByteArray = null, privateKey:RSAKey = null, CAStore:X509CertificateCollection = null, ver:uint = 0x00) {
this.entity = entity;
this.cipherSuites = cipherSuites;
this.compressions = compressions;
this.certificate = certificate;
this.privateKey = privateKey;
this.CAStore = CAStore;
this.version = ver;
// default settings.
if (cipherSuites==null) {
this.cipherSuites = CipherSuites.getDefaultSuites();
}
if (compressions==null) {
this.compressions = [TLSSecurityParameters.COMPRESSION_NULL];
}
if (CAStore==null) {
this.CAStore = new MozillaRootCertificates;
}
if (ver==0x00) {
// Default to TLS
this.version = TLSSecurityParameters.PROTOCOL_VERSION;
}
}
public function setPEMCertificate(cert:String, key:String = null):void {
if (key == null) {
key = cert; // for folks who like to concat those two in one file.
}
certificate = PEM.readCertIntoArray(cert);
privateKey = PEM.readRSAPrivateKey(key);
}
}
}
/**
* TLSConnectionState
*
* This class encapsulates the read or write state of a TLS connection,
* and implementes the encrypting and hashing of packets.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.utils.IDataInput;
import flash.utils.ByteArray;
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.HMAC;
import com.hurlant.crypto.hash.IHash;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.util.Hex;
import com.hurlant.util.ArrayUtil;
public class TLSConnectionState implements IConnectionState {
// compression state
// cipher state
private var bulkCipher:uint;
private var cipherType:uint;
private var CIPHER_key:ByteArray;
private var CIPHER_IV:ByteArray;
private var cipher:ICipher;
private var ivmode:IVMode;
// mac secret
private var macAlgorithm:uint;
private var MAC_write_secret:ByteArray;
private var hmac:HMAC;
// sequence number. uint64
private var seq_lo:uint;
private var seq_hi:uint;
public function TLSConnectionState(
bulkCipher:uint=0, cipherType:uint=0, macAlgorithm:uint=0,
mac:ByteArray=null, key:ByteArray=null, IV:ByteArray=null) {
this.bulkCipher = bulkCipher;
this.cipherType = cipherType;
this.macAlgorithm = macAlgorithm;
MAC_write_secret = mac;
hmac = MACs.getHMAC(macAlgorithm);
CIPHER_key = key;
CIPHER_IV = IV;
cipher = BulkCiphers.getCipher(bulkCipher, key, 0x0301);
if (cipher is IVMode) {
ivmode = cipher as IVMode;
ivmode.IV = IV;
}
}
public function decrypt(type:uint, length:uint, p:ByteArray):ByteArray {
// decompression is a nop.
if (cipherType == BulkCiphers.STREAM_CIPHER) {
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.decrypt(p);
}
} else {
// block cipher
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
cipher.decrypt(p);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
if (macAlgorithm!=MACs.NULL) {
var data:ByteArray = new ByteArray;
var len:uint = p.length - hmac.getHashSize();
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
data.writeByte(type);
data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);
data.writeShort(len);
if (len!=0) {
data.writeBytes(p, 0, len);
}
var mac:ByteArray = hmac.compute(MAC_write_secret, data);
// compare "mac" with the last X bytes of p.
var mac_received:ByteArray = new ByteArray;
mac_received.writeBytes(p, len, hmac.getHashSize());
if (ArrayUtil.equals(mac, mac_received)) {
// happy happy joy joy
} else {
throw new TLSError("Bad Mac Data", TLSError.bad_record_mac);
}
p.length = len;
p.position = 0;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
return p;
}
public function encrypt(type:uint, p:ByteArray):ByteArray {
var mac:ByteArray = null;
if (macAlgorithm!=MACs.NULL) {
var data:ByteArray = new ByteArray;
data.writeUnsignedInt(seq_hi);
data.writeUnsignedInt(seq_lo);
data.writeByte(type);
data.writeShort(TLSSecurityParameters.PROTOCOL_VERSION);
data.writeShort(p.length);
if (p.length!=0) {
data.writeBytes(p, 0, p.length);
}
mac = hmac.compute(MAC_write_secret, data);
p.position = p.length;
p.writeBytes(mac);
}
p.position = 0;
if (cipherType == BulkCiphers.STREAM_CIPHER) {
// stream cipher
if (bulkCipher == BulkCiphers.NULL) {
// no-op
} else {
cipher.encrypt(p);
}
} else {
// block cipher
cipher.encrypt(p);
// adjust IV
var nextIV:ByteArray = new ByteArray;
nextIV.writeBytes(p, p.length-CIPHER_IV.length, CIPHER_IV.length);
CIPHER_IV = nextIV;
ivmode.IV = nextIV;
}
// increment seq
seq_lo++;
if (seq_lo==0) seq_hi++;
// compression is a nop.
return p;
}
}
}
\ No newline at end of file
/**
* TLSEngine
*
* A TLS protocol implementation.
* See comment below for some details.
* Copyright (c) 2007 Henri Torgemane
*
* Patched(heavily) by Bobby Parker (shortwave@gmail.com)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.cert.X509Certificate;
import com.hurlant.crypto.cert.X509CertificateCollection;
import com.hurlant.crypto.prng.Random;
import com.hurlant.util.ArrayUtil;
import com.hurlant.util.Hex;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.ProgressEvent;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
import com.hurlant.crypto.prng.ARC4;
[Event(name="close", type="flash.events.Event")]
[Event(name="socketData", type="flash.events.ProgressEvent")]
[Event(name="ready", type="com.hurlant.crypto.tls.TLSEvent")]
[Event(name="data", type="com.hurlant.crypto.tls.TLSEvent")]
/**
* The heart of the TLS protocol.
* This class can work in server or client mode.
*
* This doesn't fully implement the TLS protocol.
*
* Things missing that I'd like to add:
* - support for client-side certificates
* - general code clean-up to make sure we don't have gaping securite holes
*
* Things that aren't there that I won't add:
* - support for "export" cypher suites (deprecated in later TLS versions)
* - support for "anon" cypher suites (deprecated in later TLS versions)
*
* Things that I'm unsure about adding later:
* - compression. Compressing encrypted streams is barely worth the CPU cycles.
* - diffie-hellman based key exchange mechanisms. Nifty, but would we miss it?
*
* @author henri
*
*/
public class TLSEngine extends EventDispatcher {
public static const SERVER:uint = 0;
public static const CLIENT:uint = 1;
public var protocol_version:uint;
private static const PROTOCOL_HANDSHAKE:uint = 22;
private static const PROTOCOL_ALERT:uint = 21;
private static const PROTOCOL_CHANGE_CIPHER_SPEC:uint = 20;
private static const PROTOCOL_APPLICATION_DATA:uint = 23;
private static const STATE_NEW:uint = 0; // brand new. nothing happened yet
private static const STATE_NEGOTIATING:uint = 1; // we're figuring out what to use
private static const STATE_READY:uint = 2; // we're ready for AppData stuff to go over us.
private static const STATE_CLOSED:uint = 3; // we're done done.
private var _entity:uint; // SERVER | CLIENT
private var _config:TLSConfig;
private var _state:uint;
private var _securityParameters:ISecurityParameters;
private var _currentReadState:IConnectionState;
private var _currentWriteState:IConnectionState;
private var _pendingReadState:IConnectionState;
private var _pendingWriteState:IConnectionState;
private var _handshakePayloads:ByteArray;
private var _handshakeRecords:ByteArray; // For client-side certificate verify
private var _iStream:IDataInput;
private var _oStream:IDataOutput;
// temporary store for X509 certs received by this engine.
private var _store:X509CertificateCollection;
// the main certificate received from the other side.
private var _otherCertificate:X509Certificate;
public function get peerCertificate() : X509Certificate {
return _otherCertificate;
}
// If this isn't null, we expect this identity to be found in the Cert's Subject CN.
private var _otherIdentity:String;
// The client-side cert
private var _myCertficate:X509Certificate;
// My Identity
private var _myIdentity:String;
/**
*
* @param config A TLSConfig instance describing how we're supposed to work
* @param iStream An input stream to read TLS data from
* @param oStream An output stream to write TLS data to
* @param otherIdentity An optional identifier. If set, this will be checked against the Subject CN of the other side's certificate.
*
*/
function TLSEngine(config:TLSConfig, iStream:IDataInput, oStream:IDataOutput, otherIdentity:String = null) {
_entity = config.entity;
_config = config;
_iStream = iStream;
_oStream = oStream;
_otherIdentity = otherIdentity;
_state = STATE_NEW;
// Pick the right set of callbacks
_entityHandshakeHandlers = _entity == CLIENT ? handshakeHandlersClient : handshakeHandlersServer;
// setting up new security parameters needs to be controlled by...something.
if (_config.version == SSLSecurityParameters.PROTOCOL_VERSION) {
_securityParameters = new SSLSecurityParameters(_entity);
} else {
_securityParameters = new TLSSecurityParameters(_entity, _config.certificate, _config.privateKey);
}
protocol_version = _config.version;
// So this...why is it here, other than to preclude a possible null pointer situation?
var states:Object = _securityParameters.getConnectionStates();
_currentReadState = states.read;
_currentWriteState = states.write;
_handshakePayloads = new ByteArray;
_store = new X509CertificateCollection;
}
/**
* This starts the TLS negotiation for a TLS Client.
*
* This is a no-op for a TLS Server.
*
*/
public function start():void {
if (_entity == CLIENT) {
try {
startHandshake();
} catch (e:TLSError) {
handleTLSError(e);
}
}
}
public function dataAvailable(e:* = null):void {
if (_state == STATE_CLOSED) return; // ignore
try {
parseRecord(_iStream);
} catch (e:TLSError) {
handleTLSError(e);
}
}
public function close(e:TLSError = null):void {
if (_state == STATE_CLOSED) return; // ignore
// ok. send an Alert to let the peer know
var rec:ByteArray = new ByteArray;
if (e==null && _state != STATE_READY) {
// use canceled while handshaking. be nice about it
rec[0] = 1;
rec[1] = TLSError.user_canceled;
sendRecord(PROTOCOL_ALERT, rec);
}
rec[0] = 2;
if (e == null) {
rec[1] = TLSError.close_notify;
} else {
rec[1] = e.errorID;
trace("TLSEngine shutdown triggered by "+e);
}
sendRecord(PROTOCOL_ALERT, rec);
_state = STATE_CLOSED;
dispatchEvent(new Event(Event.CLOSE));
}
private var _packetQueue:Array = [];
private function parseRecord(stream:IDataInput):void {
var p:ByteArray;
while(_state!=STATE_CLOSED && stream.bytesAvailable>4) {
if (_packetQueue.length>0) {
var packet:Object = _packetQueue.shift();
p = packet.data;
if (stream.bytesAvailable+p.length>=packet.length) {
// we have a whole packet. put together.
stream.readBytes(p, p.length, packet.length-p.length);
parseOneRecord(packet.type, packet.length, p);
// do another loop to parse any leftover record
continue;
} else {
// not enough. grab the data and park it.
stream.readBytes(p, p.length, stream.bytesAvailable);
_packetQueue.push(packet);
continue;
}
}
var type:uint = stream.readByte();
var ver:uint = stream.readShort();
var length:uint = stream.readShort();
if (length>16384+2048) { // support compression and encryption overhead.
throw new TLSError("Excessive TLS Record length: "+length, TLSError.record_overflow);
}
// Can pretty much assume that if I'm here, I've got a default config, so let's use it.
if (ver != _securityParameters.version ) {
throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
}
p = new ByteArray;
var actualLength:uint = Math.min(stream.bytesAvailable, length);
stream.readBytes(p, 0, actualLength);
if (actualLength == length) {
parseOneRecord(type, length, p);
} else {
_packetQueue.push({type:type, length:length, data:p});
}
}
}
// Protocol handler map, provides a mapping of protocol types to individual packet handlers
private var protocolHandlers:Object = { 23 : parseApplicationData, // PROTOCOL_APPLICATION_DATA
22 : parseHandshake, // PROTOCOL_HANDSHAKE
21 : parseAlert, // PROTOCOL_ALERT
20 : parseChangeCipherSpec }; // PROTOCOL_CHANGE_CIPHER_SPEC
/**
* Modified to support the notion of a handler map(see above ), since it makes for better clarity (IMHO of course).
*/
private function parseOneRecord(type:uint, length:uint, p:ByteArray):void {
p = _currentReadState.decrypt(type, length, p);
if (p.length>16384) {
throw new TLSError("Excessive Decrypted TLS Record length: "+p.length, TLSError.record_overflow);
}
if (protocolHandlers.hasOwnProperty( type )) {
while( p != null)
p = protocolHandlers[ type ]( p );
} else {
throw new TLSError("Unsupported TLS Record Content Type: "+type.toString( 16 ), TLSError.unexpected_message);
}
}
///////// handshake handling
// session identifier
// peer certificate
// compression method
// cipher spec
// master secret
// is resumable
private static const HANDSHAKE_HELLO_REQUEST:uint = 0;
private static const HANDSHAKE_CLIENT_HELLO:uint = 1;
private static const HANDSHAKE_SERVER_HELLO:uint = 2;
private static const HANDSHAKE_CERTIFICATE:uint = 11;
private static const HANDSHAKE_SERVER_KEY_EXCHANGE:uint = 12;
private static const HANDSHAKE_CERTIFICATE_REQUEST:uint = 13;
private static const HANDSHAKE_HELLO_DONE:uint = 14;
private static const HANDSHAKE_CERTIFICATE_VERIFY:uint = 15;
private static const HANDSHAKE_CLIENT_KEY_EXCHANGE:uint = 16;
private static const HANDSHAKE_FINISHED:uint = 20;
// Server handshake handler map
private var handshakeHandlersServer:Object = { 0 : notifyStateError, // HANDSHAKE_HELLO_REQUEST
1 : parseHandshakeClientHello, // HANDSHAKE_CLIENT_HELLO
2 : notifyStateError, // HANDSHAKE_SERVER_HELLO
11 : loadCertificates, // HANDSHAKE_CERTIFICATE
12 : notifyStateError, // HANDSHAKE_SERVER_KEY_EXCHANGE
13 : notifyStateError, // HANDSHAKE_CERTIFICATE_REQUEST
14 : notifyStateError, // HANDSHAKE_HELLO_DONE
15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
16 : parseHandshakeClientKeyExchange, // HANDSHAKE_CLIENT_KEY_EXCHANGE
20 : verifyHandshake // HANDSHAKE_FINISHED
};
// Client handshake handler map
private var handshakeHandlersClient:Object = { 0 : parseHandshakeHello, // HANDSHAKE_HELLO_REQUEST
1 : notifyStateError, // HANDSHAKE_CLIENT_HELLO
2 : parseHandshakeServerHello, // HANDSHAKE_SERVER_HELLO
11 : loadCertificates, // HANDSHAKE_CERTIFICATE
12 : parseServerKeyExchange, // HANDSHAKE_SERVER_KEY_EXCHANGE
13 : setStateRespondWithCertificate, // HANDSHAKE_CERTIFICATE
14 : sendClientAck, // HANDSHAKE_HELLO_DONE
15 : notifyStateError, // HANDSHAKE_CERTIFICATE_VERIFY
16 : notifyStateError, // HANDSHAKE_CLIENT_KEY_EXCHANGE
20 : verifyHandshake // HANDSHAKE_FINISHED
};
private var _entityHandshakeHandlers:Object;
private var _handshakeCanContinue:Boolean = true; // For handling cases where I might need to pause processing during a handshake (cert issues, etc.).
private var _handshakeQueue:Array = [];
/**
* The handshake is always started by the client.
*/
private function startHandshake():void {
_state = STATE_NEGOTIATING;
// reset some other handshake state. XXX
sendClientHello();
}
/**
* Handle the incoming handshake packet.
*
*/
private function parseHandshake(p:ByteArray):ByteArray {
if (p.length<4) {
trace("Handshake packet is way too short. bailing.");
return null;
}
p.position = 0;
var rec:ByteArray = p;
var type:uint = rec.readUnsignedByte();
var tmp:uint = rec.readUnsignedByte();
var length:uint = (tmp<<16) | rec.readUnsignedShort();
if (length+4>p.length) {
// partial read.
trace("Handshake packet is incomplete. bailing.");
return null;
}
// we need to copy the record, to have a valid FINISHED exchange.
if (type!=HANDSHAKE_FINISHED) {
_handshakePayloads.writeBytes(p, 0, length+4);
}
// Surf the handler map and find the right handler for this handshake packet type.
// I modified the individual handlers so they encapsulate all possible knowledge
// about the incoming packet type, so no previous handling or massaging of the data
// is required, as was the case using the switch statement. BP
if (_entityHandshakeHandlers.hasOwnProperty( type )) {
if (_entityHandshakeHandlers[ type ] is Function)
_entityHandshakeHandlers[ type ]( rec );
} else {
throw new TLSError( "Unimplemented or unknown handshake type!", TLSError.internal_error );
}
// Get set up for the next packet.
if (length+4<p.length) {
var n:ByteArray = new ByteArray;
n.writeBytes(p,length+4, p.length-(length+4));
return n;
} else {
return null;
}
}
/**
* Throw an error when the detected handshake state isn't a valid state for the given entity type (client vs. server, etc. ).
* This really should abort the handshake, since there's no case in which a server should EVER be confused about the type of entity it is. BP
*/
private function notifyStateError( rec:ByteArray ) : void {
throw new TLSError( "Invalid handshake state for a TLS Entity type of " + _entity, TLSError.internal_error );
}
/**
* two unimplemented functions
*/
private function parseClientKeyExchange( rec:ByteArray ) : void {
throw new TLSError( "ClientKeyExchange is currently unimplemented!", TLSError.internal_error );
}
private function parseServerKeyExchange( rec:ByteArray ) : void {
throw new TLSError( "ServerKeyExchange is currently unimplemented!", TLSError.internal_error );
}
/**
* Test the server's Finished message for validity against the data we know about. Only slightly rewritten. BP
*/
private function verifyHandshake( rec:ByteArray):void {
// Get the Finished message
var verifyData:ByteArray = new ByteArray;
// This, in the vain hope that noboby is using SSL 2 anymore
if (_securityParameters.version == SSLSecurityParameters.PROTOCOL_VERSION) {
rec.readBytes(verifyData, 0, 36); // length should be (in fact, better be) 16 + 20 (md5-size + sha1-size)
} else { // presuming TLS
rec.readBytes(verifyData, 0, 12);
}
var data:ByteArray = _securityParameters.computeVerifyData(1-_entity, _handshakePayloads);
if (ArrayUtil.equals(verifyData, data)) {
_state = STATE_READY;
dispatchEvent(new TLSEvent(TLSEvent.READY));
} else {
throw new TLSError("Invalid Finished mac.", TLSError.bad_record_mac);
}
}
// enforceClient/enforceServer removed in favor of state-driven function maps
/**
* Handle a HANDSHAKE_HELLO
*/
private function parseHandshakeHello( rec:ByteArray ) : void {
if (_state != STATE_READY) {
trace("Received an HELLO_REQUEST before being in state READY. ignoring.");
return;
}
_handshakePayloads = new ByteArray;
startHandshake();
}
/**
* Handle a HANDSHAKE_CLIENT_KEY_EXCHANGE
*/
private function parseHandshakeClientKeyExchange(rec:ByteArray):void {
if (_securityParameters.useRSA) {
// skip 2 bytes for length.
var len:uint = rec.readShort();
var cipher:ByteArray = new ByteArray;
rec.readBytes(cipher, 0, len);
var preMasterSecret:ByteArray = new ByteArray;
_config.privateKey.decrypt(cipher, preMasterSecret, len);
_securityParameters.setPreMasterSecret(preMasterSecret);
// now is a good time to get our pending states
var o:Object = _securityParameters.getConnectionStates();
_pendingReadState = o.read;
_pendingWriteState = o.write;
} else {
throw new TLSError("parseHandshakeClientKeyExchange not implemented for DH modes.", TLSError.internal_error);
}
}
/**
* Handle HANDSHAKE_SERVER_HELLO - client-side
*/
private function parseHandshakeServerHello( rec:IDataInput ) : void {
var ver:uint = rec.readShort();
if (ver != _securityParameters.version) {
throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
}
var random:ByteArray = new ByteArray;
rec.readBytes(random, 0, 32);
var session_length:uint = rec.readByte();
var session:ByteArray = new ByteArray;
if (session_length > 0) {
// some implementations don't assign a session ID
rec.readBytes(session, 0, session_length);
}
_securityParameters.setCipher(rec.readShort());
_securityParameters.setCompression(rec.readByte());
_securityParameters.setServerRandom(random);
}
/**
* Handle HANDSHAKE_CLIENT_HELLO - server side
*/
private function parseHandshakeClientHello( rec:IDataInput ) : void {
var ret:Object;
var ver:uint = rec.readShort();
if (ver != _securityParameters.version) {
throw new TLSError("Unsupported TLS version: "+ver.toString(16), TLSError.protocol_version);
}
var random:ByteArray = new ByteArray;
rec.readBytes(random, 0, 32);
var session_length:uint = rec.readByte();
var session:ByteArray = new ByteArray;
if (session_length > 0) {
// some implementations don't assign a session ID
rec.readBytes(session, 0, session_length);
}
var suites:Array = [];
var suites_length:uint = rec.readShort();
for (var i:uint=0;i<suites_length/2;i++) {
suites.push(rec.readShort());
}
var compressions:Array = [];
var comp_length:uint = rec.readByte();
for (i=0;i<comp_length;i++) {
compressions.push(rec.readByte());
}
ret = {random:random, session:session, suites:suites, compressions:compressions};
var sofar:uint = 2+32+1+session_length+2+suites_length+1+comp_length;
var extensions:Array = [];
if (sofar<length) {
// we have extensions. great.
var ext_total_length:uint = rec.readShort();
while (ext_total_length>0) {
var ext_type:uint = rec.readShort();
var ext_length:uint = rec.readShort();
var ext_data:ByteArray = new ByteArray;
rec.readBytes(ext_data, 0, ext_length);
ext_total_length -= 4+ext_length;
extensions.push({type:ext_type, length:ext_length, data:ext_data});
}
}
ret.ext = extensions;
sendServerHello(ret);
sendCertificate();
// TODO: Modify to handle case of requesting a certificate from the client, for "client authentication",
// and testing purposes, will probably never actually need it.
sendServerHelloDone();
}
private function sendClientHello():void {
var rec:ByteArray = new ByteArray;
// version - modified to support version attribute from ISecurityParameters
rec.writeShort(_securityParameters.version);
// random
var prng:Random = new Random;
var clientRandom:ByteArray = new ByteArray;
prng.nextBytes(clientRandom, 32);
_securityParameters.setClientRandom(clientRandom);
rec.writeBytes(clientRandom,0,32);
// session
rec.writeByte(32);
prng.nextBytes(rec, 32);
// Cipher suites
var cs:Array = _config.cipherSuites;
rec.writeShort(2* cs.length);
for (var i:int=0;i<cs.length;i++) {
rec.writeShort(cs[i]);
}
// Compression
cs = _config.compressions;
rec.writeByte(cs.length);
for (i=0;i<cs.length;i++) {
rec.writeByte(cs[i]);
}
// no extensions, yet.
rec.position = 0;
sendHandshake(HANDSHAKE_CLIENT_HELLO, rec.length, rec);
}
private function findMatch(a1:Array, a2:Array):int {
for (var i:int=0;i<a1.length;i++) {
var e:uint = a1[i];
if (a2.indexOf(e)>-1) {
return e;
}
}
return -1;
}
private function sendServerHello(v:Object):void {
var cipher:int = findMatch(_config.cipherSuites, v.suites);
if (cipher == -1) {
throw new TLSError("No compatible cipher found.", TLSError.handshake_failure);
}
_securityParameters.setCipher(cipher);
var comp:int = findMatch(_config.compressions, v.compressions);
if (comp == 01) {
throw new TLSError("No compatible compression method found.", TLSError.handshake_failure);
}
_securityParameters.setCompression(comp);
_securityParameters.setClientRandom(v.random);
var rec:ByteArray = new ByteArray;
rec.writeShort(_securityParameters.version);
var prng:Random = new Random;
var serverRandom:ByteArray = new ByteArray;
prng.nextBytes(serverRandom, 32);
_securityParameters.setServerRandom(serverRandom);
rec.writeBytes(serverRandom,0,32);
// session
rec.writeByte(32);
prng.nextBytes(rec, 32);
// Cipher suite
rec.writeShort(v.suites[0]);
// Compression
rec.writeByte(v.compressions[0]);
rec.position = 0;
sendHandshake(HANDSHAKE_SERVER_HELLO, rec.length, rec);
}
private var sendClientCert:Boolean = false;
private function setStateRespondWithCertificate( r:ByteArray = null) : void {
sendClientCert = true;
}
private function sendCertificate( r:ByteArray = null ):void {
var cert:ByteArray = _config.certificate;
var len:uint;
var len2:uint;
var rec:ByteArray = new ByteArray;
// Look for a certficate chain, if we have one, send it, if we don't, send an empty record.
if (cert != null) {
len = cert.length;
len2 = cert.length + 3;
rec.writeByte(len2>>16);
rec.writeShort(len2&65535);
rec.writeByte(len>>16);
rec.writeShort(len&65535);
rec.writeBytes(cert);
} else {
rec.writeShort( 0 );
rec.writeByte( 0 );
}
rec.position = 0;
sendHandshake(HANDSHAKE_CERTIFICATE, rec.length, rec);
}
private function sendCertificateVerify():void {
var rec:ByteArray = new ByteArray();
// Encrypt the handshake payloads here
var data:ByteArray = _securityParameters.computeCertificateVerify(_entity, _handshakePayloads);
data.position=0;
sendHandshake(HANDSHAKE_CERTIFICATE_VERIFY, data.length, data);
}
private function sendServerHelloDone():void {
var rec:ByteArray = new ByteArray;
sendHandshake(HANDSHAKE_HELLO_DONE, rec.length, rec);
}
private function sendClientKeyExchange():void {
if (_securityParameters.useRSA) {
var p:ByteArray = new ByteArray;
p.writeShort(_securityParameters.version);
var prng:Random = new Random;
prng.nextBytes(p, 46);
p.position = 0;
var preMasterSecret:ByteArray = new ByteArray;
preMasterSecret.writeBytes(p, 0, p.length);
preMasterSecret.position = 0;
_securityParameters.setPreMasterSecret(preMasterSecret);
var enc_key:ByteArray = new ByteArray;
_otherCertificate.getPublicKey().encrypt(preMasterSecret, enc_key, preMasterSecret.length);
enc_key.position = 0;
var rec:ByteArray = new ByteArray;
// TLS requires the size of the premaster key be sent BUT
// SSL 3.0 does not
if (_securityParameters.version > 0x0300) {
rec.writeShort(enc_key.length);
}
rec.writeBytes(enc_key, 0, enc_key.length);
rec.position=0;
sendHandshake(HANDSHAKE_CLIENT_KEY_EXCHANGE, rec.length, rec);
// now is a good time to get our pending states
var o:Object = _securityParameters.getConnectionStates();
_pendingReadState = o.read;
_pendingWriteState = o.write;
} else {
throw new TLSError("Non-RSA Client Key Exchange not implemented.", TLSError.internal_error);
}
}
private function sendFinished():void {
var data:ByteArray = _securityParameters.computeVerifyData(_entity, _handshakePayloads);
data.position=0;
sendHandshake(HANDSHAKE_FINISHED, data.length, data);
}
private function sendHandshake(type:uint, len:uint, payload:IDataInput):void {
var rec:ByteArray = new ByteArray;
rec.writeByte(type);
rec.writeByte(0);
rec.writeShort(len);
payload.readBytes(rec, rec.position, len);
_handshakePayloads.writeBytes(rec, 0, rec.length);
sendRecord(PROTOCOL_HANDSHAKE, rec);
}
private function sendChangeCipherSpec():void {
var rec:ByteArray = new ByteArray;
rec[0] = 1;
sendRecord(PROTOCOL_CHANGE_CIPHER_SPEC, rec);
// right after, switch the cipher for writing.
_currentWriteState = _pendingWriteState;
_pendingWriteState = null;
}
public function sendApplicationData(data:ByteArray, offset:uint=0, length:uint=0):void {
var rec:ByteArray = new ByteArray;
var len:uint = length;
// BIG FAT WARNING: Patch from Arlen Cuss ALA As3crypto group on Google code.
// This addresses data overflow issues when the packet size hits the max length boundary.
if (len == 0) len = data.length;
while (len>16384) {
rec.position = 0;
rec.writeBytes(data, offset, 16384);
rec.position = 0;
sendRecord(PROTOCOL_APPLICATION_DATA, rec);
offset += 16384;
len -= 16384;
}
rec.position = 0;
rec.writeBytes(data, offset, len);
// trace("Data I'm sending..." + Hex.fromArray( data ));
rec.position = 0;
sendRecord(PROTOCOL_APPLICATION_DATA, rec);
}
private function sendRecord(type:uint, payload:ByteArray):void {
// encrypt
payload = _currentWriteState.encrypt(type, payload);
_oStream.writeByte(type);
_oStream.writeShort(_securityParameters.version);
_oStream.writeShort(payload.length);
_oStream.writeBytes(payload, 0, payload.length);
scheduleWrite();
}
private var _writeScheduler:uint;
private function scheduleWrite():void {
if (_writeScheduler!=0) return;
_writeScheduler = setTimeout(commitWrite, 0);
}
private function commitWrite():void {
clearTimeout(_writeScheduler);
_writeScheduler = 0;
if (_state != STATE_CLOSED) {
dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA));
}
}
private function sendClientAck( rec:ByteArray ):void {
if ( _handshakeCanContinue ) {
// If I have a pending cert request, send it
if (sendClientCert)
sendCertificate();
// send a client key exchange
sendClientKeyExchange();
// Send the certificate verify, if we have one
if (_config.certificate != null)
sendCertificateVerify();
// send a change cipher spec
sendChangeCipherSpec();
// send a finished
sendFinished();
}
}
/**
* Vaguely gross function that parses a RSA key out of a certificate.
*
* As long as that certificate looks just the way we expect it to.
*
*/
private function loadCertificates( rec:ByteArray ):void {
var tmp:uint = rec.readByte();
var certs_len:uint = (tmp<<16) | rec.readShort();
var certs:Array = [];
while (certs_len>0) {
tmp = rec.readByte();
var cert_len:uint = (tmp<<16) | rec.readShort();
var cert:ByteArray = new ByteArray;
rec.readBytes(cert, 0, cert_len);
certs.push(cert);
certs_len -= 3 + cert_len;
}
var firstCert:X509Certificate = null;
for (var i:int=0;i<certs.length;i++) {
var x509:X509Certificate = new X509Certificate(certs[i]);
_store.addCertificate(x509);
if (firstCert==null) {
firstCert = x509;
}
}
// Test first for trust override parameters
// This nice trust override stuff comes from Joey Parrish via As3crypto forums
var certTrusted:Boolean;
if (_config.trustAllCertificates) {
certTrusted = true; // Blatantly trust everything
} else if (_config.trustSelfSignedCertificates ) {
// Self-signed certs
certTrusted = firstCert.isSelfSigned(new Date);
} else {
// Certs with a signer in the CA store - realistically, I should setup an event chain to handle this
certTrusted = firstCert.isSigned(_store, _config.CAStore );
}
// Good so far
if (certTrusted) {
// ok, that's encouraging. now for the hostname match.
if (_otherIdentity==null || _config.ignoreCommonNameMismatch ) {
// we don't care who we're talking with. groovy.
_otherCertificate = firstCert;
} else {
// use regex to handle wildcard certs
var commonName:String = firstCert.getCommonName();
// replace all regex special characters with escaped version, except for asterisk
// replace the asterisk with a regex sequence to match one or more non-dot characters
var commonNameRegex:RegExp = new RegExp( commonName.replace(/[\^\\\-$.[\]|()?+{}]/g, "\\$&").replace(/\*/g, "[^.]+"), "gi");
if (commonNameRegex.exec(_otherIdentity)) {
_otherCertificate = firstCert;
} else {
if (_config.promptUserForAcceptCert ) {
_handshakeCanContinue = false;
dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
} else {
throw new TLSError("Invalid common name: "+firstCert.getCommonName()+", expected "+_otherIdentity, TLSError.bad_certificate);
}
}
}
} else {
// Let's ask the user if we can accept this cert. I'm not certain of the behaviour in case of timeouts,
// so I probably need to handle the case by killing and restarting the connection rather than continuing if it becomes
// an issue. We shall see. BP
if (_config.promptUserForAcceptCert) {
_handshakeCanContinue = false;
dispatchEvent( new TLSEvent( TLSEvent.PROMPT_ACCEPT_CERT ));
} else {
// Cannot continue, die.
throw new TLSError("Cannot verify certificate", TLSError.bad_certificate);
}
}
}
// Accept the peer cert, and keep going
public function acceptPeerCertificate() : void {
_handshakeCanContinue = true;
sendClientAck( null );
}
// Step off biotch! No trust for you!
public function rejectPeerCertificate() : void {
throw new TLSError("Peer certificate not accepted!", TLSError.bad_certificate);
}
private function parseAlert(p:ByteArray):void {
//throw new Error("Alert not implemented.");
// 7.2
trace("GOT ALERT! type="+p[1]);
close();
}
private function parseChangeCipherSpec(p:ByteArray):void {
p.readUnsignedByte();
if (_pendingReadState==null) {
throw new TLSError("Not ready to Change Cipher Spec, damnit.", TLSError.unexpected_message);
}
_currentReadState = _pendingReadState;
_pendingReadState = null;
// 7.1
}
private function parseApplicationData(p:ByteArray):void {
if (_state != STATE_READY) {
throw new TLSError("Too soon for data!", TLSError.unexpected_message);
return;
}
dispatchEvent(new TLSEvent(TLSEvent.DATA, p));
}
private function handleTLSError(e:TLSError):void {
// basic rules to keep things simple:
// - Make a good faith attempt at notifying peers
// - TLSErrors are always fatal.
// BP: Meh...not always. Common Name mismatches appear to be common on servers. Instead of closing, let's pause, and ask for confirmation
// before we tear the connection down.
close(e);
}
}
}
/**
* TLSError
*
* A error that can be thrown when something wrong happens in the TLS protocol.
* This is handled in TLSEngine by generating a TLS ALERT as appropriate.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
public class TLSError extends Error {
public static const close_notify:uint = 0;
public static const unexpected_message:uint = 10;
public static const bad_record_mac:uint = 20;
public static const decryption_failed:uint = 21;
public static const record_overflow:uint = 22;
public static const decompression_failure:uint = 30;
public static const handshake_failure:uint = 40;
public static const bad_certificate:uint = 42;
public static const unsupported_certificate:uint = 43;
public static const certificate_revoked:uint = 44;
public static const certificate_expired:uint = 45;
public static const certificate_unknown:uint = 46;
public static const illegal_parameter:uint = 47;
public static const unknown_ca:uint = 48;
public static const access_denied:uint = 49;
public static const decode_error:uint = 50;
public static const decrypt_error:uint = 51;
public static const protocol_version:uint = 70;
public static const insufficient_security:uint = 71;
public static const internal_error:uint = 80;
public static const user_canceled:uint = 90;
public static const no_renegotiation:uint = 100;
public function TLSError(message:String, id:int) {
super(message,id);
}
}
}
\ No newline at end of file
/**
* TLSEvent
*
* This is used by TLSEngine to let the application layer know
* when we're ready for sending, or have received application data
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.utils.ByteArray;
public class TLSEvent extends Event {
static public const DATA:String = "data";
static public const READY:String = "ready";
static public const PROMPT_ACCEPT_CERT:String = "promptAcceptCert";
public var data:ByteArray;
public function TLSEvent(type:String, data:ByteArray = null) {
this.data = data;
super(type, false, false);
}
}
}
\ No newline at end of file
/**
* TLSSecurityParameters
*
* This class encapsulates all the security parameters that get negotiated
* during the TLS handshake. It also holds all the key derivation methods.
* Copyright (c) 2007 Henri Torgemane
*
* Patched by Bobby Parker (sh0rtwave@gmail.com)
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.hash.MD5;
import com.hurlant.crypto.hash.SHA1;
import com.hurlant.crypto.prng.TLSPRF;
import com.hurlant.util.Hex;
import flash.utils.ByteArray;
import com.hurlant.crypto.rsa.RSAKey;
public class TLSSecurityParameters implements ISecurityParameters {
// COMPRESSION
public static const COMPRESSION_NULL:uint = 0;
// This is probably not smart. Revise this to use all settings from TLSConfig, since this shouldn't really know about
// user settings, those are best handled from the engine at a session level.
public static var IGNORE_CN_MISMATCH:Boolean = true;
public static var ENABLE_USER_CLIENT_CERTIFICATE:Boolean = false;
public static var USER_CERTIFICATE:String;
private var cert:ByteArray; // Local Cert
private var key:RSAKey; // local key
private var entity:uint; // SERVER | CLIENT
private var bulkCipher:uint; // BULK_CIPHER_*
private var cipherType:uint; // STREAM_CIPHER | BLOCK_CIPHER
private var keySize:uint;
private var keyMaterialLength:uint;
private var IVSize:uint;
private var macAlgorithm:uint; // MAC_*
private var hashSize:uint;
private var compression:uint; // COMPRESSION_NULL
private var masterSecret:ByteArray; // 48 bytes
private var clientRandom:ByteArray; // 32 bytes
private var serverRandom:ByteArray; // 32 bytes
private var ignoreCNMismatch:Boolean = true;
private var trustAllCerts:Boolean = false;
private var trustSelfSigned:Boolean = false;
public static const PROTOCOL_VERSION:uint = 0x0301;
private var tlsDebug:Boolean = false;
// not strictly speaking part of this, but yeah.
public var keyExchange:uint;
public function TLSSecurityParameters(entity:uint, localCert:ByteArray = null, localKey:RSAKey = null) {
this.entity = entity;
reset();
key = localKey;
cert = localCert;
}
public function get version() : uint {
return PROTOCOL_VERSION;
}
public function reset():void {
bulkCipher = BulkCiphers.NULL;
cipherType = BulkCiphers.BLOCK_CIPHER;
macAlgorithm = MACs.NULL;
compression = COMPRESSION_NULL;
masterSecret = null;
}
public function getBulkCipher():uint {
return bulkCipher;
}
public function getCipherType():uint {
return cipherType;
}
public function getMacAlgorithm():uint {
return macAlgorithm;
}
public function setCipher(cipher:uint):void {
bulkCipher = CipherSuites.getBulkCipher(cipher);
cipherType = BulkCiphers.getType(bulkCipher);
keySize = BulkCiphers.getExpandedKeyBytes(bulkCipher); // 8
keyMaterialLength = BulkCiphers.getKeyBytes(bulkCipher); // 5
IVSize = BulkCiphers.getIVSize(bulkCipher);
keyExchange = CipherSuites.getKeyExchange(cipher);
macAlgorithm = CipherSuites.getMac(cipher);
hashSize = MACs.getHashSize(macAlgorithm);
}
public function setCompression(algo:uint):void {
compression = algo;
}
public function setPreMasterSecret(secret:ByteArray):void {
// compute master_secret
var seed:ByteArray = new ByteArray;
seed.writeBytes(clientRandom, 0, clientRandom.length);
seed.writeBytes(serverRandom, 0, serverRandom.length);
var prf:TLSPRF = new TLSPRF(secret, "master secret", seed);
masterSecret = new ByteArray;
prf.nextBytes(masterSecret, 48);
if (tlsDebug)
trace("Master Secret: " + Hex.fromArray( masterSecret, true ));
}
public function setClientRandom(secret:ByteArray):void {
clientRandom = secret;
}
public function setServerRandom(secret:ByteArray):void {
serverRandom = secret;
}
public function get useRSA():Boolean {
return KeyExchanges.useRSA(keyExchange);
}
public function computeVerifyData(side:uint, handshakeMessages:ByteArray):ByteArray {
var seed:ByteArray = new ByteArray;
var md5:MD5 = new MD5;
if (tlsDebug)
trace("Handshake value: " + Hex.fromArray(handshakeMessages, true ));
seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());
var sha:SHA1 = new SHA1;
seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());
if (tlsDebug)
trace("Seed in: " + Hex.fromArray(seed, true ));
var prf:TLSPRF = new TLSPRF(masterSecret, (side==TLSEngine.CLIENT) ? "client finished" : "server finished", seed);
var out:ByteArray = new ByteArray;
prf.nextBytes(out, 12);
if (tlsDebug)
trace("Finished out: " + Hex.fromArray(out, true ));
out.position = 0;
return out;
}
// client side certficate check - This is probably incorrect somehow
public function computeCertificateVerify( side:uint, handshakeMessages:ByteArray ):ByteArray {
var seed:ByteArray = new ByteArray;
var md5:MD5 = new MD5;
seed.writeBytes(md5.hash(handshakeMessages),0,md5.getHashSize());
var sha:SHA1 = new SHA1;
seed.writeBytes(sha.hash(handshakeMessages),0,sha.getHashSize());
// Now that I have my hashes of existing handshake messages (which I'm not sure about the length of yet) then
// Sign that with my private key
seed.position = 0;
var out:ByteArray = new ByteArray();
key.sign( seed, out, seed.bytesAvailable);
out.position = 0;
return out;
}
public function getConnectionStates():Object {
if (masterSecret != null) {
var seed:ByteArray = new ByteArray;
seed.writeBytes(serverRandom, 0, serverRandom.length);
seed.writeBytes(clientRandom, 0, clientRandom.length);
var prf:TLSPRF = new TLSPRF(masterSecret, "key expansion", seed);
var client_write_MAC:ByteArray = new ByteArray;
prf.nextBytes(client_write_MAC, hashSize);
var server_write_MAC:ByteArray = new ByteArray;
prf.nextBytes(server_write_MAC, hashSize);
var client_write_key:ByteArray = new ByteArray;
prf.nextBytes(client_write_key, keyMaterialLength);
var server_write_key:ByteArray = new ByteArray;
prf.nextBytes(server_write_key, keyMaterialLength);
var client_write_IV:ByteArray = new ByteArray;
prf.nextBytes(client_write_IV, IVSize);
var server_write_IV:ByteArray = new ByteArray;
prf.nextBytes(server_write_IV, IVSize);
var client_write:TLSConnectionState = new TLSConnectionState(
bulkCipher, cipherType, macAlgorithm,
client_write_MAC, client_write_key, client_write_IV);
var server_write:TLSConnectionState = new TLSConnectionState(
bulkCipher, cipherType, macAlgorithm,
server_write_MAC, server_write_key, server_write_IV);
if (entity == TLSEngine.CLIENT) {
return {read:server_write, write:client_write};
} else {
return {read:client_write, write:server_write};
}
} else {
return {read:new TLSConnectionState, write:new TLSConnectionState};
}
}
}
}
\ No newline at end of file
/**
* TLSSocket
*
* This is the "end-user" TLS class.
* It works just like a Socket, by encapsulating a Socket and
* wrapping the TLS protocol around the data that passes over it.
* This class can either create a socket connection, or reuse an
* existing connected socket. The later is useful for STARTTLS flows.
*
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.ObjectEncoding;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.Endian;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
import com.hurlant.crypto.cert.X509Certificate;
[Event(name="close", type="flash.events.Event")]
[Event(name="connect", type="flash.events.Event")]
[Event(name="ioError", type="flash.events.IOErrorEvent")]
[Event(name="securityError", type="flash.events.SecurityErrorEvent")]
[Event(name="socketData", type="flash.events.ProgressEvent")]
[Event(name="acceptPeerCertificatePrompt", type="flash.events.Event")]
/**
* It feels like a socket, but it wraps the stream
* over TLS 1.0
*
* That's all.
*
*/
public class TLSSocket extends Socket implements IDataInput, IDataOutput {
private var _endian:String;
private var _objectEncoding:uint;
private var _iStream:ByteArray;
private var _oStream:ByteArray;
private var _iStream_cursor:uint;
private var _socket:Socket;
private var _config:TLSConfig;
private var _engine:TLSEngine;
public static const ACCEPT_PEER_CERT_PROMPT:String = "acceptPeerCertificatePrompt"
public function TLSSocket(host:String = null, port:int = 0, config:TLSConfig = null) {
_config = config;
if (host!=null && port!=0) {
connect(host, port);
}
}
override public function get bytesAvailable():uint {
return _iStream.bytesAvailable;
}
override public function get connected():Boolean {
return _socket.connected;
}
override public function get endian():String {
return _endian;
}
override public function set endian(value:String):void {
_endian = value;
_iStream.endian = value;
_oStream.endian = value;
}
override public function get objectEncoding():uint {
return _objectEncoding;
}
override public function set objectEncoding(value:uint):void {
_objectEncoding = value;
_iStream.objectEncoding = value;
_oStream.objectEncoding = value;
}
private function onTLSData(event:TLSEvent):void {
if (_iStream.position == _iStream.length) {
_iStream.position = 0;
_iStream.length = 0;
_iStream_cursor = 0;
}
var cursor:uint = _iStream.position;
_iStream.position = _iStream_cursor;
_iStream.writeBytes(event.data);
_iStream_cursor = _iStream.position;
_iStream.position = cursor;
dispatchEvent(new ProgressEvent(ProgressEvent.SOCKET_DATA, false, false, event.data.length));
}
private function onTLSReady(event:TLSEvent):void {
_ready = true;
scheduleWrite();
}
private function onTLSClose(event:Event):void {
dispatchEvent(event);
// trace("Received TLS close");
close();
}
private var _ready:Boolean;
private var _writeScheduler:uint;
private function scheduleWrite():void {
if (_writeScheduler!=0) return;
_writeScheduler = setTimeout(commitWrite, 0);
}
private function commitWrite():void {
clearTimeout(_writeScheduler);
_writeScheduler = 0;
if (_ready) {
_engine.sendApplicationData(_oStream);
_oStream.length = 0;
}
}
override public function close():void {
_ready = false;
_engine.close();
if (_socket.connected) {
_socket.flush();
_socket.close();
}
}
public function setTLSConfig( config:TLSConfig) : void {
_config = config;
}
override public function connect(host:String, port:int):void {
init(new Socket, _config, host);
_socket.connect(host, port);
_engine.start();
}
public function releaseSocket() : void {
_socket.removeEventListener(Event.CONNECT, dispatchEvent);
_socket.removeEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_socket.removeEventListener(Event.CLOSE, dispatchEvent);
_socket.removeEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);
_socket = null;
}
public function reinitialize(host:String, config:TLSConfig) : void {
// Reinitialize the connection using new values
// but re-use the existing socket
// Doubt this is useful in any valid context other than my specific case (VMWare)
var ba:ByteArray = new ByteArray;
if (_socket.bytesAvailable > 0) {
_socket.readBytes(ba, 0, _socket.bytesAvailable);
}
// Do nothing with it.
_iStream = new ByteArray;
_oStream = new ByteArray;
_iStream_cursor = 0;
objectEncoding = ObjectEncoding.DEFAULT;
endian = Endian.BIG_ENDIAN;
/*
_socket.addEventListener(Event.CONNECT, dispatchEvent);
_socket.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_socket.addEventListener(Event.CLOSE, dispatchEvent);
*/
if (config == null) {
config = new TLSConfig(TLSEngine.CLIENT);
}
_engine = new TLSEngine(config, _socket, _socket, host);
_engine.addEventListener(TLSEvent.DATA, onTLSData);
_engine.addEventListener(TLSEvent.READY, onTLSReady);
_engine.addEventListener(Event.CLOSE, onTLSClose);
_engine.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { _socket.flush(); });
_socket.addEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);
_engine.addEventListener( TLSEvent.PROMPT_ACCEPT_CERT, onAcceptCert );
_ready = false;
_engine.start();
}
public function startTLS(socket:Socket, host:String, config:TLSConfig = null):void {
if (!socket.connected) {
throw new Error("Cannot STARTTLS on a socket that isn't connected.");
}
init(socket, config, host);
_engine.start();
}
private function init(socket:Socket, config:TLSConfig, host:String):void {
_iStream = new ByteArray;
_oStream = new ByteArray;
_iStream_cursor = 0;
objectEncoding = ObjectEncoding.DEFAULT;
endian = Endian.BIG_ENDIAN;
_socket = socket;
_socket.addEventListener(Event.CONNECT, dispatchEvent);
_socket.addEventListener(IOErrorEvent.IO_ERROR, dispatchEvent);
_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, dispatchEvent);
_socket.addEventListener(Event.CLOSE, dispatchEvent);
if (config == null) {
config = new TLSConfig(TLSEngine.CLIENT);
}
_engine = new TLSEngine(config, _socket, _socket, host);
_engine.addEventListener(TLSEvent.DATA, onTLSData);
_engine.addEventListener( TLSEvent.PROMPT_ACCEPT_CERT, onAcceptCert );
_engine.addEventListener(TLSEvent.READY, onTLSReady);
_engine.addEventListener(Event.CLOSE, onTLSClose);
_engine.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { if(connected) _socket.flush(); });
_socket.addEventListener(ProgressEvent.SOCKET_DATA, _engine.dataAvailable);
_ready = false;
}
override public function flush():void {
commitWrite();
_socket.flush();
}
override public function readBoolean():Boolean {
return _iStream.readBoolean();
}
override public function readByte():int {
return _iStream.readByte();
}
override public function readBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void {
return _iStream.readBytes(bytes, offset, length);
}
override public function readDouble():Number {
return _iStream.readDouble();
}
override public function readFloat():Number {
return _iStream.readFloat();
}
override public function readInt():int {
return _iStream.readInt();
}
override public function readMultiByte(length:uint, charSet:String):String {
return _iStream.readMultiByte(length, charSet);
}
override public function readObject():* {
return _iStream.readObject();
}
override public function readShort():int {
return _iStream.readShort();
}
override public function readUnsignedByte():uint {
return _iStream.readUnsignedByte();
}
override public function readUnsignedInt():uint {
return _iStream.readUnsignedInt();
}
override public function readUnsignedShort():uint {
return _iStream.readUnsignedShort();
}
override public function readUTF():String {
return _iStream.readUTF();
}
override public function readUTFBytes(length:uint):String {
return _iStream.readUTFBytes(length);
}
override public function writeBoolean(value:Boolean):void {
_oStream.writeBoolean(value);
scheduleWrite();
}
override public function writeByte(value:int):void {
_oStream.writeByte(value);
scheduleWrite();
}
override public function writeBytes(bytes:ByteArray, offset:uint = 0, length:uint = 0):void {
_oStream.writeBytes(bytes, offset, length);
scheduleWrite();
}
override public function writeDouble(value:Number):void {
_oStream.writeDouble(value);
scheduleWrite();
}
override public function writeFloat(value:Number):void {
_oStream.writeFloat(value);
scheduleWrite();
}
override public function writeInt(value:int):void {
_oStream.writeInt(value);
scheduleWrite();
}
override public function writeMultiByte(value:String, charSet:String):void {
_oStream.writeMultiByte(value, charSet);
scheduleWrite();
}
override public function writeObject(object:*):void {
_oStream.writeObject(object);
scheduleWrite();
}
override public function writeShort(value:int):void {
_oStream.writeShort(value);
scheduleWrite();
}
override public function writeUnsignedInt(value:uint):void {
_oStream.writeUnsignedInt(value);
scheduleWrite();
}
override public function writeUTF(value:String):void {
_oStream.writeUTF(value);
scheduleWrite();
}
override public function writeUTFBytes(value:String):void {
_oStream.writeUTFBytes(value);
scheduleWrite();
}
public function getPeerCertificate() : X509Certificate {
return _engine.peerCertificate;
}
public function onAcceptCert( event:TLSEvent ) : void {
dispatchEvent( new TLSSocketEvent( _engine.peerCertificate ) );
}
// These are just a passthroughs to the engine. Encapsulation, et al
public function acceptPeerCertificate( event:Event ) : void {
_engine.acceptPeerCertificate();
}
public function rejectPeerCertificate( event:Event ) : void {
_engine.rejectPeerCertificate();
}
}
}
/**
* TLSEvent
*
* This is used by TLSEngine to let the application layer know
* when we're ready for sending, or have received application data
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import flash.events.Event;
import flash.utils.ByteArray;
import com.hurlant.crypto.cert.X509Certificate;
public class TLSSocketEvent extends Event {
static public const PROMPT_ACCEPT_CERT:String = "promptAcceptCert";
public var cert:X509Certificate;
public function TLSSocketEvent( cert:X509Certificate = null) {
super(PROMPT_ACCEPT_CERT, false, false);
this.cert = cert;
}
}
}
\ No newline at end of file
/**
* TLSTest
*
* A test class for TLS. Not a finished product.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.crypto.tls {
import com.hurlant.crypto.cert.X509Certificate;
import com.hurlant.crypto.cert.X509CertificateCollection;
import com.hurlant.util.Hex;
import com.hurlant.util.der.PEM;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.getTimer;
public class TLSTest {
public var myDebugData:String;
//[Embed(source="/src/host.cert",mimeType="application/octet-stream")]
public var myCert:Class;
//[Embed(source="/src/host.key",mimeType="application/octet-stream")]
public var myKey:Class;
public function TLSTest(host:String = null, port:int = 0, type:int = 0 ) {
//loopback();
if (host != null) {
if (type == 0) { // SSL 3.0
connectLoginYahooCom();
// connectLocalSSL(host, port);
} else {
connectLocalTLS(host, port);
}
} else {
testSocket();
}
}
public function connectLoginYahooCom():void {
trace("Connecting test socket");
var s:Socket = new Socket("esx.bluebearllc.net", 903);
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT,
null,
null,
null,
null,
null,
SSLSecurityParameters.PROTOCOL_VERSION);
var client:TLSEngine = new TLSEngine(clientConfig, s, s);
// hook some events.
s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
client.start();
}
public function connectLocalTLS(host:String, port:int):void {
var s:Socket = new Socket(host, port);
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT);
var client:TLSEngine = new TLSEngine(clientConfig, s, s);
// hook some events.
s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
client.start();
}
public function connectLocalSSL(host:String, port:int):void {
var s:Socket = new Socket(host, port);
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT,
null,
null,
null,
null,
null,
SSLSecurityParameters.PROTOCOL_VERSION);
var client:TLSEngine = new TLSEngine(clientConfig, s, s);
// hook some events.
s.addEventListener(ProgressEvent.SOCKET_DATA, client.dataAvailable);
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*):void { s.flush(); });
client.start();
}
public function loopback():void {
var server_write:ByteArray = new ByteArray;
var client_write:ByteArray = new ByteArray;
var server_write_cursor:uint = 0;
var client_write_cursor:uint = 0;
var clientConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
var serverConfig:TLSConfig = new TLSConfig(TLSEngine.SERVER, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
var cert:ByteArray = new myCert;
var key:ByteArray = new myKey;
serverConfig.setPEMCertificate(cert.readUTFBytes(cert.length), key.readUTFBytes(key.length));
// tmp, for debugging. currently useless
cert.position = 0;
key.position = 0;
clientConfig.setPEMCertificate(cert.readUTFBytes(cert.length), key.readUTFBytes(key.length));
// put the server cert in the client's trusted store, to keep things happy.
clientConfig.CAStore = new X509CertificateCollection;
cert.position = 0;
var x509:X509Certificate = new X509Certificate(PEM.readCertIntoArray(cert.readUTFBytes(cert.length)));
clientConfig.CAStore.addCertificate(x509);
var server:TLSEngine = new TLSEngine(serverConfig, client_write, server_write);
var client:TLSEngine = new TLSEngine(clientConfig, server_write, client_write);
server.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*=null):void {
trace("server wrote something!");
trace(Hex.fromArray(server_write));
var l:uint = server_write.position;
server_write.position = server_write_cursor;
client.dataAvailable(e);
server_write.position = l;
server_write_cursor = l;
});
client.addEventListener(ProgressEvent.SOCKET_DATA, function(e:*=null):void {
trace("client wrote something!");
trace(Hex.fromArray(client_write));
var l:uint = client_write.position;
client_write.position = client_write_cursor;
server.dataAvailable(e);
client_write.position = l;
client_write_cursor = l;
});
server.start();
client.start();
}
public function testSocket():void {
var hosts:Array = [
"bugs.adobe.com", // apache
"login.yahoo.com", // apache, bigger response
"login.live.com", // IIS-6, chain of 3 certs
"banking.wellsfargo.com", // custom, sends its CA cert along for the ride.
"www.bankofamerica.com" // sun-one, chain of 3 certs
];
var i:int =0;
(function next():void {
testHost(hosts[i++], next);
})();
}
private function testHost(host:String, next:Function):void {
if (host==null) return;
var t1:int = getTimer();
var host:String = host;
var t:TLSSocket = new TLSSocket;
t.connect(host, 4433);
t.writeUTFBytes("GET / HTTP/1.0\nHost: "+host+"\n\n");
t.addEventListener(Event.CLOSE, function(e:*):void {
var s:String = t.readUTFBytes(t.bytesAvailable);
trace("Response from "+host+": "+s.length+" characters");
var bytes:ByteArray = new ByteArray();
t.readBytes(bytes, 0, t.bytesAvailable);
trace(Hex.fromArray(bytes));
trace("Time used = "+(getTimer()-t1)+"ms");
next();
});
}
}
}
package com.hurlant.math
{
use namespace bi_internal;
internal class BarrettReduction implements IReduction
{
private var m:BigInteger;
private var r2:BigInteger;
private var q3:BigInteger;
private var mu:BigInteger;
public function BarrettReduction(m:BigInteger) {
// setup Barrett
r2 = new BigInteger;
q3 = new BigInteger;
BigInteger.ONE.dlShiftTo(2*m.t, r2);
mu = r2.divide(m);
this.m = m;
}
public function revert(x:BigInteger):BigInteger
{
return x;
}
/**
*
* @param x
* @param y
* @param r = x*y mod m; x != r
*
*/
public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void
{
x.multiplyTo(y, r);
reduce(r);
}
/**
*
* @param x
* @param r = x^2 mod m; x != r
*
*/
public function sqrTo(x:BigInteger, r:BigInteger):void
{
x.squareTo(r);
reduce(r);
}
public function convert(x:BigInteger):BigInteger
{
if (x.s<0 || x.t>2*m.t) {
return x.mod(m);
} else if (x.compareTo(m)<0) {
return x;
} else {
var r:BigInteger = new BigInteger;
x.copyTo(r);
reduce(r);
return r;
}
}
/**
*
* @param x = x mod m (HAC 14.42)
*
*/
public function reduce(lx:BigInteger):void
{
var x:BigInteger = lx as BigInteger;
x.drShiftTo(m.t-1,r2);
if (x.t>m.t+1) {
x.t = m.t+1;
x.clamp();
}
mu.multiplyUpperTo(r2, m.t+1, q3);
m.multiplyLowerTo(q3, m.t+1, r2);
while (x.compareTo(r2)<0) {
x.dAddOffset(1, m.t+1);
}
x.subTo(r2,x);
while (x.compareTo(m)>=0) {
x.subTo(m,x);
}
}
}
}
\ No newline at end of file
/**
* BigInteger
*
* An ActionScript 3 implementation of BigInteger (light version)
* Copyright (c) 2007 Henri Torgemane
*
* Derived from:
* The jsbn library, Copyright (c) 2003-2005 Tom Wu
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.math
{
import com.hurlant.crypto.prng.Random;
import com.hurlant.util.Hex;
import com.hurlant.util.Memory;
import flash.utils.ByteArray;
use namespace bi_internal;
public class BigInteger
{
public static const DB:int = 30; // number of significant bits per chunk
public static const DV:int = (1<<DB);
public static const DM:int = (DV-1); // Max value in a chunk
public static const BI_FP:int = 52;
public static const FV:Number = Math.pow(2, BI_FP);
public static const F1:int = BI_FP - DB;
public static const F2:int = 2*DB - BI_FP;
public static const ZERO:BigInteger = nbv(0);
public static const ONE:BigInteger = nbv(1);
/*bi_internal */public var t:int; // number of chunks.
bi_internal var s:int; // sign
bi_internal var a:Array; // chunks
/**
*
* @param value
* @param radix WARNING: If value is ByteArray, this holds the number of bytes to use.
* @param unsigned
*
*/
public function BigInteger(value:* = null, radix:int = 0, unsigned:Boolean = false) {
a = new Array;
if (value is String) {
if (radix&&radix!=16) throw new Error("BigInteger construction with radix!=16 is not supported.");
value = Hex.toArray(value);
radix=0;
}
if (value is ByteArray) {
var array:ByteArray = value as ByteArray;
var length:int = radix || (array.length - array.position);
fromArray(array, length, unsigned);
}
}
public function dispose():void {
var r:Random = new Random;
for (var i:uint=0;i<a.length;i++) {
a[i] = r.nextByte();
delete a[i];
}
a=null;
t=0;
s=0;
Memory.gc();
}
public function toString(radix:Number=16):String {
if (s<0) return "-"+negate().toString(radix);
var k:int;
switch (radix) {
case 2: k=1; break;
case 4: k=2; break;
case 8: k=3; break;
case 16: k=4; break;
case 32: k=5; break;
default:
// return toRadix(radix);
}
var km:int = (1<<k)-1;
var d:int = 0;
var m:Boolean = false;
var r:String = "";
var i:int = t;
var p:int = DB-(i*DB)%k;
if (i-->0) {
if (p<DB && (d=a[i]>>p)>0) {
m = true;
r = d.toString(36);
}
while (i >= 0) {
if (p<k) {
d = (a[i]&((1<<p)-1))<<(k-p);
d|= a[--i]>>(p+=DB-k);
} else {
d = (a[i]>>(p-=k))&km;
if (p<=0) {
p += DB;
--i;
}
}
if (d>0) {
m = true;
}
if (m) {
r += d.toString(36);
}
}
}
return m?r:"0";
}
public function toArray(array:ByteArray):uint {
const k:int = 8;
const km:int = (1<<8)-1;
var d:int = 0;
var i:int = t;
var p:int = DB-(i*DB)%k;
var m:Boolean = false;
var c:int = 0;
if (i-->0) {
if (p<DB && (d=a[i]>>p)>0) {
m = true;
array.writeByte(d);
c++;
}
while (i >= 0) {
if (p<k) {
d = (a[i]&((1<<p)-1))<<(k-p);
d|= a[--i]>>(p+=DB-k);
} else {
d = (a[i]>>(p-=k))&km;
if (p<=0) {
p += DB;
--i;
}
}
if (d>0) {
m = true;
}
if (m) {
array.writeByte(d);
c++;
}
}
}
return c;
}
/**
* best-effort attempt to fit into a Number.
* precision can be lost if it just can't fit.
*/
public function valueOf():Number {
if (s==-1) {
return -negate().valueOf();
}
var coef:Number = 1;
var value:Number = 0;
for (var i:uint=0;i<t;i++) {
value += a[i]*coef;
coef *= DV;
}
return value;
}
/**
* -this
*/
public function negate():BigInteger {
var r:BigInteger = nbi();
ZERO.subTo(this, r);
return r;
}
/**
* |this|
*/
public function abs():BigInteger {
return (s<0)?negate():this;
}
/**
* return + if this > v, - if this < v, 0 if equal
*/
public function compareTo(v:BigInteger):int {
var r:int = s - v.s;
if (r!=0) {
return r;
}
var i:int = t;
r = i-v.t;
if (r!=0) {
return r;
}
while (--i >=0) {
r=a[i]-v.a[i];
if (r != 0) return r;
}
return 0;
}
/**
* returns bit length of the integer x
*/
bi_internal function nbits(x:int):int {
var r:int = 1;
var t:int;
if ((t=x>>>16) != 0) { x = t; r += 16; }
if ((t=x>>8) != 0) { x = t; r += 8; }
if ((t=x>>4) != 0) { x = t; r += 4; }
if ((t=x>>2) != 0) { x = t; r += 2; }
if ((t=x>>1) != 0) { x = t; r += 1; }
return r;
}
/**
* returns the number of bits in this
*/
public function bitLength():int {
if (t<=0) return 0;
return DB*(t-1)+nbits(a[t-1]^(s&DM));
}
/**
*
* @param v
* @return this % v
*
*/
public function mod(v:BigInteger):BigInteger {
var r:BigInteger = nbi();
abs().divRemTo(v,null,r);
if (s<0 && r.compareTo(ZERO)>0) {
v.subTo(r,r);
}
return r;
}
/**
* this^e % m, 0 <= e < 2^32
*/
public function modPowInt(e:int, m:BigInteger):BigInteger {
var z:IReduction;
if (e<256 || m.isEven()) {
z = new ClassicReduction(m);
} else {
z = new MontgomeryReduction(m);
}
return exp(e, z);
}
/**
* copy this to r
*/
bi_internal function copyTo(r:BigInteger):void {
for (var i:int = t-1; i>=0; --i) {
r.a[i] = a[i];
}
r.t = t;
r.s = s;
}
/**
* set from integer value "value", -DV <= value < DV
*/
bi_internal function fromInt(value:int):void {
t = 1;
s = (value<0)?-1:0;
if (value>0) {
a[0] = value;
} else if (value<-1) {
a[0] = value+DV;
} else {
t = 0;
}
}
/**
* set from ByteArray and length,
* starting a current position
* If length goes beyond the array, pad with zeroes.
*/
bi_internal function fromArray(value:ByteArray, length:int, unsigned:Boolean = false):void {
var p:int = value.position;
var i:int = p+length;
var sh:int = 0;
const k:int = 8;
t = 0;
s = 0;
while (--i >= p) {
var x:int = i<value.length?value[i]:0;
if (sh == 0) {
a[t++] = x;
} else if (sh+k > DB) {
a[t-1] |= (x&((1<<(DB-sh))-1))<<sh;
a[t++] = x>>(DB-sh);
} else {
a[t-1] |= x<<sh;
}
sh += k;
if (sh >= DB) sh -= DB;
}
if (!unsigned && (value[0]&0x80)==0x80) {
s = -1;
if (sh > 0) {
a[t-1] |= ((1<<(DB-sh))-1)<<sh;
}
}
clamp();
value.position = Math.min(p+length,value.length);
}
/**
* clamp off excess high words
*/
bi_internal function clamp():void {
var c:int = s&DM;
while (t>0 && a[t-1]==c) {
--t;
}
}
/**
* r = this << n*DB
*/
bi_internal function dlShiftTo(n:int, r:BigInteger):void {
var i:int;
for (i=t-1; i>=0; --i) {
r.a[i+n] = a[i];
}
for (i=n-1; i>=0; --i) {
r.a[i] = 0;
}
r.t = t+n;
r.s = s;
}
/**
* r = this >> n*DB
*/
bi_internal function drShiftTo(n:int, r:BigInteger):void {
var i:int;
for (i=n; i<t; ++i) {
r.a[i-n] = a[i];
}
r.t = Math.max(t-n,0);
r.s = s;
}
/**
* r = this << n
*/
bi_internal function lShiftTo(n:int, r:BigInteger):void {
var bs:int = n%DB;
var cbs:int = DB-bs;
var bm:int = (1<<cbs)-1;
var ds:int = n/DB;
var c:int = (s<<bs)&DM;
var i:int;
for (i=t-1; i>=0; --i) {
r.a[i+ds+1] = (a[i]>>cbs)|c;
c = (a[i]&bm)<<bs;
}
for (i=ds-1; i>=0; --i) {
r.a[i] = 0;
}
r.a[ds] = c;
r.t = t+ds+1;
r.s = s;
r.clamp();
}
/**
* r = this >> n
*/
bi_internal function rShiftTo(n:int, r:BigInteger):void {
r.s = s;
var ds:int = n/DB;
if (ds >= t) {
r.t = 0;
return;
}
var bs:int = n%DB;
var cbs:int = DB-bs;
var bm:int = (1<<bs)-1;
r.a[0] = a[ds]>>bs;
var i:int;
for (i=ds+1; i<t; ++i) {
r.a[i-ds-1] |= (a[i]&bm)<<cbs;
r.a[i-ds] = a[i]>>bs;
}
if (bs>0) {
r.a[t-ds-1] |= (s&bm)<<cbs;
}
r.t = t-ds;
r.clamp();
}
/**
* r = this - v
*/
bi_internal function subTo(v:BigInteger, r:BigInteger):void {
var i:int = 0;
var c:int = 0;
var m:int = Math.min(v.t, t);
while (i<m) {
c += a[i] - v.a[i];
r.a[i++] = c & DM;
c >>= DB;
}
if (v.t < t) {
c -= v.s;
while (i< t) {
c+= a[i];
r.a[i++] = c&DM;
c >>= DB;
}
c += s;
} else {
c += s;
while (i < v.t) {
c -= v.a[i];
r.a[i++] = c&DM;
c >>= DB;
}
c -= v.s;
}
r.s = (c<0)?-1:0;
if (c<-1) {
r.a[i++] = DV+c;
} else if (c>0) {
r.a[i++] = c;
}
r.t = i;
r.clamp();
}
/**
* am: Compute w_j += (x*this_i), propagates carries,
* c is initial carry, returns final carry.
* c < 3*dvalue, x < 2*dvalue, this_i < dvalue
*/
bi_internal function am(i:int,x:int,w:BigInteger,j:int,c:int,n:int):int {
var xl:int = x&0x7fff;
var xh:int = x>>15;
while(--n >= 0) {
var l:int = a[i]&0x7fff;
var h:int = a[i++]>>15;
var m:int = xh*l + h*xl;
l = xl*l + ((m&0x7fff)<<15)+w.a[j]+(c&0x3fffffff);
c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
w.a[j++] = l&0x3fffffff;
}
return c;
}
/**
* r = this * v, r != this,a (HAC 14.12)
* "this" should be the larger one if appropriate
*/
bi_internal function multiplyTo(v:BigInteger, r:BigInteger):void {
var x:BigInteger = abs();
var y:BigInteger = v.abs();
var i:int = x.t;
r.t = i+y.t;
while (--i >= 0) {
r.a[i] = 0;
}
for (i=0; i<y.t; ++i) {
r.a[i+x.t] = x.am(0, y.a[i], r, i, 0, x.t);
}
r.s = 0;
r.clamp();
if (s!=v.s) {
ZERO.subTo(r, r);
}
}
/**
* r = this^2, r != this (HAC 14.16)
*/
bi_internal function squareTo(r:BigInteger):void {
var x:BigInteger = abs();
var i:int = r.t = 2*x.t;
while (--i>=0) r.a[i] = 0;
for (i=0; i<x.t-1; ++i) {
var c:int = x.am(i, x.a[i], r, 2*i, 0, 1);
if ((r.a[i+x.t] += x.am(i+1, 2*x.a[i], r, 2*i+1, c, x.t-i-1)) >= DV) {
r.a[i+x.t] -= DV;
r.a[i+x.t+1] = 1;
}
}
if (r.t>0) {
r.a[r.t-1] += x.am(i, x.a[i], r, 2*i, 0, 1);
}
r.s = 0;
r.clamp();
}
/**
* divide this by m, quotient and remainder to q, r (HAC 14.20)
* r != q, this != m. q or r may be null.
*/
bi_internal function divRemTo(m:BigInteger, q:BigInteger = null, r:BigInteger = null):void {
var pm:BigInteger = m.abs();
if (pm.t <= 0) return;
var pt:BigInteger = abs();
if (pt.t < pm.t) {
if (q!=null) q.fromInt(0);
if (r!=null) copyTo(r);
return;
}
if (r==null) r = nbi();
var y:BigInteger = nbi();
var ts:int = s;
var ms:int = m.s;
var nsh:int = DB-nbits(pm.a[pm.t-1]); // normalize modulus
if (nsh>0) {
pm.lShiftTo(nsh, y);
pt.lShiftTo(nsh, r);
} else {
pm.copyTo(y);
pt.copyTo(r);
}
var ys:int = y.t;
var y0:int = y.a[ys-1];
if (y0==0) return;
var yt:Number = y0*(1<<F1)+((ys>1)?y.a[ys-2]>>F2:0);
var d1:Number = FV/yt;
var d2:Number = (1<<F1)/yt;
var e:Number = 1<<F2;
var i:int = r.t;
var j:int = i-ys;
var t:BigInteger = (q==null)?nbi():q;
y.dlShiftTo(j,t);
if (r.compareTo(t)>=0) {
r.a[r.t++] = 1;
r.subTo(t,r);
}
ONE.dlShiftTo(ys,t);
t.subTo(y,y); // "negative" y so we can replace sub with am later.
while(y.t<ys) y.(y.t++, 0);
while(--j >= 0) {
// Estimate quotient digit
var qd:int = (r.a[--i]==y0)?DM:Number(r.a[i])*d1+(Number(r.a[i-1])+e)*d2;
if ((r.a[i]+= y.am(0, qd, r, j, 0, ys))<qd) { // Try it out
y.dlShiftTo(j, t);
r.subTo(t,r);
while (r.a[i]<--qd) {
r.subTo(t,r);
}
}
}
if (q!=null) {
r.drShiftTo(ys,q);
if (ts!=ms) {
ZERO.subTo(q,q);
}
}
r.t = ys;
r.clamp();
if (nsh>0) {
r.rShiftTo(nsh, r); // Denormalize remainder
}
if (ts<0) {
ZERO.subTo(r,r);
}
}
/**
* return "-1/this % 2^DB"; useful for Mont. reduction
* justification:
* xy == 1 (mod n)
* xy = 1+km
* xy(2-xy) = (1+km)(1-km)
* x[y(2-xy)] = 1-k^2.m^2
* x[y(2-xy)] == 1 (mod m^2)
* if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
* should reduce x and y(2-xy) by m^2 at each step to keep size bounded
* [XXX unit test the living shit out of this.]
*/
bi_internal function invDigit():int {
if (t<1) return 0;
var x:int = a[0];
if ((x&1)==0) return 0;
var y:int = x&3; // y == 1/x mod 2^2
y = (y*(2-(x&0xf )*y)) &0xf; // y == 1/x mod 2^4
y = (y*(2-(x&0xff)*y)) &0xff; // y == 1/x mod 2^8
y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
// last step - calculate inverse mod DV directly;
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
// XXX 48 bit ints? Whaaaa? is there an implicit float conversion in here?
y = (y*(2-x*y%DV))%DV; // y == 1/x mod 2^dbits
// we really want the negative inverse, and -DV < y < DV
return (y>0)?DV-y:-y;
}
/**
* true iff this is even
*/
bi_internal function isEven():Boolean {
return ((t>0)?(a[0]&1):s) == 0;
}
/**
* this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
*/
bi_internal function exp(e:int, z:IReduction):BigInteger {
if (e > 0xffffffff || e < 1) return ONE;
var r:BigInteger = nbi();
var r2:BigInteger = nbi();
var g:BigInteger = z.convert(this);
var i:int = nbits(e)-1;
g.copyTo(r);
while(--i>=0) {
z.sqrTo(r, r2);
if ((e&(1<<i))>0) {
z.mulTo(r2,g,r);
} else {
var t:BigInteger = r;
r = r2;
r2 = t;
}
}
return z.revert(r);
}
bi_internal function intAt(str:String, index:int):int {
return parseInt(str.charAt(index), 36);
}
protected function nbi():* {
return new BigInteger;
}
/**
* return bigint initialized to value
*/
public static function nbv(value:int):BigInteger {
var bn:BigInteger = new BigInteger;
bn.fromInt(value);
return bn;
}
// Functions above are sufficient for RSA encryption.
// The stuff below is useful for decryption and key generation
public static const lowprimes:Array = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509];
public static const lplim:int = (1<<26)/lowprimes[lowprimes.length-1];
public function clone():BigInteger {
var r:BigInteger = new BigInteger;
this.copyTo(r);
return r;
}
/**
*
* @return value as integer
*
*/
public function intValue():int {
if (s<0) {
if (t==1) {
return a[0]-DV;
} else if (t==0) {
return -1;
}
} else if (t==1) {
return a[0];
} else if (t==0) {
return 0;
}
// assumes 16 < DB < 32
return ((a[1]&((1<<(32-DB))-1))<<DB)|a[0];
}
/**
*
* @return value as byte
*
*/
public function byteValue():int {
return (t==0)?s:(a[0]<<24)>>24;
}
/**
*
* @return value as short (assumes DB>=16)
*
*/
public function shortValue():int {
return (t==0)?s:(a[0]<<16)>>16;
}
/**
*
* @param r
* @return x s.t. r^x < DV
*
*/
protected function chunkSize(r:Number):int {
return Math.floor(Math.LN2*DB/Math.log(r));
}
/**
*
* @return 0 if this ==0, 1 if this >0
*
*/
public function sigNum():int {
if (s<0) {
return -1;
} else if (t<=0 || (t==1 && a[0]<=0)) {
return 0;
} else{
return 1;
}
}
/**
*
* @param b: radix to use
* @return a string representing the integer converted to the radix.
*
*/
protected function toRadix(b:uint=10):String {
if (sigNum()==0 || b<2 || b>32) return "0";
var cs:int = chunkSize(b);
var a:Number = Math.pow(b, cs);
var d:BigInteger = nbv(a);
var y:BigInteger = nbi();
var z:BigInteger = nbi();
var r:String = "";
divRemTo(d, y, z);
while (y.sigNum()>0) {
r = (a+z.intValue()).toString(b).substr(1) + r;
y.divRemTo(d,y,z);
}
return z.intValue().toString(b) + r;
}
/**
*
* @param s a string to convert from using radix.
* @param b a radix
*
*/
protected function fromRadix(s:String, b:int = 10):void {
fromInt(0);
var cs:int = chunkSize(b);
var d:Number = Math.pow(b, cs);
var mi:Boolean = false;
var j:int = 0;
var w:int = 0;
for (var i:int=0;i<s.length;++i) {
var x:int = intAt(s, i);
if (x<0) {
if (s.charAt(i) == "-" && sigNum() == 0) {
mi = true;
}
continue;
}
w = b*w+x;
if (++j >= cs) {
dMultiply(d);
dAddOffset(w,0);
j=0;
w=0;
}
}
if (j>0) {
dMultiply(Math.pow(b,j));
dAddOffset(w,0);
}
if (mi) {
BigInteger.ZERO.subTo(this, this);
}
}
// XXX function fromNumber not written yet.
/**
*
* @return a byte array.
*
*/
public function toByteArray():ByteArray {
var i:int = t;
var r:ByteArray = new ByteArray;
r[0] = s;
var p:int = DB-(i*DB)%8;
var d:int;
var k:int=0;
if (i-->0) {
if (p<DB && (d=a[i]>>p)!=(s&DM)>>p) {
r[k++] = d|(s<<(DB-p));
}
while (i>=0) {
if(p<8) {
d = (a[i]&((1<<p)-1))<<(8-p);
d|= a[--i]>>(p+=DB-8);
} else {
d = (a[i]>>(p-=8))&0xff;
if (p<=0) {
p += DB;
--i;
}
}
if ((d&0x80)!=0) d|=-256;
if (k==0 && (s&0x80)!=(d&0x80)) ++k;
if (k>0 || d!=s) r[k++] = d;
}
}
return r;
}
public function equals(a:BigInteger):Boolean {
return compareTo(a)==0;
}
public function min(a:BigInteger):BigInteger {
return (compareTo(a)<0)?this:a;
}
public function max(a:BigInteger):BigInteger {
return (compareTo(a)>0)?this:a;
}
/**
*
* @param a a BigInteger to perform the operation with
* @param op a Function implementing the operation
* @param r a BigInteger to store the result of the operation
*
*/
protected function bitwiseTo(a:BigInteger, op:Function, r:BigInteger):void {
var i:int;
var f:int;
var m:int = Math.min(a.t, t);
for (i=0; i<m; ++i) {
r.a[i] = op(this.a[i],a.a[i]);
}
if (a.t<t) {
f = a.s&DM;
for (i=m;i<t;++i) {
r.a[i] = op(this.a[i],f);
}
r.t = t;
} else {
f = s&DM;
for (i=m;i<a.t;++i) {
r.a[i] = op(f,a.a[i]);
}
r.t = a.t;
}
r.s = op(s, a.s);
r.clamp();
}
private function op_and(x:int, y:int):int {return x&y;}
public function and(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
bitwiseTo(a, op_and, r);
return r;
}
private function op_or(x:int, y:int):int {return x|y;}
public function or(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
bitwiseTo(a, op_or, r);
return r;
}
private function op_xor(x:int, y:int):int {return x^y;}
public function xor(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
bitwiseTo(a, op_xor, r);
return r;
}
private function op_andnot(x:int, y:int):int { return x&~y;}
public function andNot(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
bitwiseTo(a, op_andnot, r);
return r;
}
public function not():BigInteger {
var r:BigInteger = new BigInteger;
for (var i:int=0;i<t;++i) {
r[i] = DM&~a[i];
}
r.t = t;
r.s = ~s;
return r;
}
public function shiftLeft(n:int):BigInteger {
var r:BigInteger = new BigInteger;
if (n<0) {
rShiftTo(-n, r);
} else {
lShiftTo(n, r);
}
return r;
}
public function shiftRight(n:int):BigInteger {
var r:BigInteger = new BigInteger;
if (n<0) {
lShiftTo(-n, r);
} else {
rShiftTo(n, r);
}
return r;
}
/**
*
* @param x
* @return index of lowet 1-bit in x, x < 2^31
*
*/
private function lbit(x:int):int {
if (x==0) return -1;
var r:int = 0;
if ((x&0xffff)==0) { x>>= 16; r += 16; }
if ((x&0xff) == 0) { x>>= 8; r += 8; }
if ((x&0xf) == 0) { x>>= 4; r += 4; }
if ((x&0x3) == 0) { x>>= 2; r += 2; }
if ((x&0x1) == 0) ++r;
return r;
}
/**
*
* @return index of lowest 1-bit (or -1 if none)
*
*/
public function getLowestSetBit():int {
for (var i:int=0;i<t;++i) {
if (a[i]!=0) return i*DB+lbit(a[i]);
}
if (s<0) return t*DB;
return -1;
}
/**
*
* @param x
* @return number of 1 bits in x
*
*/
private function cbit(x:int):int {
var r:uint =0;
while (x!=0) { x &= x-1; ++r }
return r;
}
/**
*
* @return number of set bits
*
*/
public function bitCount():int {
var r:int=0;
var x:int = s&DM;
for (var i:int=0;i<t;++i) {
r += cbit(a[i]^x);
}
return r;
}
/**
*
* @param n
* @return true iff nth bit is set
*
*/
public function testBit(n:int):Boolean {
var j:int = Math.floor(n/DB);
if (j>=t) {
return s!=0;
}
return ((a[j]&(1<<(n%DB)))!=0);
}
/**
*
* @param n
* @param op
* @return this op (1<<n)
*
*/
protected function changeBit(n:int,op:Function):BigInteger {
var r:BigInteger = BigInteger.ONE.shiftLeft(n);
bitwiseTo(r, op, r);
return r;
}
/**
*
* @param n
* @return this | (1<<n)
*
*/
public function setBit(n:int):BigInteger { return changeBit(n, op_or); }
/**
*
* @param n
* @return this & ~(1<<n)
*
*/
public function clearBit(n:int):BigInteger { return changeBit(n, op_andnot); }
/**
*
* @param n
* @return this ^ (1<<n)
*
*/
public function flipBit(n:int):BigInteger { return changeBit(n, op_xor); }
/**
*
* @param a
* @param r = this + a
*
*/
protected function addTo(a:BigInteger, r:BigInteger):void {
var i:int = 0;
var c:int = 0;
var m:int = Math.min(a.t, t);
while (i<m) {
c += this.a[i] + a.a[i];
r.a[i++] = c&DM;
c>>=DB;
}
if (a.t < t) {
c += a.s;
while (i<t) {
c += this.a[i];
r.a[i++] = c&DM;
c >>= DB;
}
c += s;
} else {
c += s;
while (i<a.t) {
c += a.a[i];
r.a[i++] = c&DM;
c >>= DB;
}
c += a.s;
}
r.s = (c<0)?-1:0;
if (c>0) {
r.a[i++] = c;
} else if (c<-1) {
r.a[i++] = DV+c;
}
r.t = i;
r.clamp();
}
/**
*
* @param a
* @return this + a
*
*/
public function add(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
addTo(a,r);
return r;
}
/**
*
* @param a
* @return this - a
*
*/
public function subtract(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
subTo(a,r);
return r;
}
/**
*
* @param a
* @return this * a
*
*/
public function multiply(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
multiplyTo(a,r);
return r;
}
/**
*
* @param a
* @return this / a
*
*/
public function divide(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
divRemTo(a, r, null);
return r;
}
public function remainder(a:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
divRemTo(a, null, r);
return r;
}
/**
*
* @param a
* @return [this/a, this%a]
*
*/
public function divideAndRemainder(a:BigInteger):Array {
var q:BigInteger = new BigInteger;
var r:BigInteger = new BigInteger;
divRemTo(a, q, r);
return [q,r];
}
/**
*
* this *= n, this >=0, 1 < n < DV
*
* @param n
*
*/
bi_internal function dMultiply(n:int):void {
a[t] = am(0, n-1, this, 0, 0, t);
++t;
clamp();
}
/**
*
* this += n << w words, this >= 0
*
* @param n
* @param w
*
*/
bi_internal function dAddOffset(n:int, w:int):void {
while (t<=w) {
a[t++] = 0;
}
a[w] += n;
while (a[w] >= DV) {
a[w] -= DV;
if (++w >= t) {
a[t++] = 0;
}
++a[w];
}
}
/**
*
* @param e
* @return this^e
*
*/
public function pow(e:int):BigInteger {
return exp(e, new NullReduction);
}
/**
*
* @param a
* @param n
* @param r = lower n words of "this * a", a.t <= n
*
*/
bi_internal function multiplyLowerTo(a:BigInteger, n:int, r:BigInteger):void {
var i:int = Math.min(t+a.t, n);
r.s = 0; // assumes a, this >= 0
r.t = i;
while (i>0) {
r.a[--i]=0;
}
var j:int;
for (j=r.t-t;i<j;++i) {
r.a[i+t] = am(0, a.a[i], r, i, 0, t);
}
for (j=Math.min(a.t,n);i<j;++i) {
am(0, a.a[i], r, i, 0, n-i);
}
r.clamp();
}
/**
*
* @param a
* @param n
* @param r = "this * a" without lower n words, n > 0
*
*/
bi_internal function multiplyUpperTo(a:BigInteger, n:int, r:BigInteger):void {
--n;
var i:int = r.t = t+a.t-n;
r.s = 0; // assumes a,this >= 0
while (--i>=0) {
r.a[i] = 0;
}
for (i=Math.max(n-t,0);i<a.t;++i) {
r.a[t+i-n] = am(n-i, a.a[i], r, 0, 0, t+i-n);
}
r.clamp();
r.drShiftTo(1,r);
}
/**
*
* @param e
* @param m
* @return this^e % m (HAC 14.85)
*
*/
public function modPow(e:BigInteger, m:BigInteger):BigInteger {
var i:int = e.bitLength();
var k:int;
var r:BigInteger = nbv(1);
var z:IReduction;
if (i<=0) {
return r;
} else if (i<18) {
k=1;
} else if (i<48) {
k=3;
} else if (i<144) {
k=4;
} else if (i<768) {
k=5;
} else {
k=6;
}
if (i<8) {
z = new ClassicReduction(m);
} else if (m.isEven()) {
z = new BarrettReduction(m);
} else {
z = new MontgomeryReduction(m);
}
// precomputation
var g:Array = [];
var n:int = 3;
var k1:int = k-1;
var km:int = (1<<k)-1;
g[1] = z.convert(this);
if (k > 1) {
var g2:BigInteger = new BigInteger;
z.sqrTo(g[1], g2);
while (n<=km) {
g[n] = new BigInteger;
z.mulTo(g2, g[n-2], g[n]);
n += 2;
}
}
var j:int = e.t-1;
var w:int;
var is1:Boolean = true;
var r2:BigInteger = new BigInteger;
var t:BigInteger;
i = nbits(e.a[j])-1;
while (j>=0) {
if (i>=k1) {
w = (e.a[j]>>(i-k1))&km;
} else {
w = (e.a[j]&((1<<(i+1))-1))<<(k1-i);
if (j>0) {
w |= e.a[j-1]>>(DB+i-k1);
}
}
n = k;
while ((w&1)==0) {
w >>= 1;
--n;
}
if ((i -= n) <0) {
i += DB;
--j;
}
if (is1) { // ret == 1, don't bother squaring or multiplying it
g[w].copyTo(r);
is1 = false;
} else {
while (n>1) {
z.sqrTo(r, r2);
z.sqrTo(r2, r);
n -= 2;
}
if (n>0) {
z.sqrTo(r, r2);
} else {
t = r;
r = r2;
r2 = t;
}
z.mulTo(r2, g[w], r);
}
while (j>=0 && (e.a[j]&(1<<i)) == 0) {
z.sqrTo(r, r2);
t = r;
r = r2;
r2 = t;
if (--i<0) {
i = DB-1;
--j;
}
}
}
return z.revert(r);
}
/**
*
* @param a
* @return gcd(this, a) (HAC 14.54)
*
*/
public function gcd(a:BigInteger):BigInteger {
var x:BigInteger = (s<0)?negate():clone();
var y:BigInteger = (a.s<0)?a.negate():a.clone();
if (x.compareTo(y)<0) {
var t:BigInteger=x;
x=y;
y=t;
}
var i:int = x.getLowestSetBit();
var g:int = y.getLowestSetBit();
if (g<0) return x;
if (i<g) g= i;
if (g>0) {
x.rShiftTo(g, x);
y.rShiftTo(g, y);
}
while (x.sigNum()>0) {
if ((i = x.getLowestSetBit()) >0) {
x.rShiftTo(i, x);
}
if ((i = y.getLowestSetBit()) >0) {
y.rShiftTo(i, y);
}
if (x.compareTo(y) >= 0) {
x.subTo(y, x);
x.rShiftTo(1, x);
} else {
y.subTo(x, y);
y.rShiftTo(1, y);
}
}
if (g>0) {
y.lShiftTo(g, y);
}
return y;
}
/**
*
* @param n
* @return this % n, n < 2^DB
*
*/
protected function modInt(n:int):int {
if (n<=0) return 0;
var d:int = DV%n;
var r:int = (s<0)?n-1:0;
if (t>0) {
if (d==0) {
r = a[0]%n;
} else {
for (var i:int=t-1;i>=0;--i) {
r = (d*r+a[i])%n;
}
}
}
return r;
}
/**
*
* @param m
* @return 1/this %m (HAC 14.61)
*
*/
public function modInverse(m:BigInteger):BigInteger {
var ac:Boolean = m.isEven();
if ((isEven()&&ac) || m.sigNum()==0) {
return BigInteger.ZERO;
}
var u:BigInteger = m.clone();
var v:BigInteger = clone();
var a:BigInteger = nbv(1);
var b:BigInteger = nbv(0);
var c:BigInteger = nbv(0);
var d:BigInteger = nbv(1);
while (u.sigNum()!=0) {
while (u.isEven()) {
u.rShiftTo(1,u);
if (ac) {
if (!a.isEven() || !b.isEven()) {
a.addTo(this,a);
b.subTo(m,b);
}
a.rShiftTo(1,a);
} else if (!b.isEven()) {
b.subTo(m,b);
}
b.rShiftTo(1,b);
}
while (v.isEven()) {
v.rShiftTo(1,v);
if (ac) {
if (!c.isEven() || !d.isEven()) {
c.addTo(this,c);
d.subTo(m,d);
}
c.rShiftTo(1,c);
} else if (!d.isEven()) {
d.subTo(m,d);
}
d.rShiftTo(1,d);
}
if (u.compareTo(v)>=0) {
u.subTo(v,u);
if (ac) {
a.subTo(c,a);
}
b.subTo(d,b);
} else {
v.subTo(u,v);
if (ac) {
c.subTo(a,c);
}
d.subTo(b,d);
}
}
if (v.compareTo(BigInteger.ONE) != 0) {
return BigInteger.ZERO;
}
if (d.compareTo(m) >= 0) {
return d.subtract(m);
}
if (d.sigNum()<0) {
d.addTo(m,d);
} else {
return d;
}
if (d.sigNum()<0) {
return d.add(m);
} else {
return d;
}
}
/**
*
* @param t
* @return primality with certainty >= 1-.5^t
*
*/
public function isProbablePrime(t:int):Boolean {
var i:int;
var x:BigInteger = abs();
if (x.t == 1 && x.a[0]<=lowprimes[lowprimes.length-1]) {
for (i=0;i<lowprimes.length;++i) {
if (x[0]==lowprimes[i]) return true;
}
return false;
}
if (x.isEven()) return false;
i = 1;
while (i<lowprimes.length) {
var m:int = lowprimes[i];
var j:int = i+1;
while (j<lowprimes.length && m<lplim) {
m *= lowprimes[j++];
}
m = x.modInt(m);
while (i<j) {
if (m%lowprimes[i++]==0) {
return false;
}
}
}
return x.millerRabin(t);
}
/**
*
* @param t
* @return true if probably prime (HAC 4.24, Miller-Rabin)
*
*/
protected function millerRabin(t:int):Boolean {
var n1:BigInteger = subtract(BigInteger.ONE);
var k:int = n1.getLowestSetBit();
if (k<=0) {
return false;
}
var r:BigInteger = n1.shiftRight(k);
t = (t+1)>>1;
if (t>lowprimes.length) {
t = lowprimes.length;
}
var a:BigInteger = new BigInteger;
for (var i:int=0;i<t;++i) {
a.fromInt(lowprimes[i]);
var y:BigInteger = a.modPow(r, this);
if (y.compareTo(BigInteger.ONE)!=0 && y.compareTo(n1)!=0) {
var j:int = 1;
while (j++<k && y.compareTo(n1)!=0) {
y = y.modPowInt(2, this);
if (y.compareTo(BigInteger.ONE)==0) {
return false;
}
}
if (y.compareTo(n1)!=0) {
return false;
}
}
}
return true;
}
/**
* Tweak our BigInteger until it looks prime enough
*
* @param bits
* @param t
*
*/
public function primify(bits:int, t:int):void {
if (!testBit(bits-1)) { // force MSB set
bitwiseTo(BigInteger.ONE.shiftLeft(bits-1), op_or, this);
}
if (isEven()) {
dAddOffset(1,0); // force odd
}
while (!isProbablePrime(t)) {
dAddOffset(2,0);
while(bitLength()>bits) subTo(BigInteger.ONE.shiftLeft(bits-1),this);
}
}
}
}
package com.hurlant.math
{
use namespace bi_internal;
/**
* Modular reduction using "classic" algorithm
*/
internal class ClassicReduction implements IReduction
{
private var m:BigInteger;
public function ClassicReduction(m:BigInteger) {
this.m = m;
}
public function convert(x:BigInteger):BigInteger {
if (x.s<0 || x.compareTo(m)>=0) {
return x.mod(m);
}
return x;
}
public function revert(x:BigInteger):BigInteger {
return x;
}
public function reduce(x:BigInteger):void {
x.divRemTo(m, null,x);
}
public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void {
x.multiplyTo(y,r);
reduce(r);
}
public function sqrTo(x:BigInteger, r:BigInteger):void {
x.squareTo(r);
reduce(r);
}
}
}
\ No newline at end of file
package com.hurlant.math
{
internal interface IReduction
{
function convert(x:BigInteger):BigInteger;
function revert(x:BigInteger):BigInteger;
function reduce(x:BigInteger):void;
function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void;
function sqrTo(x:BigInteger, r:BigInteger):void;
}
}
\ No newline at end of file
package com.hurlant.math
{
use namespace bi_internal;
/**
* Montgomery reduction
*/
internal class MontgomeryReduction implements IReduction
{
private var m:BigInteger;
private var mp:int;
private var mpl:int;
private var mph:int;
private var um:int;
private var mt2:int;
public function MontgomeryReduction(m:BigInteger) {
this.m = m;
mp = m.invDigit();
mpl = mp & 0x7fff;
mph = mp>>15;
um = (1<<(BigInteger.DB-15))-1;
mt2 = 2*m.t;
}
/**
* xR mod m
*/
public function convert(x:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
x.abs().dlShiftTo(m.t, r);
r.divRemTo(m, null, r);
if (x.s<0 && r.compareTo(BigInteger.ZERO)>0) {
m.subTo(r,r);
}
return r;
}
/**
* x/R mod m
*/
public function revert(x:BigInteger):BigInteger {
var r:BigInteger = new BigInteger;
x.copyTo(r);
reduce(r);
return r;
}
/**
* x = x/R mod m (HAC 14.32)
*/
public function reduce(x:BigInteger):void {
while (x.t<=mt2) { // pad x so am has enough room later
x.a[x.t++] = 0;
}
for (var i:int=0; i<m.t; ++i) {
// faster way of calculating u0 = x[i]*mp mod DV
var j:int = x.a[i]&0x7fff;
var u0:int = (j*mpl+(((j*mph+(x.a[i]>>15)*mpl)&um)<<15))&BigInteger.DM;
// use am to combine the multiply-shift-add into one call
j = i+m.t;
x.a[j] += m.am(0, u0, x, i, 0, m.t);
// propagate carry
while (x.a[j]>=BigInteger.DV) {
x.a[j] -= BigInteger.DV;
x.a[++j]++;
}
}
x.clamp();
x.drShiftTo(m.t, x);
if (x.compareTo(m)>=0) {
x.subTo(m,x);
}
}
/**
* r = "x^2/R mod m"; x != r
*/
public function sqrTo(x:BigInteger, r:BigInteger):void {
x.squareTo(r);
reduce(r);
}
/**
* r = "xy/R mod m"; x,y != r
*/
public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void {
x.multiplyTo(y,r);
reduce(r);
}
}
}
\ No newline at end of file
package com.hurlant.math
{
use namespace bi_internal;
/**
* A "null" reducer
*/
public class NullReduction implements IReduction
{
public function revert(x:BigInteger):BigInteger
{
return x;
}
public function mulTo(x:BigInteger, y:BigInteger, r:BigInteger):void
{
x.multiplyTo(y,r);
}
public function sqrTo(x:BigInteger, r:BigInteger):void
{
x.squareTo(r);
}
public function convert(x:BigInteger):BigInteger
{
return x;
}
public function reduce(x:BigInteger):void
{
}
}
}
\ No newline at end of file
/**
* bi_internal
*
* A namespace. w00t.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.math {
public namespace bi_internal = "http://crypto.hurlant.com/BigInteger";
}
\ No newline at end of file
/**
* ArrayUtil
*
* A class that allows to compare two ByteArrays.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util {
import flash.utils.ByteArray;
public class ArrayUtil {
public static function equals(a1:ByteArray, a2:ByteArray):Boolean {
if (a1.length != a2.length) return false;
var l:int = a1.length;
for (var i:int=0;i<l;i++) {
if (a1[i]!=a2[i]) return false;
}
return true;
}
}
}
\ No newline at end of file
/* Base64 library for ActionScript 3.0.
* Based on: Ma Bingyao code.
* Optimized by: Jean-Philippe Auclair / jpauclair.wordpress.com
* Copyright (C) 2007 Ma Bingyao <andot@ujn.edu.cn>
* LastModified: Oct 26, 2009
* This library is free. You can redistribute it and/or modify it.
*/
package com.hurlant.util{
import flash.utils.ByteArray;
public class Base64
{
private static const _encodeChars : Vector.<int> = InitEncoreChar();
private static const _decodeChars : Vector.<int> = InitDecodeChar();
public static function encodeByteArray(data : ByteArray) : String
{
var out : ByteArray = new ByteArray();
//Presetting the length keep the memory smaller and optimize speed since there is no "grow" needed
out.length = (2 + data.length - ((data.length + 2) % 3)) * 4 / 3; //Preset length //1.6 to 1.5 ms
var i : int = 0;
var r : int = data.length % 3;
var len : int = data.length - r;
var c : int; //read (3) character AND write (4) characters
while (i < len)
{
//Read 3 Characters (8bit * 3 = 24 bits)
c = data[i++] << 16 | data[i++] << 8 | data[i++];
//Cannot optimize this to read int because of the positioning overhead. (as3 bytearray seek is slow)
//Convert to 4 Characters (6 bit * 4 = 24 bits)
c = (_encodeChars[c >>> 18] << 24) | (_encodeChars[c >>> 12 & 0x3f] << 16) | (_encodeChars[c >>> 6 & 0x3f] << 8) | _encodeChars[c & 0x3f];
//Optimization: On older and slower computer, do one write Int instead of 4 write byte: 1.5 to 0.71 ms
out.writeInt(c);
/*
out.writeByte(_encodeChars[c >> 18] );
out.writeByte(_encodeChars[c >> 12 & 0x3f]);
out.writeByte(_encodeChars[c >> 6 & 0x3f]);
out.writeByte(_encodeChars[c & 0x3f]);
*/
}
if (r == 1) //Need two "=" padding
{
//Read one char, write two chars, write padding
c = data[i];
c = (_encodeChars[c >>> 2] << 24) | (_encodeChars[(c & 0x03) << 4] << 16) | 61 << 8 | 61;
out.writeInt(c);
}
else if (r == 2) //Need one "=" padding
{
c = data[i++] << 8 | data[i];
c = (_encodeChars[c >>> 10] << 24) | (_encodeChars[c >>> 4 & 0x3f] << 16) | (_encodeChars[(c & 0x0f) << 2] << 8) | 61;
out.writeInt(c);
}
out.position = 0;
return out.readUTFBytes(out.length);
}
public static function decodeToByteArray(str : String) : ByteArray
{
var c1 : int;
var c2 : int;
var c3 : int;
var c4 : int;
var i : int;
var len : int;
var out : ByteArray;
len = str.length;
i = 0;
out = new ByteArray();
var byteString : ByteArray = new ByteArray();
byteString.writeUTFBytes(str);
while (i < len)
{
//c1
do
{
c1 = _decodeChars[byteString[i++]];
} while (i < len && c1 == -1);
if (c1 == -1) break;
//c2
do
{
c2 = _decodeChars[byteString[i++]];
} while (i < len && c2 == -1);
if (c2 == -1) break;
out.writeByte((c1 << 2) | ((c2 & 0x30) >> 4));
//c3
do
{
c3 = byteString[i++];
if (c3 == 61) return out;
c3 = _decodeChars[c3];
} while (i < len && c3 == -1);
if (c3 == -1) break;
out.writeByte(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2));
//c4
do {
c4 = byteString[i++];
if (c4 == 61) return out;
c4 = _decodeChars[c4];
} while (i < len && c4 == -1);
if (c4 == -1) break;
out.writeByte(((c3 & 0x03) << 6) | c4);
}
out.position = 0;
return out;
}
public static function encode(data : String) : String {
// Convert string to ByteArray
var bytes : ByteArray = new ByteArray();
bytes.writeUTFBytes(data);
// Return encoded ByteArray
return encodeByteArray(bytes);
}
public static function decode(data : String) : String {
// Decode data to ByteArray
var bytes : ByteArray = decodeToByteArray(data);
// Convert to string and return
return bytes.readUTFBytes(bytes.length);
}
public static function InitEncoreChar() : Vector.<int>
{
var encodeChars : Vector.<int> = new Vector.<int>();
// We could push the number directly, but i think it's nice to see the characters (with no overhead on encode/decode)
var chars : String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var i : int = 0; i < 64; i++)
{
encodeChars.push(chars.charCodeAt(i));
}
/*
encodeChars.push(
65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110,
111, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 43, 47);
*/
return encodeChars;
}
public static function InitDecodeChar() : Vector.<int>
{
var decodeChars : Vector.<int> = new Vector.<int>();
decodeChars.push(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
- 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
return decodeChars;
}
}
}
\ No newline at end of file
/**
* Hex
*
* Utility class to convert Hex strings to ByteArray or String types.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util
{
import flash.utils.ByteArray;
public class Hex
{
/**
* Support straight hex, or colon-laced hex.
* (that means 23:03:0e:f0, but *NOT* 23:3:e:f0)
* Whitespace characters are ignored.
*/
public static function toArray(hex:String):ByteArray {
hex = hex.replace(/\s|:/gm,'');
var a:ByteArray = new ByteArray;
if (hex.length&1==1) hex="0"+hex;
for (var i:uint=0;i<hex.length;i+=2) {
a[i/2] = parseInt(hex.substr(i,2),16);
}
return a;
}
public static function fromArray(array:ByteArray, colons:Boolean=false):String {
var s:String = "";
for (var i:uint=0;i<array.length;i++) {
s+=("0"+array[i].toString(16)).substr(-2,2);
if (colons) {
if (i<array.length-1) s+=":";
}
}
return s;
}
/**
*
* @param hex
* @return a UTF-8 string decoded from hex
*
*/
public static function toString(hex:String):String {
var a:ByteArray = toArray(hex);
return a.readUTFBytes(a.length);
}
/**
*
* @param str
* @return a hex string encoded from the UTF-8 string str
*
*/
public static function fromString(str:String, colons:Boolean=false):String {
var a:ByteArray = new ByteArray;
a.writeUTFBytes(str);
return fromArray(a, colons);
}
}
}
\ No newline at end of file
/**
* Memory
*
* A class with a few memory-management methods, as much as
* such a thing exists in a Flash player.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util
{
import flash.net.LocalConnection;
import flash.system.System;
public class Memory
{
public static function gc():void {
// force a GC
try {
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:*) {}
}
public static function get used():uint {
return System.totalMemory;
}
}
}
\ No newline at end of file
/**
* ByteString
*
* An ASN1 type for a ByteString, represented with a ByteArray
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
public class ByteString extends ByteArray implements IAsn1Type
{
private var type:uint;
private var len:uint;
public function ByteString(type:uint = 0x04, length:uint = 0x00) {
this.type = type;
this.len = length;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
public function toDER():ByteArray {
return DER.wrapDER(type, this);
}
override public function toString():String {
return DER.indent+"ByteString["+type+"]["+len+"]["+Hex.fromArray(this)+"]";
}
}
}
\ No newline at end of file
/**
* DER
*
* A basic class to parse DER structures.
* It is very incomplete, but sufficient to extract whatever data we need so far.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import com.hurlant.math.BigInteger;
import flash.utils.ByteArray;
import com.hurlant.util.der.Sequence;
import com.hurlant.util.Hex;
// goal 1: to be able to parse an RSA Private Key PEM file.
// goal 2: to parse an X509v3 cert. kinda.
/**
* DER for dummies:
* http://luca.ntop.org/Teaching/Appunti/asn1.html
*
* This class does the bare minimum to get by. if that.
*/
public class DER
{
public static var indent:String = "";
public static function parse(der:ByteArray, structure:*=null):IAsn1Type {
/* if (der.position==0) {
trace("DER.parse: "+Hex.fromArray(der));
}
*/ // type
var type:int = der.readUnsignedByte();
var constructed:Boolean = (type&0x20)!=0;
type &=0x1F;
// length
var len:int = der.readUnsignedByte();
if (len>=0x80) {
// long form of length
var count:int = len & 0x7f;
len = 0;
while (count>0) {
len = (len<<8) | der.readUnsignedByte();
count--;
}
}
// data
var b:ByteArray
switch (type) {
case 0x00: // WHAT IS THIS THINGY? (seen as 0xa0)
// (note to self: read a spec someday.)
// for now, treat as a sequence.
case 0x10: // SEQUENCE/SEQUENCE OF. whatever
// treat as an array
var p:int = der.position;
var o:Sequence = new Sequence(type, len);
var arrayStruct:Array = structure as Array;
if (arrayStruct!=null) {
// copy the array, as we destroy it later.
arrayStruct = arrayStruct.concat();
}
while (der.position < p+len) {
var tmpStruct:Object = null
if (arrayStruct!=null) {
tmpStruct = arrayStruct.shift();
}
if (tmpStruct!=null) {
while (tmpStruct && tmpStruct.optional) {
// make sure we have something that looks reasonable. XXX I'm winging it here..
var wantConstructed:Boolean = (tmpStruct.value is Array);
var isConstructed:Boolean = isConstructedType(der);
if (wantConstructed!=isConstructed) {
// not found. put default stuff, or null
o.push(tmpStruct.defaultValue);
o[tmpStruct.name] = tmpStruct.defaultValue;
// try the next thing
tmpStruct = arrayStruct.shift();
} else {
break;
}
}
}
if (tmpStruct!=null) {
var name:String = tmpStruct.name;
var value:* = tmpStruct.value;
if (tmpStruct.extract) {
// we need to keep a binary copy of this element
var size:int = getLengthOfNextElement(der);
var ba:ByteArray = new ByteArray;
ba.writeBytes(der, der.position, size);
o[name+"_bin"] = ba;
}
var obj:IAsn1Type = DER.parse(der, value);
o.push(obj);
o[name] = obj;
} else {
o.push(DER.parse(der));
}
}
return o;
case 0x11: // SET/SET OF
p = der.position;
var s:Set = new Set(type, len);
while (der.position < p+len) {
s.push(DER.parse(der));
}
return s;
case 0x02: // INTEGER
// put in a BigInteger
b = new ByteArray;
der.readBytes(b,0,len);
b.position=0;
return new Integer(type, len, b);
case 0x06: // OBJECT IDENTIFIER:
b = new ByteArray;
der.readBytes(b,0,len);
b.position=0;
return new ObjectIdentifier(type, len, b);
default:
trace("I DONT KNOW HOW TO HANDLE DER stuff of TYPE "+type);
// fall through
case 0x03: // BIT STRING
if (der[der.position]==0) {
//trace("Horrible Bit String pre-padding removal hack."); // I wish I had the patience to find a spec for this.
der.position++;
len--;
}
case 0x04: // OCTET STRING
// stuff in a ByteArray for now.
var bs:ByteString = new ByteString(type, len);
der.readBytes(bs,0,len);
return bs;
case 0x05: // NULL
// if len!=0, something's horribly wrong.
// should I check?
return null;
case 0x13: // PrintableString
var ps:PrintableString = new PrintableString(type, len);
ps.setString(der.readMultiByte(len, "US-ASCII"));
return ps;
case 0x22: // XXX look up what this is. openssl uses this to store my email.
case 0x14: // T61String - an horrible format we don't even pretend to support correctly
ps = new PrintableString(type, len);
ps.setString(der.readMultiByte(len, "latin1"));
return ps;
case 0x17: // UTCTime
var ut:UTCTime = new UTCTime(type, len);
ut.setUTCTime(der.readMultiByte(len, "US-ASCII"));
return ut;
}
}
private static function getLengthOfNextElement(b:ByteArray):int {
var p:uint = b.position;
// length
b.position++;
var len:int = b.readUnsignedByte();
if (len>=0x80) {
// long form of length
var count:int = len & 0x7f;
len = 0;
while (count>0) {
len = (len<<8) | b.readUnsignedByte();
count--;
}
}
len += b.position-p; // length of length
b.position = p;
return len;
}
private static function isConstructedType(b:ByteArray):Boolean {
var type:int = b[b.position];
return (type&0x20)!=0;
}
public static function wrapDER(type:int, data:ByteArray):ByteArray {
var d:ByteArray = new ByteArray;
d.writeByte(type);
var len:int = data.length;
if (len<128) {
d.writeByte(len);
} else if (len<256) {
d.writeByte(1 | 0x80);
d.writeByte(len);
} else if (len<65536) {
d.writeByte(2 | 0x80);
d.writeByte(len>>8);
d.writeByte(len);
} else if (len<65536*256) {
d.writeByte(3 | 0x80);
d.writeByte(len>>16);
d.writeByte(len>>8);
d.writeByte(len);
} else {
d.writeByte(4 | 0x80);
d.writeByte(len>>24);
d.writeByte(len>>16);
d.writeByte(len>>8);
d.writeByte(len);
}
d.writeBytes(data);
d.position=0;
return d;
}
}
}
\ No newline at end of file
/**
* IAsn1Type
*
* An interface for Asn-1 types.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import flash.utils.ByteArray;
public interface IAsn1Type
{
function getType():uint;
function getLength():uint;
function toDER():ByteArray;
}
}
\ No newline at end of file
/**
* Integer
*
* An ASN1 type for an Integer, represented with a BigInteger
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import com.hurlant.math.BigInteger;
import flash.utils.ByteArray;
public class Integer extends BigInteger implements IAsn1Type
{
private var type:uint;
private var len:uint;
public function Integer(type:uint, length:uint, b:ByteArray) {
this.type = type;
this.len = length;
super(b);
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
override public function toString(radix:Number=0):String {
return DER.indent+"Integer["+type+"]["+len+"]["+super.toString(16)+"]";
}
public function toDER():ByteArray {
return null;
}
}
}
\ No newline at end of file
/**
* OID
*
* A list of various ObjectIdentifiers.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
public class OID
{
public static const RSA_ENCRYPTION:String = "1.2.840.113549.1.1.1";
public static const MD2_WITH_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.2";
public static const MD5_WITH_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.4";
public static const SHA1_WITH_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.5";
public static const MD2_ALGORITHM:String = "1.2.840.113549.2.2";
public static const MD5_ALGORITHM:String = "1.2.840.113549.2.5";
public static const DSA:String = "1.2.840.10040.4.1";
public static const DSA_WITH_SHA1:String = "1.2.840.10040.4.3";
public static const DH_PUBLIC_NUMBER:String = "1.2.840.10046.2.1";
public static const SHA1_ALGORITHM:String = "1.3.14.3.2.26";
public static const COMMON_NAME:String = "2.5.4.3";
public static const SURNAME:String = "2.5.4.4";
public static const COUNTRY_NAME:String = "2.5.4.6";
public static const LOCALITY_NAME:String = "2.5.4.7";
public static const STATE_NAME:String = "2.5.4.8";
public static const ORGANIZATION_NAME:String = "2.5.4.10";
public static const ORG_UNIT_NAME:String = "2.5.4.11";
public static const TITLE:String = "2.5.4.12";
}
}
\ No newline at end of file
/**
* ObjectIdentifier
*
* An ASN1 type for an ObjectIdentifier
* We store the oid in an Array.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import flash.utils.ByteArray;
public class ObjectIdentifier implements IAsn1Type
{
private var type:uint;
private var len:uint;
private var oid:Array;
public function ObjectIdentifier(type:uint, length:uint, b:*) {
this.type = type;
this.len = length;
if (b is ByteArray) {
parse(b as ByteArray);
} else if (b is String) {
generate(b as String);
} else {
throw new Error("Invalid call to new ObjectIdentifier");
}
}
private function generate(s:String):void {
oid = s.split(".");
}
private function parse(b:ByteArray):void {
// parse stuff
// first byte = 40*value1 + value2
var o:uint = b.readUnsignedByte();
var a:Array = []
a.push(uint(o/40));
a.push(uint(o%40));
var v:uint = 0;
while (b.bytesAvailable>0) {
o = b.readUnsignedByte();
var last:Boolean = (o&0x80)==0;
o &= 0x7f;
v = v*128 + o;
if (last) {
a.push(v);
v = 0;
}
}
oid = a;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
public function toDER():ByteArray {
var tmp:Array = [];
tmp[0] = oid[0]*40 + oid[1];
for (var i:int=2;i<oid.length;i++) {
var v:int = parseInt(oid[i]);
if (v<128) {
tmp.push(v);
} else if (v<128*128) {
tmp.push( (v>>7)|0x80 );
tmp.push( v&0x7f );
} else if (v<128*128*128) {
tmp.push( (v>>14)|0x80 );
tmp.push( (v>>7)&0x7f | 0x80 );
tmp.push( v&0x7f);
} else if (v<128*128*128*128) {
tmp.push( (v>>21)|0x80 );
tmp.push( (v>>14) & 0x7f | 0x80 );
tmp.push( (v>>7) & 0x7f | 0x80 );
tmp.push( v & 0x7f );
} else {
throw new Error("OID element bigger than we thought. :(");
}
}
len = tmp.length;
if (type==0) {
type = 6;
}
tmp.unshift(len); // assume length is small enough to fit here.
tmp.unshift(type);
var b:ByteArray = new ByteArray;
for (i=0;i<tmp.length;i++) {
b[i] = tmp[i];
}
return b;
}
public function toString():String {
return DER.indent+oid.join(".");
}
public function dump():String {
return "OID["+type+"]["+len+"]["+toString()+"]";
}
}
}
\ No newline at end of file
/**
* PEM
*
* A class to parse some PEM stuff.
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.math.BigInteger;
import com.hurlant.util.Base64;
import flash.utils.ByteArray;
import com.hurlant.util.Hex;
public class PEM
{
private static const RSA_PRIVATE_KEY_HEADER:String = "-----BEGIN RSA PRIVATE KEY-----";
private static const RSA_PRIVATE_KEY_FOOTER:String = "-----END RSA PRIVATE KEY-----";
private static const RSA_PUBLIC_KEY_HEADER:String = "-----BEGIN PUBLIC KEY-----";
private static const RSA_PUBLIC_KEY_FOOTER:String = "-----END PUBLIC KEY-----";
private static const CERTIFICATE_HEADER:String = "-----BEGIN CERTIFICATE-----";
private static const CERTIFICATE_FOOTER:String = "-----END CERTIFICATE-----";
/**
*
* Read a structure encoded according to
* ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
* section 11.1.2
*
* @param str
* @return
*
*/
public static function readRSAPrivateKey(str:String):RSAKey {
var der:ByteArray = extractBinary(RSA_PRIVATE_KEY_HEADER, RSA_PRIVATE_KEY_FOOTER, str);
if (der==null) return null;
var obj:* = DER.parse(der);
if (obj is Array) {
var arr:Array = obj as Array;
// arr[0] is Version. should be 0. should be checked. shoulda woulda coulda.
return new RSAKey(
arr[1], // N
arr[2].valueOf(), // E
arr[3], // D
arr[4], // P
arr[5], // Q
arr[6], // DMP1
arr[7], // DMQ1
arr[8]); // IQMP
} else {
// dunno
return null;
}
}
/**
* Read a structure encoded according to some spec somewhere
* Also, follows some chunk from
* ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
* section 11.1
*
* @param str
* @return
*
*/
public static function readRSAPublicKey(str:String):RSAKey {
var der:ByteArray = extractBinary(RSA_PUBLIC_KEY_HEADER, RSA_PUBLIC_KEY_FOOTER, str);
if (der==null) return null;
var obj:* = DER.parse(der);
if (obj is Array) {
var arr:Array = obj as Array;
// arr[0] = [ <some crap that means "rsaEncryption">, null ]; ( apparently, that's an X-509 Algorithm Identifier.
if (arr[0][0].toString()!=OID.RSA_ENCRYPTION) {
return null;
}
// arr[1] is a ByteArray begging to be parsed as DER
arr[1].position = 1; // there's a 0x00 byte up front. find out why later. like, read a spec.
obj = DER.parse(arr[1]);
if (obj is Array) {
arr = obj as Array;
// arr[0] = modulus
// arr[1] = public expt.
return new RSAKey(arr[0], arr[1]);
} else {
return null;
}
} else {
// dunno
return null;
}
}
public static function readCertIntoArray(str:String):ByteArray {
var tmp:ByteArray = extractBinary(CERTIFICATE_HEADER, CERTIFICATE_FOOTER, str);
return tmp;
}
private static function extractBinary(header:String, footer:String, str:String):ByteArray {
var i:int = str.indexOf(header);
if (i==-1) return null;
i += header.length;
var j:int = str.indexOf(footer);
if (j==-1) return null;
var b64:String = str.substring(i, j);
// remove whitesapces.
b64 = b64.replace(/\s/mg, '');
// decode
return Base64.decodeToByteArray(b64);
}
}
}
\ No newline at end of file
/**
* PrintableString
*
* An ASN1 type for a PrintableString, held within a String
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import flash.utils.ByteArray;
public class PrintableString implements IAsn1Type
{
protected var type:uint;
protected var len:uint;
protected var str:String;
public function PrintableString(type:uint, length:uint) {
this.type = type;
this.len = length;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
public function setString(s:String):void {
str = s;
}
public function getString():String {
return str;
}
public function toString():String {
return DER.indent+str;
}
public function toDER():ByteArray {
return null; // XXX not implemented
}
}
}
\ No newline at end of file
/**
* Sequence
*
* An ASN1 type for a Sequence, implemented as an Array
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import flash.utils.ByteArray;
public dynamic class Sequence extends Array implements IAsn1Type
{
protected var type:uint;
protected var len:uint;
public function Sequence(type:uint = 0x30, length:uint = 0x00) {
this.type = type;
this.len = length;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
public function toDER():ByteArray {
var tmp:ByteArray = new ByteArray;
for (var i:int=0;i<length;i++) {
var e:IAsn1Type = this[i];
if (e == null) { // XXX Arguably, I could have a der.Null class instead
tmp.writeByte(0x05);
tmp.writeByte(0x00);
} else {
tmp.writeBytes(e.toDER());
}
}
return DER.wrapDER(type, tmp);
}
public function toString():String {
var s:String = DER.indent;
DER.indent += " ";
var t:String = "";
for (var i:int=0;i<length;i++) {
if (this[i]==null) continue;
var found:Boolean = false;
for (var key:String in this) {
if ( (i.toString()!=key) && this[i]==this[key]) {
t += key+": "+this[i]+"\n";
found = true;
break;
}
}
if (!found) t+=this[i]+"\n";
}
// var t:String = join("\n");
DER.indent= s;
return DER.indent+"Sequence["+type+"]["+len+"][\n"+t+"\n"+s+"]";
}
/////////
public function findAttributeValue(oid:String):IAsn1Type {
for each (var set:* in this) {
if (set is Set) {
var child:* = set[0];
if (child is Sequence) {
var tmp:* = child[0];
if (tmp is ObjectIdentifier) {
var id:ObjectIdentifier = tmp as ObjectIdentifier;
if (id.toString()==oid) {
return child[1] as IAsn1Type;
}
}
}
}
}
return null;
}
}
}
\ No newline at end of file
/**
* Set
*
* An ASN1 type for an Set, that extends a Sequence
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
public dynamic class Set extends Sequence implements IAsn1Type
{
public function Set(type:uint = 0x31, length:uint = 0x00) {
super(type, length);
}
public override function toString():String {
var s:String = DER.indent;
DER.indent += " ";
var t:String = join("\n");
DER.indent= s;
return DER.indent+"Set["+type+"]["+len+"][\n"+t+"\n"+s+"]";
}
}
}
\ No newline at end of file
/**
* Type
*
* A few Asn-1 structures
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import com.hurlant.util.Hex;
public class Type
{
public static const TLS_CERT:Array = [
{name:"signedCertificate", extract:true, value: [
{name:"versionHolder", optional:true, value: [
{name:"version"}
], defaultValue: function():Sequence{
var s:Sequence = new Sequence(0, 0);
var v:Integer = new Integer(2,1, Hex.toArray("00"));
s.push(v);
s.version = v;
return s;
}()
},
{name:"serialNumber"},
{name:"signature", value: [
{name:"algorithmId"}
]},
{name:"issuer", extract:true, value: [
{name:"type"},
{name:"value"}
]},
{name:"validity", value: [
{name:"notBefore"},
{name:"notAfter"}
]},
{name:"subject", extract:true, value: [
]},
{name:"subjectPublicKeyInfo", value: [
{name:"algorithm", value: [
{name:"algorithmId"}
]},
{name:"subjectPublicKey"}
]},
{name:"extensions", value: [
]}
]},
{name:"algorithmIdentifier",value:[
{name:"algorithmId"}
]},
{name:"encrypted", value:null}
];
public static const CERTIFICATE:Array = [
{name:"tbsCertificate", value:[
{name:"tag0", value:[
{name:"version"}
]},
{name:"serialNumber"},
{name:"signature"},
{name:"issuer", value:[
{name:"type"},
{name:"value"}
]},
{name:"validity", value:[
{name:"notBefore"},
{name:"notAfter"}
]},
{name:"subject"},
{name:"subjectPublicKeyInfo", value:[
{name:"algorithm"},
{name:"subjectPublicKey"}
]},
{name:"issuerUniqueID"},
{name:"subjectUniqueID"},
{name:"extensions"}
]},
{name:"signatureAlgorithm"},
{name:"signatureValue"}
];
public static const RSA_PUBLIC_KEY:Array = [
{name:"modulus"},
{name:"publicExponent"}
];
public static const RSA_SIGNATURE:Array = [
{name:"algorithm", value:[
{name:"algorithmId"}
]},
{name:"hash"}
];
}
}
\ No newline at end of file
/**
* UTCTime
*
* An ASN1 type for UTCTime, represented as a Date
* Copyright (c) 2007 Henri Torgemane
*
* See LICENSE.txt for full license information.
*/
package com.hurlant.util.der
{
import flash.utils.ByteArray;
public class UTCTime implements IAsn1Type
{
protected var type:uint;
protected var len:uint;
public var date:Date;
public function UTCTime(type:uint, len:uint)
{
this.type = type;
this.len = len;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
public function setUTCTime(str:String):void {
var year:uint = parseInt(str.substr(0, 2));
if (year<50) {
year+=2000;
} else {
year+=1900;
}
var month:uint = parseInt(str.substr(2,2));
var day:uint = parseInt(str.substr(4,2));
var hour:uint = parseInt(str.substr(6,2));
var minute:uint = parseInt(str.substr(8,2));
// XXX this could be off by up to a day. parse the rest. someday.
date = new Date(year, month-1, day, hour, minute);
}
public function toString():String {
return DER.indent+"UTCTime["+type+"]["+len+"]["+date+"]";
}
public function toDER():ByteArray {
return null // XXX not implemented
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8" ?>
<application
xmlns="http://ns.adobe.com/air/application/1.0"
minimumPatchLevel="0">
<!-- AIR Application Descriptor File. See http://www.adobe.com/go/air_1.0_application_descriptor. -->
<id>com.Test</id>
<name>Test</name>
<version>1.0</version>
<filename>Test</filename>
<description>Test</description>
<copyright>(c) 2007</copyright>
<initialWindow>
<content>bin/Test.swf</content>
<title>Test</title>
<systemChrome>standard</systemChrome>
<transparent>false</transparent>
<visible>true</visible>
<minimizable>true</minimizable>
<maximizable>true</maximizable>
<resizable>true</resizable>
<width>1024</width>
<height>768</height>
<x>100</x>
<y>50</y>
<minSize>300 300</minSize>
<maxSize>800 800</maxSize>
</initialWindow>
<installFolder>Test</installFolder>
<programMenuFolder>Test</programMenuFolder>
<icon>
<!--
<image16x16>icons/AIRApp_16.png</image16x16>
<image32x32>icons/AIRApp_32.png</image32x32>
<image48x48>icons/AIRApp_48.png</image48x48>
<image128x128>icons/AIRApp_128.png</image128x128>
-->
</icon>
<customUpdateUI>false</customUpdateUI>
<allowBrowserInvocation>false</allowBrowserInvocation>
</application>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"
xmlns:flexunit="flexunit.flexui.*"
creationComplete="onCreationComplete()">
<mx:Script>
<![CDATA[
import flexunit.framework.TestSuite;
import suite.*;
// After everything is built, configure the test
// runner to use the appropriate test suite and
// kick off the unit tests
private function onCreationComplete():void {
testRunner.test = createSuite();
testRunner.startTest();
}
// Creates the test suite to run
private function createSuite():TestSuite {
var ts:TestSuite = new TestSuite();
// TODO: Add more tests here to test more classes
// by calling addTest as often as necessary
ts.addTest(new AllTests());
return ts;
}
]]>
</mx:Script>
<!-- flexunit provides a very handy default test runner GUI -->
<flexunit:TestRunnerBase id="testRunner" width="100%" height="100%" />
</mx:Application>
\ No newline at end of file
package suite {
import flexunit.framework.TestSuite;
public class AllTests extends TestSuite {
public function AllTests() {
super();
// Add tests here
// For examples, see: http://code.google.com/p/as3flexunitlib/wiki/Resources
//addTest(SomeTest.suite());
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment