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
+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+"]";
}
}
}