Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
DerEncoder.cs
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.IO;
5using System.Text;
6using System.Text.RegularExpressions;
7
9{
13 public enum Asn1TypeClass
14 {
18 Universal = 0,
19
23 Application = 1,
24
28 ContextSpecific = 2,
29
33 Private = 3
34 }
35
39 public class DerEncoder : IDisposable
40 {
41 private MemoryStream output = new MemoryStream();
42 private LinkedList<KeyValuePair<byte, MemoryStream>> stack = null;
43
47 public DerEncoder()
48 {
49 }
50
54 public void Dispose()
55 {
56 throw new NotImplementedException();
57 }
58
62 public void Clear()
63 {
64 this.output.Position = 0;
65 this.output.SetLength(0);
66 }
67
72 public byte[] ToArray()
73 {
74 if (!(this.stack is null) && !(this.stack.First is null))
75 throw new Exception("DER output not properly closed.");
76
77 return this.output.ToArray();
78 }
79
84 public void BOOLEAN(bool Value)
85 {
86 this.output.WriteByte(1);
87 this.output.WriteByte(1);
88
89 if (Value)
90 this.output.WriteByte(0xff);
91 else
92 this.output.WriteByte(0x00);
93 }
94
99 public void INTEGER(long Value)
100 {
101 this.output.WriteByte(2);
102
103 int Pos = (int)this.output.Position;
104 int c = 8;
105 byte b;
106
107 this.output.WriteByte(0);
108
109 if (Value < 0)
110 {
111 do
112 {
113 b = (byte)(Value >> 56);
114 Value <<= 8;
115 c--;
116 }
117 while (b == 0xff);
118
119 if (b < 0x80)
120 this.output.WriteByte(0xff);
121
122 this.output.WriteByte(b);
123
124 while (c-- > 0)
125 {
126 b = (byte)(Value >> 56);
127 this.output.WriteByte(b);
128 Value <<= 8;
129 }
130 }
131 else if (Value == 0)
132 this.output.WriteByte(0);
133 else
134 {
135 do
136 {
137 b = (byte)(Value >> 56);
138 Value <<= 8;
139 c--;
140 }
141 while (b == 0);
142
143 if (b >= 0x80)
144 this.output.WriteByte(0);
145
146 this.output.WriteByte(b);
147
148 while (c-- > 0)
149 {
150 b = (byte)(Value >> 56);
151 this.output.WriteByte(b);
152 Value <<= 8;
153 }
154 }
155
156 this[Pos] = (byte)(this.output.Position - Pos - 1);
157 }
158
164 public void INTEGER(byte[] Value, bool Negative)
165 {
166 this.output.WriteByte(2);
167
168 if (Negative)
169 {
170 if (Value is null || Value.Length == 0)
171 Value = new byte[] { 0xff };
172 else if (Value[0] < 0x80)
173 {
174 int c = Value.Length;
175 byte[] Value2 = new byte[c + 1];
176 Value2[0] = 0xff;
177 Array.Copy(Value, 0, Value2, 1, Value.Length);
178 Value = Value2;
179 }
180 }
181 else
182 {
183 if (Value is null || Value.Length == 0)
184 Value = new byte[] { 0 };
185 else if (Value[0] >= 0x80)
186 {
187 int c = Value.Length;
188 byte[] Value2 = new byte[c + 1];
189 Value2[0] = 0;
190 Array.Copy(Value, 0, Value2, 1, Value.Length);
191 Value = Value2;
192 }
193 }
194
195 this.EncodeBinary(Value);
196 }
197
198 private void EncodeBinary(byte[] Bin)
199 {
200 int Len = Bin.Length;
201
202 if (Len >= 0x80)
203 {
204 if (Len <= 0xff)
205 this.output.WriteByte(0x81);
206 else
207 {
208 if (Len <= 0xffff)
209 this.output.WriteByte(0x82);
210 else
211 {
212 if (Len <= 0xffffff)
213 this.output.WriteByte(0x83);
214 else
215 {
216 this.output.WriteByte(0x84);
217 this.output.WriteByte((byte)(Len >> 24));
218 }
219
220 this.output.WriteByte((byte)(Len >> 16));
221 }
222
223 this.output.WriteByte((byte)(Len >> 8));
224 }
225 }
226
227 this.output.WriteByte((byte)Len);
228 this.output.Write(Bin, 0, Bin.Length);
229 }
230
235 public void BITSTRING(BitArray Bits)
236 {
237 this.output.WriteByte(3);
238
239 int NrBits = Bits.Length;
240 int Len = (NrBits + 7) / 8 + 1;
241 int NrUnusedBits = 8 - (NrBits & 7);
242 byte[] Bin = new byte[Len];
243 byte b = 0;
244 int i, j = 0;
245
246 if (NrUnusedBits == 8)
247 NrUnusedBits = 0;
248
249 Bin[j++] = (byte)NrUnusedBits;
250
251 for (i = 0; i < NrBits; i++)
252 {
253 b <<= 1;
254 if (Bits[i])
255 b |= 1;
256
257 if ((i & 7) == 7)
258 Bin[j++] = b;
259 }
260
261 if (NrUnusedBits > 0)
262 {
263 b <<= NrUnusedBits;
264 Bin[j++] = b;
265 }
266
267 this.EncodeBinary(Bin);
268 }
269
270
275 public void BITSTRING(byte[] Bytes)
276 {
277 this.output.WriteByte(3);
278
279 int c = Bytes.Length;
280 byte[] Bytes2 = new byte[c + 1];
281 Bytes2[0] = 0; // Unused bits.
282 Array.Copy(Bytes, 0, Bytes2, 1, c);
283
284 this.EncodeBinary(Bytes2);
285 }
286
290 public void StartBITSTRING()
291 {
292 this.Start(3);
293 this.output.WriteByte(0);
294 }
295
299 public void EndBITSTRING()
300 {
301 this.End(3);
302 }
303
308 public void OCTET_STRING(byte[] Value)
309 {
310 this.output.WriteByte(4);
311 this.EncodeBinary(Value);
312 }
313
317 public void StartOCTET_STRING()
318 {
319 this.Start(4);
320 }
321
325 public void EndOCTET_STRING()
326 {
327 this.End(4);
328 }
329
333 public void NULL()
334 {
335 this.output.WriteByte(5);
336 this.output.WriteByte(0);
337 }
338
343 public void OBJECT_IDENTIFIER(string OID)
344 {
345 string[] s = OID.Split('.');
346 int i, c = s.Length;
347 uint[] OID2 = new uint[c];
348
349 for (i = 0; i < c; i++)
350 {
351 if (!uint.TryParse(s[i], out OID2[i]))
352 throw new ArgumentException("Invalid object identifier.", nameof(OID));
353 }
354
355 this.OBJECT_IDENTIFIER(OID2);
356 }
357
362 public void OBJECT_IDENTIFIER(uint[] OID)
363 {
364 int i, c = OID.Length;
365 uint j;
366
367 if (c < 2)
368 throw new ArgumentException("Invalid length of OID.", nameof(OID));
369
370 if (OID[1] >= 40)
371 throw new ArgumentException("Invalid second integer in OID.", nameof(OID));
372
373 j = OID[0] * 40;
374 if (j > 255 || j + OID[1] > 255)
375 throw new ArgumentException("Invalid first integer in OID.", nameof(OID));
376
377 j += OID[1];
378
379 using (MemoryStream Bin = new MemoryStream())
380 {
381 Bin.WriteByte((byte)j);
382
383 for (i = 2; i < c; i++)
384 {
385 j = OID[i];
386
387 if (j >= 0x10000000)
388 Bin.WriteByte((byte)(128 + (j >> 28)));
389
390 if (j >= 0x200000)
391 Bin.WriteByte((byte)(128 + (j >> 21)));
392
393 if (j >= 0x4000)
394 Bin.WriteByte((byte)(128 + (j >> 14)));
395
396 if (j >= 0x80)
397 Bin.WriteByte((byte)(128 + (j >> 7)));
398
399 Bin.WriteByte((byte)(j & 127));
400 }
401
402 this.output.WriteByte(6);
403 this.EncodeBinary(Bin.ToArray());
404 }
405 }
406
411 public void UNICODE_STRING(string Value)
412 {
413 this.output.WriteByte(0x1e);
414 this.EncodeBinary(Encoding.BigEndianUnicode.GetBytes(Value));
415 }
416
421 public void IA5_STRING(string Value)
422 {
423 this.output.WriteByte(0x16);
424 this.EncodeBinary(Encoding.ASCII.GetBytes(Value));
425 }
426
431 public void PRINTABLE_STRING(string Value)
432 {
433 if (!IsPrintable(Value))
434 throw new ArgumentException("Not a printable string.", nameof(Value));
435
436 this.output.WriteByte(0x13);
437 this.EncodeBinary(Encoding.ASCII.GetBytes(Value));
438 }
439
445 public static bool IsPrintable(string Value)
446 {
447 return PrintableString.IsMatch(Value);
448 }
449
450 private static readonly Regex PrintableString = new Regex("^[A-Za-z0-9 '()+,-./:=?]*$", RegexOptions.Singleline | RegexOptions.Compiled);
451
456 public void UTF8_STRING(string Value)
457 {
458 this.output.WriteByte(0x0c);
459 this.EncodeBinary(Encoding.UTF8.GetBytes(Value));
460 }
461
465 public void StartSEQUENCE()
466 {
467 this.Start(0x30);
468 }
469
470 private void Start(byte Expected)
471 {
472 if (this.stack is null)
473 this.stack = new LinkedList<KeyValuePair<byte, MemoryStream>>();
474
475 this.stack.AddLast(new KeyValuePair<byte, MemoryStream>(Expected, this.output));
476
477 this.output = new MemoryStream();
478 }
479
483 public void EndSEQUENCE()
484 {
485 this.End(0x30);
486 }
487
488 private void End(byte Type)
489 {
490 if (this.stack is null || this.stack.Last is null)
491 throw new Exception("Not properly started.");
492
493 if (Type != this.stack.Last.Value.Key)
494 throw new Exception("Start/End type mismatch.");
495
496 byte[] Bin = this.output.ToArray();
497 this.output.Dispose();
498
499 this.output = this.stack.Last.Value.Value;
500 this.stack.RemoveLast();
501
502 this.output.WriteByte(Type);
503 this.EncodeBinary(Bin);
504 }
505
509 public void StartSET()
510 {
511 this.Start(0x31);
512 }
513
517 public void EndSET()
518 {
519 this.End(0x31);
520 }
521
526 public void Content(Asn1TypeClass Class)
527 {
528 this.output.WriteByte((byte)((((int)Class) << 6) | 0x20));
529 this.output.WriteByte(0);
530 }
531
536 public void StartContent(Asn1TypeClass Class)
537 {
538 this.Start((byte)((((int)Class) << 6) | 0x20));
539 }
540
545 public void EndContent(Asn1TypeClass Class)
546 {
547 this.End((byte)((((int)Class) << 6) | 0x20));
548 }
549
554 public void Raw(byte[] DerEncodedBytes)
555 {
556 this.output.Write(DerEncodedBytes, 0, DerEncodedBytes.Length);
557 }
558
562 public int Position
563 {
564 get { return (int)this.output.Position; }
565 }
566
572 public byte this[int Index]
573 {
574 get
575 {
576 long PosBak = this.output.Position;
577 byte Result;
578
579 this.output.Position = Index;
580 Result = (byte)this.output.ReadByte();
581 this.output.Position = PosBak;
582
583 return Result;
584 }
585
586 set
587 {
588 long PosBak = this.output.Position;
589
590 this.output.Position = Index;
591 this.output.WriteByte(value);
592 this.output.Position = PosBak;
593 }
594 }
595
596 }
597}
Encodes data using the Distinguished Encoding Rules (DER), as defined in X.690
Definition: DerEncoder.cs:40
void Raw(byte[] DerEncodedBytes)
Adds DER-encoded bytes to the output.
Definition: DerEncoder.cs:554
byte[] ToArray()
Converts the generated output to a byte arary.
Definition: DerEncoder.cs:72
void Clear()
Clears the output buffer.
Definition: DerEncoder.cs:62
void Content(Asn1TypeClass Class)
Encodes content to the output.
Definition: DerEncoder.cs:526
void EndSET()
Ends the current SET.
Definition: DerEncoder.cs:517
void StartOCTET_STRING()
Starts a OCTET_STRING.
Definition: DerEncoder.cs:317
void StartBITSTRING()
Starts a BITSTRING.
Definition: DerEncoder.cs:290
void Dispose()
IDisposable.Dispose
Definition: DerEncoder.cs:54
void EndSEQUENCE()
Ends the current SEQUENCE.
Definition: DerEncoder.cs:483
void INTEGER(byte[] Value, bool Negative)
Encodes an INTEGER value.
Definition: DerEncoder.cs:164
void BITSTRING(byte[] Bytes)
Encodes an BITSTRING value.
Definition: DerEncoder.cs:275
void EndContent(Asn1TypeClass Class)
Ends the current Content section.
Definition: DerEncoder.cs:545
DerEncoder()
Encodes data using the Distinguished Encoding Rules (DER), as defined in X.690
Definition: DerEncoder.cs:47
void UNICODE_STRING(string Value)
Encodes a UNICODE STRING (BMPString) value.
Definition: DerEncoder.cs:411
static bool IsPrintable(string Value)
Checks if a string is a printable string.
Definition: DerEncoder.cs:445
void OBJECT_IDENTIFIER(string OID)
Encodes an OBJECT IDENTIFIER value.
Definition: DerEncoder.cs:343
void NULL()
Encodes an NULL value.
Definition: DerEncoder.cs:333
void BOOLEAN(bool Value)
Encodes an BOOLEAN value.
Definition: DerEncoder.cs:84
void EndOCTET_STRING()
Ends the current OCTET_STRING.
Definition: DerEncoder.cs:325
void IA5_STRING(string Value)
Encodes an IA5 STRING value.
Definition: DerEncoder.cs:421
void BITSTRING(BitArray Bits)
Encodes an BITSTRING value.
Definition: DerEncoder.cs:235
void OBJECT_IDENTIFIER(uint[] OID)
Encodes an OBJECT IDENTIFIER value.
Definition: DerEncoder.cs:362
void StartContent(Asn1TypeClass Class)
Starts a content section.
Definition: DerEncoder.cs:536
void UTF8_STRING(string Value)
Encodes an UTF-8 STRING value.
Definition: DerEncoder.cs:456
int Position
Current output position.
Definition: DerEncoder.cs:563
void INTEGER(long Value)
Encodes an INTEGER value.
Definition: DerEncoder.cs:99
void EndBITSTRING()
Ends the current BITSTRING.
Definition: DerEncoder.cs:299
void PRINTABLE_STRING(string Value)
Encodes an PRINTABLE STRING value.
Definition: DerEncoder.cs:431
void StartSET()
Starts a SET.
Definition: DerEncoder.cs:509
void StartSEQUENCE()
Starts a SEQUENCE.
Definition: DerEncoder.cs:465
void OCTET_STRING(byte[] Value)
Encodes an OCTET STRING value.
Definition: DerEncoder.cs:308
Asn1TypeClass
Type class
Definition: DerEncoder.cs:14