no commit message

This commit is contained in:
niandeng
2020-09-17 18:40:01 +08:00
parent 4382915d09
commit d957abceaa
283 changed files with 86935 additions and 63 deletions
+134
View File
@@ -0,0 +1,134 @@
/**
Base64 - 1.1.0
Copyright (c) 2006 Steve Webster
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.hurlant.util {
import flash.utils.ByteArray;
public class Base64 {
private static const BASE64_CHARS:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
public static const version:String = "1.0.0";
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 encodeByteArray(data:ByteArray):String {
// Initialise output
var output:String = "";
// Create data and output buffers
var dataBuffer:Array;
var outputBuffer:Array = new Array(4);
// Rewind ByteArray
data.position = 0;
// while there are still bytes to be processed
while (data.bytesAvailable > 0) {
// Create new data buffer and populate next 3 bytes from data
dataBuffer = new Array();
for (var i:uint = 0; i < 3 && data.bytesAvailable > 0; i++) {
dataBuffer[i] = data.readUnsignedByte();
}
// Convert to data buffer Base64 character positions and
// store in output buffer
outputBuffer[0] = (dataBuffer[0] & 0xfc) >> 2;
outputBuffer[1] = ((dataBuffer[0] & 0x03) << 4) | ((dataBuffer[1]) >> 4);
outputBuffer[2] = ((dataBuffer[1] & 0x0f) << 2) | ((dataBuffer[2]) >> 6);
outputBuffer[3] = dataBuffer[2] & 0x3f;
// If data buffer was short (i.e not 3 characters) then set
// end character indexes in data buffer to index of '=' symbol.
// This is necessary because Base64 data is always a multiple of
// 4 bytes and is basses with '=' symbols.
for (var j:uint = dataBuffer.length; j < 3; j++) {
outputBuffer[j + 1] = 64;
}
// Loop through output buffer and add Base64 characters to
// encoded data string for each character.
for (var k:uint = 0; k < outputBuffer.length; k++) {
output += BASE64_CHARS.charAt(outputBuffer[k]);
}
}
// Return encoded data
return output;
}
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 decodeToByteArray(data:String):ByteArray {
// Initialise output ByteArray for decoded data
var output:ByteArray = new ByteArray();
// Create data and output buffers
var dataBuffer:Array = new Array(4);
var outputBuffer:Array = new Array(3);
// While there are data bytes left to be processed
for (var i:uint = 0; i < data.length; i += 4) {
// Populate data buffer with position of Base64 characters for
// next 4 bytes from encoded data
for (var j:uint = 0; j < 4 && i + j < data.length; j++) {
dataBuffer[j] = BASE64_CHARS.indexOf(data.charAt(i + j));
}
// Decode data buffer back into bytes
outputBuffer[0] = (dataBuffer[0] << 2) + ((dataBuffer[1] & 0x30) >> 4);
outputBuffer[1] = ((dataBuffer[1] & 0x0f) << 4) + ((dataBuffer[2] & 0x3c) >> 2);
outputBuffer[2] = ((dataBuffer[2] & 0x03) << 6) + dataBuffer[3];
// Add all non-padded bytes in output buffer to decoded data
for (var k:uint = 0; k < outputBuffer.length; k++) {
if (dataBuffer[k+1] == 64) break;
output.writeByte(outputBuffer[k]);
}
}
// Rewind decoded data ByteArray
output.position = 0;
// Return decoded data
return output;
}
public function Base64() {
throw new Error("Base64 class is static container only");
}
}
}
+66
View File
@@ -0,0 +1,66 @@
/**
* 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);
}
}
}
+19
View File
@@ -0,0 +1,19 @@
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;
}
}
}
+31
View File
@@ -0,0 +1,31 @@
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, length:uint) {
this.type = type;
this.len = length;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
override public function toString():String {
return DER.indent+"ByteString["+type+"]["+len+"]["+Hex.fromArray(this)+"]";
}
}
}
+110
View File
@@ -0,0 +1,110 @@
package com.hurlant.util.der
{
import com.hurlant.math.BigInteger;
import flash.utils.ByteArray;
import com.hurlant.util.der.Sequence;
// 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 {
// 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;
while (der.position < p+len) {
var tmpStruct:Object = null
if (arrayStruct!=null) {
tmpStruct = arrayStruct.shift();
}
if (tmpStruct!=null) {
var name:String = tmpStruct.name;
var value:* = tmpStruct.value;
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 0x04: // OCTET STRING
case 0x03: // BIT 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 0x14: // T61String
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;
}
}
}
}
+9
View File
@@ -0,0 +1,9 @@
package com.hurlant.util.der
{
public interface IAsn1Type
{
function getType():uint;
function getLength():uint;
}
}
+32
View File
@@ -0,0 +1,32 @@
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)+"]";
}
}
}
+24
View File
@@ -0,0 +1,24 @@
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 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 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";
}
}
@@ -0,0 +1,57 @@
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:ByteArray) {
this.type = type;
this.len = length;
parse(b);
}
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 toString():String {
return DER.indent+oid.join(".");
}
public function dump():String {
return "OID["+type+"]["+len+"]["+toString()+"]";
}
}
}
+108
View File
@@ -0,0 +1,108 @@
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;
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 OID_RSA_ENCRYPTION:String = "1.2.840.113549.1.1.1";
/**
*
* 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 {
// 1. we expect a "-----BEGIN RSA PRIVATE KEY-----"
var i:int = str.indexOf(RSA_PRIVATE_KEY_HEADER);
if (i==-1) return null;
i += RSA_PRIVATE_KEY_HEADER.length;
var j:int = str.indexOf(RSA_PRIVATE_KEY_FOOTER);
if (j==-1) return null;
var b64:String = str.substring(i, j);
// remove any whitespace characters from the string
var space:RegExp= /\s/mg;
b64 = b64.replace(space,'');
// decode
var der:ByteArray = Base64.decodeToByteArray(b64);
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 i:int = str.indexOf(RSA_PUBLIC_KEY_HEADER);
if (i==-1) return null;
i += RSA_PUBLIC_KEY_HEADER.length;
var j:int = str.indexOf(RSA_PUBLIC_KEY_FOOTER);
if (j==-1) return null;
var b64:String = str.substring(i, j);
// remove whitesapces.
b64 = b64.replace(/\s/mg, '');
// decode
var der:ByteArray = Base64.decodeToByteArray(b64);
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;
}
}
}
}
@@ -0,0 +1,36 @@
package com.hurlant.util.der
{
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;
}
}
}
+52
View File
@@ -0,0 +1,52 @@
package com.hurlant.util.der
{
public dynamic class Sequence extends Array implements IAsn1Type
{
protected var type:uint;
protected var len:uint;
public function Sequence(type:uint, length:uint) {
this.type = type;
this.len = length;
}
public function getLength():uint
{
return len;
}
public function getType():uint
{
return type;
}
public function toString():String {
var s:String = DER.indent;
DER.indent += " ";
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;
}
}
}
+19
View File
@@ -0,0 +1,19 @@
package com.hurlant.util.der
{
public dynamic class Set extends Sequence implements IAsn1Type
{
public function Set(type:uint, length:uint) {
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+"]";
}
}
}
+39
View File
@@ -0,0 +1,39 @@
package com.hurlant.util.der
{
public class Type
{
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"}
];
}
}
+40
View File
@@ -0,0 +1,40 @@
package com.hurlant.util.der
{
public class UTCTime implements IAsn1Type
{
protected var type:uint;
protected var len:uint;
protected 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 = 2000 + parseInt(str.substr(0, 2)); // Y2.1K unsafe!@!!
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 a day. parse the rest. someday.
date = new Date(year, month, day, hour, minute);
}
public function toString():String {
return DER.indent+"UTCTime["+type+"]["+len+"]["+date+"]";
}
}
}