📄 ber.cs
字号:
using System;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Text;
// ASN.1 BER encoding library by Malcolm Crowe at the University of Paisley
// See http://cis.paisley.ac.uk/crow-ci0
// This is version 0 of the library, please advise me about any bugs
// mailto:malcolm.crowe@paisley.ac.uk
// Restrictions: It is assumed that no encoding has a length greater than 2^31-1.
// UNIVERSAL TYPES
// Some of the more unusual Universal encodings are supported but not fully implemented
// Should you require these types, as an alternative to changing this code
// you can catch the exception that is thrown and examine the contents yourself.
// APPLICATION TYPES
// If you want to handle Application types systematically, you can derive a class from
// Universal, and provide the Creator and Creators methods for your class
// You will see an example of how to do this in the Snmplib
// CONTEXT AND PRIVATE TYPES
// Ad hoc coding can be used for these, as an alterative to derive a class as above.
namespace X690 // all references here are to ITU-X.690-12/97
{
public class Integer // This namespace has its own concept of Integer
{
public byte[] octVal = null;
public Integer(byte[] b)
{
octVal = b;
}
public Integer(int iVal)
{
if (iVal>=-127 && iVal<=127)
{
octVal = new byte[1];
octVal[0] = (byte)iVal;
}
else
{
ArrayList v = new ArrayList();
int n = iVal;
while (n!=0 && n!=-1)
{
v.Add((byte)(n&0xff));
n >>= 8;
}
octVal = new byte[v.Count];
int len = 0;
for (int j=v.Count-1;j>=0;j--)
octVal[len++] = (byte)v[j];
}
}
public Integer(long i64Val)
{
if (i64Val>=-127 && i64Val<=127)
{
octVal = new byte[1];
octVal[0] = (byte)i64Val;
}
else
{
ArrayList v = new ArrayList();
System.Int64 n = i64Val;
while (n!=0 && n!=-1)
{
v.Add((byte)(n&0xff));
n >>= 8;
}
octVal = new byte[v.Count];
int len = 0;
for (int j=v.Count-1;j>=0;j--)
octVal[len++] = (byte)v[j];
}
}
static public implicit operator int(Integer x)
{
if (x.octVal.Length>4)
throw(new Exception("truncation error for 32-bit integer coding"));
int iVal = 0;
for (int j=0;j<x.octVal.Length;j++)
iVal = (iVal<<8)|(int)x.octVal[j];
return iVal;
}
static public implicit operator long(Integer x)
{
if (x.octVal.Length>8)
throw(new Exception("truncation error for 64-bit integer coding"));
long i64Val = 0;
for (int j=0;j<x.octVal.Length;j++)
i64Val = (i64Val<<8)|(int)x.octVal[j];
return i64Val;
}
}
public class Real
{
public byte[] octVal = null;
public Real(byte[] b)
{
octVal = b;
}
public Real(double b)
{
if (b==0.0)
{
octVal = new byte[0];
return;
}
string s = b.ToString("E"); // hope this is acceptable..
octVal = new byte[s.Length+1];
octVal[0] = 0x0;
new ASCIIEncoding().GetBytes(s,0,s.Length,octVal,1);
}
static public implicit operator double(Real x)
{
if (x.octVal.Length==0)
return 0.0;
if ((x.octVal[0]&0x80)!=0) // 8.5.5 binary encoding
{
byte c = x.octVal[0];
int s = ((c&0x40)!=0)?-1:1;
int t = c&0x30;
int b = (t==0)?2:(t==1)?8:16;
if (t==3)
throw(new Exception("X690:8.5.5.2 reserved encoding"));
int f = (c&0xc)>>2;
f = 1<<f;
int p = 1;
long e = 0;
switch (c&0x3)
{
case 0: e = x.octVal[p++]; break;
case 1: e = ((int)x.octVal[p++])<<8; e+= x.octVal[p++]; break;
case 2: e = ((int)x.octVal[p++])<<16;
e += ((int)x.octVal[p++])<<8; e+= x.octVal[p++]; break;
case 3: int h = x.octVal[p++];
byte[] g = new byte[h];
for (int j=0;j<h;j++)
g[j]=x.octVal[p++];
e = new Integer(g);
break;
}
byte[] m = new byte[x.octVal.Length-p+1];
for (int k=0;p<x.octVal.Length;k++,p++)
m[k]=x.octVal[p];
long n = new Integer(m);
return ((double)(s*n*f))*Math.Pow((double)b,(double)e);
}
else if ((x.octVal[0]&0x40)==0) // 8.5.6 decimal encoding
return double.Parse(new ASCIIEncoding().GetString(x.octVal,0,x.octVal.Length));
else // 8.5.7 special real encoding
switch (x.octVal[0])
{
case 0x40: return double.PositiveInfinity;
case 0x41: return double.NegativeInfinity;
default: throw(new Exception("X690:8.5.7 reserved encoding"));
}
}
}
public abstract class BER
{
// internal representation of the encoding
public BERtag type; // BERtag class does encoding/decoding
protected uint len; // GetUInt/PutUInt for external representation
protected object val = null;
// safety field
protected bool e; // encode if true, decode if false
// external representation of the contents octets
protected byte[] b;
public bool Encode { get { return e; }}
protected byte ReadByte(Stream s)
{
int n = s.ReadByte();
if (n==-1)
throw(new Exception("BER end of file"));
return (byte)n;
}
protected void WriteByte(Stream s,byte b)
{
s.WriteByte(b);
}
}
public enum BERtype // 8.1.2.2
{
Universal=0, Application=1, Context=2, Private=3
}
public enum UniversalType
{
EndMarker = 0x00,
Boolean = 0x01,
Integer=0x02, // X690.Integer
BitString=0x03, // BitSet
OctetString=0x04, // string
Null=0x05,
ObjectIdentifier=0x06, // uint[]
ObjectDescriptor=0x7,
ExternalInstance=0x8,
Real=0x9, // X690.Real
Enumerated=0xa,
EmbeddedPDV=0xb,
UTF8String=0xc,
RelativeOID=0xd,
Reserved1=0xe,
Reserved2=0xf,
Sequence=0x10,
Set=0x11,
NumericString=0x12,
PrintableString=0x13,
T61String=0x14,
VideoTextString=0x15,
IA5String=0x16,
UTCTime=0x17,
GeneralizedTime=0x18,
GrahicString=0x19,
VisibleString=0x1a,
GeneralString=0x1b,
UniversalString=0x1c,
CharacterString=0x1d,
BMPString=0x1e
}
public class BERtag : BER
{
// Internal representation of Identifier octets 8.1.2.3
public BERtype atp;
public bool comp;
public ulong tag;
public BERtag() { atp=BERtype.Universal; comp=false; tag=0; } // EndMarker
public BERtag(BERtype a,bool c, ulong t) { atp=a; comp=c; tag=t; }
public BERtag(UniversalType b) : this((byte)b) {}
public BERtag(byte b)
{
// decoding 8.1.2.4.3 for small tag values
atp = (BERtype)(((uint)b&0xc0)>>6);
comp = ((b&0x20)!=0);
tag = (ulong)(b&0x1f);
if (tag==0x1f)
throw(new Exception("BER bad byte tag"));
}
public BERtag(Stream s)
{
// decoding 8.1.2.4.3
byte b = ReadByte(s);
atp = (BERtype)((b&0xc0)>>6);
comp = ((b&0x20)!=0);
tag = (ulong)(b&0x1f);
if ((b&0x1f)==0x1f)
tag = GetBigTag(s);
}
public void Send(Stream s)
{
// encoding 8.1.2.4.3
byte b = (byte)(((uint)atp)<<6 | (comp?0x20:0));
if (tag<31)
{
b |= (byte)tag;
s.WriteByte(b);
return;
}
b |=31;
s.WriteByte(b);
PutBigTag(s,tag);
}
public byte ToByte()
{
byte b = (byte)(((uint)atp<<6) | (comp?0x20:0));
if (tag>=31)
throw(new Exception("BERtag out of range for convert to byte"));
b |= (byte)tag;
return b;
}
public bool isEndMarker
{
get { return (atp==BERtype.Universal && !comp && tag==0); }
}
public ulong GetBigTag(Stream s)
{
ulong r = 0;
byte x = ReadByte(s);
do
{
r = (r<<7)+(ulong)(x&0x7f);
} while ((x&0x80)!=0);
return r;
}
public void PutBigTag(Stream s,ulong n)
{
byte[] c = new byte[16];
int j=0;
while (n>0)
{
c[j++] = (byte)(n&0x7f);
n = n>>7;
}
while (j>0)
{
byte x = c[--j];
if (j>0)
x |= 0x80;
WriteByte(s,x);
}
}
public ulong ExtLength() // calculate length required for identifier octets
{
if (tag<31)
return 1;
ulong a = tag;
ulong j = 1;
while (a>0)
{
j++;
a = a>>7;
}
return j;
}
public override string ToString()
{
if (atp==BERtype.Universal && !comp)
return ((UniversalType)tag).ToString().ToUpper();
return "[" + atp.ToString().ToUpper()+" "+(comp?"SEQUENCE ":"")+tag+"]";
}
}
// The following class provides for the Universal encodings and the encodings needed for SNMP
// For application or context-specific encodings, derive a class from this and override the
// Evaluate method, which creates an object called val based on the contents in byte[] b.
// Evaluate takes a single uint parameter which is the number of bytes to use in b.
public class Universal : BER
{
// override these two functions in any subclass of Universal so that SEQUENCES work correctly
protected virtual BERtag CreateTag(Stream s) { return new BERtag(s); }
protected virtual Universal Creator(Stream s) { return new Universal(s); }
protected virtual Universal[] Creators(int n) { return new Universal[n]; }
protected Universal() {}
public static Universal Null
{
get
{
return new Universal(new BERtag(UniversalType.Null),new Universal[0]);
}
}
public Universal(bool x) // 8.2
{
type = new BERtag(UniversalType.Boolean);
e = true;
len = 1;
b = new byte[1];
b[0] = (byte)(x?0xff:0);
}
public Universal(int n) // 8.3
{
type = new BERtag(UniversalType.Integer);
e = true;
b = new Integer(n).octVal;
len = (uint)b.Length;
}
public Universal(double d)
{
type = new BERtag(UniversalType.Real);
e = true;
b = new Real(d).octVal;
len = (uint)b.Length;
}
public Universal(BitSet a)
{
// encoding 8.6.2
type = new BERtag(UniversalType.BitString);
e = true;
int n = (a.Length+7)/8;
byte r = (byte)(8-a.Length%8);
b = new byte[n+1];
len = 0;
b[len++] = r;
int k = 24;
int i = 0;
for (int j=0;j<n;j++)
{
b[len++] = (byte)(a.bits[i]>>k);
k -= 8;
if (k<0)
{
i++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -