6using System.Text.RegularExpressions;
41 private MemoryStream output =
new MemoryStream();
42 private LinkedList<KeyValuePair<byte, MemoryStream>> stack =
null;
56 this.output?.Dispose();
65 this.output.Position = 0;
66 this.output.SetLength(0);
75 if (!(this.stack is
null) && !(this.stack.First is
null))
76 throw new Exception(
"DER output not properly closed.");
78 return this.output.ToArray();
87 this.output.WriteByte(1);
88 this.output.WriteByte(1);
91 this.output.WriteByte(0xff);
93 this.output.WriteByte(0x00);
102 this.output.WriteByte(2);
104 int Pos = (int)this.output.Position;
108 this.output.WriteByte(0);
114 b = (byte)(Value >> 56);
121 this.output.WriteByte(0xff);
123 this.output.WriteByte(b);
127 b = (byte)(Value >> 56);
128 this.output.WriteByte(b);
133 this.output.WriteByte(0);
138 b = (byte)(Value >> 56);
145 this.output.WriteByte(0);
147 this.output.WriteByte(b);
151 b = (byte)(Value >> 56);
152 this.output.WriteByte(b);
157 this[Pos] = (byte)(this.output.Position - Pos - 1);
165 public void INTEGER(
byte[] Value,
bool Negative)
167 this.output.WriteByte(2);
171 if (Value is
null || Value.Length == 0)
172 Value =
new byte[] { 0xff };
173 else if (Value[0] < 0x80)
175 int c = Value.Length;
176 byte[] Value2 =
new byte[c + 1];
178 Buffer.BlockCopy(Value, 0, Value2, 1, Value.Length);
184 if (Value is
null || Value.Length == 0)
185 Value =
new byte[] { 0 };
186 else if (Value[0] >= 0x80)
188 int c = Value.Length;
189 byte[] Value2 =
new byte[c + 1];
191 Buffer.BlockCopy(Value, 0, Value2, 1, Value.Length);
196 this.EncodeBinary(Value);
199 private void EncodeBinary(
byte[] Bin)
201 int Len = Bin.Length;
206 this.output.WriteByte(0x81);
210 this.output.WriteByte(0x82);
214 this.output.WriteByte(0x83);
217 this.output.WriteByte(0x84);
218 this.output.WriteByte((
byte)(Len >> 24));
221 this.output.WriteByte((
byte)(Len >> 16));
224 this.output.WriteByte((
byte)(Len >> 8));
228 this.output.WriteByte((
byte)Len);
229 this.output.Write(Bin, 0, Bin.Length);
238 this.output.WriteByte(3);
240 int NrBits = Bits.Length;
241 int Len = (NrBits + 7) / 8 + 1;
242 int NrUnusedBits = 8 - (NrBits & 7);
243 byte[] Bin =
new byte[Len];
247 if (NrUnusedBits == 8)
250 Bin[j++] = (byte)NrUnusedBits;
252 for (i = 0; i < NrBits; i++)
262 if (NrUnusedBits > 0)
268 this.EncodeBinary(Bin);
278 this.output.WriteByte(3);
280 int c = Bytes.Length;
281 byte[] Bytes2 =
new byte[c + 1];
283 Buffer.BlockCopy(Bytes, 0, Bytes2, 1, c);
285 this.EncodeBinary(Bytes2);
294 this.output.WriteByte(0);
311 this.output.WriteByte(4);
312 this.EncodeBinary(Value);
336 this.output.WriteByte(5);
337 this.output.WriteByte(0);
346 string[] s = OID.Split(
'.');
348 uint[] OID2 =
new uint[c];
350 for (i = 0; i < c; i++)
352 if (!uint.TryParse(s[i], out OID2[i]))
353 throw new ArgumentException(
"Invalid object identifier.", nameof(OID));
365 int i, c = OID.Length;
369 throw new ArgumentException(
"Invalid length of OID.", nameof(OID));
372 throw new ArgumentException(
"Invalid second integer in OID.", nameof(OID));
375 if (j > 255 || j + OID[1] > 255)
376 throw new ArgumentException(
"Invalid first integer in OID.", nameof(OID));
380 using (MemoryStream Bin =
new MemoryStream())
382 Bin.WriteByte((
byte)j);
384 for (i = 2; i < c; i++)
389 Bin.WriteByte((
byte)(128 + (j >> 28)));
392 Bin.WriteByte((
byte)(128 + (j >> 21)));
395 Bin.WriteByte((
byte)(128 + (j >> 14)));
398 Bin.WriteByte((
byte)(128 + (j >> 7)));
400 Bin.WriteByte((
byte)(j & 127));
403 this.output.WriteByte(6);
404 this.EncodeBinary(Bin.ToArray());
414 this.output.WriteByte(0x1e);
415 this.EncodeBinary(Encoding.BigEndianUnicode.GetBytes(Value));
424 this.output.WriteByte(0x16);
425 this.EncodeBinary(Encoding.ASCII.GetBytes(Value));
435 throw new ArgumentException(
"Not a printable string.", nameof(Value));
437 this.output.WriteByte(0x13);
438 this.EncodeBinary(Encoding.ASCII.GetBytes(Value));
448 return PrintableString.IsMatch(Value);
451 private static readonly Regex PrintableString =
new Regex(
"^[A-Za-z0-9 '()+,-./:=?]*$", RegexOptions.Singleline | RegexOptions.Compiled);
459 this.output.WriteByte(0x0c);
460 this.EncodeBinary(Encoding.UTF8.GetBytes(Value));
471 private void Start(
byte Expected)
473 if (this.stack is
null)
474 this.stack =
new LinkedList<KeyValuePair<byte, MemoryStream>>();
476 this.stack.AddLast(
new KeyValuePair<byte, MemoryStream>(Expected, this.output));
478 this.output =
new MemoryStream();
489 private void End(
byte Type)
491 if (this.stack is
null || this.stack.Last is
null)
492 throw new Exception(
"Not properly started.");
494 if (Type != this.stack.Last.Value.Key)
495 throw new Exception(
"Start/End type mismatch.");
497 byte[] Bin = this.output.ToArray();
498 this.output.Dispose();
500 this.output = this.stack.Last.Value.Value;
501 this.stack.RemoveLast();
503 this.output.WriteByte(Type);
504 this.EncodeBinary(Bin);
529 this.output.WriteByte((
byte)((((
int)Class) << 6) | 0x20));
530 this.output.WriteByte(0);
539 this.Start((
byte)((((
int)Class) << 6) | 0x20));
548 this.End((
byte)((((
int)Class) << 6) | 0x20));
555 public void Raw(
byte[] DerEncodedBytes)
557 this.output.Write(DerEncodedBytes, 0, DerEncodedBytes.Length);
565 get {
return (
int)this.output.Position; }
573 public byte this[
int Index]
577 long PosBak = this.output.Position;
580 this.output.Position = Index;
581 Result = (byte)this.output.ReadByte();
582 this.output.Position = PosBak;
589 long PosBak = this.output.Position;
591 this.output.Position = Index;
592 this.output.WriteByte(value);
593 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.