2using System.Collections;
3using System.Collections.Generic;
6using System.Text.RegularExpressions;
41 private MemoryStream output =
new MemoryStream();
42 private LinkedList<KeyValuePair<byte, MemoryStream>> stack =
null;
56 throw new NotImplementedException();
64 this.output.Position = 0;
65 this.output.SetLength(0);
74 if (!(this.stack is
null) && !(this.stack.First is
null))
75 throw new Exception(
"DER output not properly closed.");
77 return this.output.ToArray();
86 this.output.WriteByte(1);
87 this.output.WriteByte(1);
90 this.output.WriteByte(0xff);
92 this.output.WriteByte(0x00);
101 this.output.WriteByte(2);
103 int Pos = (int)this.output.Position;
107 this.output.WriteByte(0);
113 b = (byte)(Value >> 56);
120 this.output.WriteByte(0xff);
122 this.output.WriteByte(b);
126 b = (byte)(Value >> 56);
127 this.output.WriteByte(b);
132 this.output.WriteByte(0);
137 b = (byte)(Value >> 56);
144 this.output.WriteByte(0);
146 this.output.WriteByte(b);
150 b = (byte)(Value >> 56);
151 this.output.WriteByte(b);
156 this[Pos] = (byte)(this.output.Position - Pos - 1);
164 public void INTEGER(
byte[] Value,
bool Negative)
166 this.output.WriteByte(2);
170 if (Value is
null || Value.Length == 0)
171 Value =
new byte[] { 0xff };
172 else if (Value[0] < 0x80)
174 int c = Value.Length;
175 byte[] Value2 =
new byte[c + 1];
177 Array.Copy(Value, 0, Value2, 1, Value.Length);
183 if (Value is
null || Value.Length == 0)
184 Value =
new byte[] { 0 };
185 else if (Value[0] >= 0x80)
187 int c = Value.Length;
188 byte[] Value2 =
new byte[c + 1];
190 Array.Copy(Value, 0, Value2, 1, Value.Length);
195 this.EncodeBinary(Value);
198 private void EncodeBinary(
byte[] Bin)
200 int Len = Bin.Length;
205 this.output.WriteByte(0x81);
209 this.output.WriteByte(0x82);
213 this.output.WriteByte(0x83);
216 this.output.WriteByte(0x84);
217 this.output.WriteByte((
byte)(Len >> 24));
220 this.output.WriteByte((
byte)(Len >> 16));
223 this.output.WriteByte((
byte)(Len >> 8));
227 this.output.WriteByte((
byte)Len);
228 this.output.Write(Bin, 0, Bin.Length);
237 this.output.WriteByte(3);
239 int NrBits = Bits.Length;
240 int Len = (NrBits + 7) / 8 + 1;
241 int NrUnusedBits = 8 - (NrBits & 7);
242 byte[] Bin =
new byte[Len];
246 if (NrUnusedBits == 8)
249 Bin[j++] = (byte)NrUnusedBits;
251 for (i = 0; i < NrBits; i++)
261 if (NrUnusedBits > 0)
267 this.EncodeBinary(Bin);
277 this.output.WriteByte(3);
279 int c = Bytes.Length;
280 byte[] Bytes2 =
new byte[c + 1];
282 Array.Copy(Bytes, 0, Bytes2, 1, c);
284 this.EncodeBinary(Bytes2);
293 this.output.WriteByte(0);
310 this.output.WriteByte(4);
311 this.EncodeBinary(Value);
335 this.output.WriteByte(5);
336 this.output.WriteByte(0);
345 string[] s = OID.Split(
'.');
347 uint[] OID2 =
new uint[c];
349 for (i = 0; i < c; i++)
351 if (!uint.TryParse(s[i], out OID2[i]))
352 throw new ArgumentException(
"Invalid object identifier.", nameof(OID));
364 int i, c = OID.Length;
368 throw new ArgumentException(
"Invalid length of OID.", nameof(OID));
371 throw new ArgumentException(
"Invalid second integer in OID.", nameof(OID));
374 if (j > 255 || j + OID[1] > 255)
375 throw new ArgumentException(
"Invalid first integer in OID.", nameof(OID));
379 using (MemoryStream Bin =
new MemoryStream())
381 Bin.WriteByte((
byte)j);
383 for (i = 2; i < c; i++)
388 Bin.WriteByte((
byte)(128 + (j >> 28)));
391 Bin.WriteByte((
byte)(128 + (j >> 21)));
394 Bin.WriteByte((
byte)(128 + (j >> 14)));
397 Bin.WriteByte((
byte)(128 + (j >> 7)));
399 Bin.WriteByte((
byte)(j & 127));
402 this.output.WriteByte(6);
403 this.EncodeBinary(Bin.ToArray());
413 this.output.WriteByte(0x1e);
414 this.EncodeBinary(Encoding.BigEndianUnicode.GetBytes(Value));
423 this.output.WriteByte(0x16);
424 this.EncodeBinary(Encoding.ASCII.GetBytes(Value));
434 throw new ArgumentException(
"Not a printable string.", nameof(Value));
436 this.output.WriteByte(0x13);
437 this.EncodeBinary(Encoding.ASCII.GetBytes(Value));
447 return PrintableString.IsMatch(Value);
450 private static readonly Regex PrintableString =
new Regex(
"^[A-Za-z0-9 '()+,-./:=?]*$", RegexOptions.Singleline | RegexOptions.Compiled);
458 this.output.WriteByte(0x0c);
459 this.EncodeBinary(Encoding.UTF8.GetBytes(Value));
470 private void Start(
byte Expected)
472 if (this.stack is
null)
473 this.stack =
new LinkedList<KeyValuePair<byte, MemoryStream>>();
475 this.stack.AddLast(
new KeyValuePair<byte, MemoryStream>(Expected, this.output));
477 this.output =
new MemoryStream();
488 private void End(
byte Type)
490 if (this.stack is
null || this.stack.Last is
null)
491 throw new Exception(
"Not properly started.");
493 if (Type != this.stack.Last.Value.Key)
494 throw new Exception(
"Start/End type mismatch.");
496 byte[] Bin = this.output.ToArray();
497 this.output.Dispose();
499 this.output = this.stack.Last.Value.Value;
500 this.stack.RemoveLast();
502 this.output.WriteByte(Type);
503 this.EncodeBinary(Bin);
528 this.output.WriteByte((
byte)((((
int)Class) << 6) | 0x20));
529 this.output.WriteByte(0);
538 this.Start((
byte)((((
int)Class) << 6) | 0x20));
547 this.End((
byte)((((
int)Class) << 6) | 0x20));
554 public void Raw(
byte[] DerEncodedBytes)
556 this.output.Write(DerEncodedBytes, 0, DerEncodedBytes.Length);
564 get {
return (
int)this.output.Position; }
572 public byte this[
int Index]
576 long PosBak = this.output.Position;
579 this.output.Position = Index;
580 Result = (byte)this.output.ReadByte();
581 this.output.Position = PosBak;
588 long PosBak = this.output.Position;
590 this.output.Position = Index;
591 this.output.WriteByte(value);
592 this.output.Position = PosBak;
Encodes data using the Distinguished Encoding Rules (DER), as defined in X.690
void Raw(byte[] DerEncodedBytes)
Adds DER-encoded bytes to the output.
byte[] ToArray()
Converts the generated output to a byte arary.
void Clear()
Clears the output buffer.
void Content(Asn1TypeClass Class)
Encodes content to the output.
void EndSET()
Ends the current SET.
void StartOCTET_STRING()
Starts a OCTET_STRING.
void StartBITSTRING()
Starts a BITSTRING.
void Dispose()
IDisposable.Dispose
void EndSEQUENCE()
Ends the current SEQUENCE.
void INTEGER(byte[] Value, bool Negative)
Encodes an INTEGER value.
void BITSTRING(byte[] Bytes)
Encodes an BITSTRING value.
void EndContent(Asn1TypeClass Class)
Ends the current Content section.
DerEncoder()
Encodes data using the Distinguished Encoding Rules (DER), as defined in X.690
void UNICODE_STRING(string Value)
Encodes a UNICODE STRING (BMPString) value.
static bool IsPrintable(string Value)
Checks if a string is a printable string.
void OBJECT_IDENTIFIER(string OID)
Encodes an OBJECT IDENTIFIER value.
void NULL()
Encodes an NULL value.
void BOOLEAN(bool Value)
Encodes an BOOLEAN value.
void EndOCTET_STRING()
Ends the current OCTET_STRING.
void IA5_STRING(string Value)
Encodes an IA5 STRING value.
void BITSTRING(BitArray Bits)
Encodes an BITSTRING value.
void OBJECT_IDENTIFIER(uint[] OID)
Encodes an OBJECT IDENTIFIER value.
void StartContent(Asn1TypeClass Class)
Starts a content section.
void UTF8_STRING(string Value)
Encodes an UTF-8 STRING value.
int Position
Current output position.
void INTEGER(long Value)
Encodes an INTEGER value.
void EndBITSTRING()
Ends the current BITSTRING.
void PRINTABLE_STRING(string Value)
Encodes an PRINTABLE STRING value.
void StartSET()
Starts a SET.
void StartSEQUENCE()
Starts a SEQUENCE.
void OCTET_STRING(byte[] Value)
Encodes an OCTET STRING value.