Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
BER.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Text;
7
8namespace Waher.Content.Asn1
9{
13 public static class BER
14 {
22 public static long DecodeIdentifier(Stream Input, out bool Constructed, out TagClass Class)
23 {
24 int i = Input.ReadByte();
25 if (i < 0)
26 throw new EndOfStreamException();
27
28 Class = (TagClass)((i >> 6) & 3);
29 Constructed = (i & 32) != 0;
30
31 i &= 31;
32 if (i < 31)
33 return i;
34
35 return DecodeVarLenInt(Input);
36 }
37
38 private static long DecodeVarLenInt(Stream Input)
39 {
40 int i = Input.ReadByte();
41 if (i < 0)
42 throw new EndOfStreamException();
43
44 long Result = (uint)(i & 127);
45 while ((i & 128) > 0)
46 {
47 i = Input.ReadByte();
48 if (i < 0)
49 throw new EndOfStreamException();
50
51 Result <<= 7;
52 Result |= (uint)(i & 127);
53 }
54
55 return Result;
56 }
57
63 public static long DecodeLength(Stream Input)
64 {
65 int i = Input.ReadByte();
66 if (i < 0)
67 throw new EndOfStreamException();
68
69 if ((i & 128) != 0)
70 {
71 if (i == 128)
72 return -1; // Indefinite form
73 else
74 return (i & 127); // Short form
75 }
76
77 if (i > 8)
78 throw new NotSupportedException("Too long.");
79
80 return ReadInteger(Input, i, false);
81 }
82
83 private static long ReadInteger(Stream Input, int NrBytes, bool Signed)
84 {
85 long Result = 0;
86 int i;
87 bool First = true;
88
89 while (NrBytes-- > 0)
90 {
91 i = Input.ReadByte();
92 if (i < 0)
93 throw new EndOfStreamException();
94
95 if (First)
96 {
97 First = false;
98 if (Signed && (i & 128) != 0)
99 Result = -1;
100 }
101
102 Result <<= 8;
103 Result |= (byte)i;
104 }
105
106 return Result;
107 }
108
114 public static bool DecodeBOOLEAN(Stream Input)
115 {
116 if (DecodeLength(Input) != 1)
117 throw new InvalidOperationException("Invalid BOOLEAN value.");
118
119 int i = Input.ReadByte();
120 if (i < 0)
121 throw new EndOfStreamException();
122
123 return i != 0;
124 }
125
131 public static long DecodeINTEGER(Stream Input)
132 {
133 long Len = DecodeLength(Input);
134 if (Len < 0)
135 throw new NotSupportedException("Indefinite length not supported.");
136
137 if (Len > 8)
138 throw new NotSupportedException("INTEGER too large.");
139
140 if (Len == 0)
141 return 0;
142
143 return ReadInteger(Input, (int)Len, true);
144 }
145
152 public static Enum DecodeEnum<T>(Stream Input)
153 where T : Enum
154 {
155 long i = DecodeINTEGER(Input);
156 return (T)((object)i);
157 }
158
164 public static double DecodeREAL(Stream Input)
165 {
166 long Len = DecodeLength(Input);
167 if (Len == 0)
168 return 0;
169
170 if (Len < 0)
171 throw new NotSupportedException("Indefinite length not supported.");
172
173 if (Len > 8)
174 throw new NotSupportedException("REAL size not supported.");
175
176 int i = Input.ReadByte();
177 if (i < 0)
178 throw new EndOfStreamException();
179
180 int c = (int)(Len - 1);
181
182 if ((i & 128) != 0) // Binary encoding
183 {
184 bool Negative = (i & 64) != 0;
185 byte F = (byte)((i >> 2) & 3);
186 long Exponent;
187
188 switch (i & 3)
189 {
190 case 0:
191 c--;
192 Exponent = ReadInteger(Input, 1, true);
193 break;
194
195 case 1:
196 c -= 2;
197 Exponent = ReadInteger(Input, 2, true);
198 break;
199
200 case 2:
201 c -= 3;
202 Exponent = ReadInteger(Input, 3, true);
203 break;
204
205 case 3:
206 default:
207 int j = (int)ReadInteger(Input, 1, false);
208 c -= j;
209 Exponent = ReadInteger(Input, j, true);
210 break;
211 }
212
213 if (c < 0)
214 throw new InvalidOperationException("Invalid REAL.");
215
216 double Mantissa = ReadInteger(Input, c, false);
217
218 Mantissa *= Math.Pow(2.0, F);
219 if (Negative)
220 Mantissa = -Mantissa;
221
222 if (Exponent == 0)
223 return Mantissa;
224
225 switch ((i >> 4) & 3)
226 {
227 case 0: // Base 2
228 return Mantissa * Math.Pow(2, Exponent);
229
230 case 1: // Base 8
231 return Mantissa * Math.Pow(8, Exponent);
232
233 case 2: // Base 16
234 return Mantissa * Math.Pow(16, Exponent);
235
236 case 3: // Reserved
237 default:
238 throw new NotSupportedException("Reserved base.");
239 }
240 }
241 else if ((i & 64) == 0) // Decimal encoding
242 {
243 byte[] Bin = new byte[c];
244 Input.ReadAll(Bin, 0, c);
245
246 string s = CommonTypes.GetString(Bin, Encoding.ASCII).Trim();
247
248 if (!CommonTypes.TryParse(s, out double d))
249 throw new NotSupportedException("Unsupported REAL value.");
250
251 return d;
252 }
253 else // Special value
254 {
255 if (c != 1)
256 throw new NotSupportedException("Invalid special value");
257
258 i = Input.ReadByte();
259 if (i < 0)
260 throw new EndOfStreamException();
261
262 switch (i)
263 {
264 case 64: return double.PositiveInfinity;
265 case 65: return double.NegativeInfinity;
266 case 66: return double.NaN;
267 case 67: return 0;
268 default: throw new NotSupportedException("Invalid special value");
269 }
270 }
271 }
272
279 public static byte[] DecodeBitString(Stream Input, out int NrUnusedBits)
280 {
281 long Len = DecodeLength(Input);
282 if (Len == 0)
283 throw new InvalidOperationException("Invalid BIT STRING.");
284
285 if (Len < 0)
286 {
287 using (MemoryStream ms = new MemoryStream())
288 {
289 NrUnusedBits = 0;
290 while ((Len = DecodeIdentifier(Input, out bool _, out TagClass _)) != 0)
291 {
292 if (Len != 3)
293 throw new NotSupportedException("Expected BIT STRING.");
294
295 byte[] Bin = DecodeBitString(Input, out NrUnusedBits);
296 ms.Write(Bin, 0, Bin.Length);
297 }
298
299 if (DecodeLength(Input) != 0)
300 throw new InvalidOperationException("Expected zero length.");
301
302 return ms.ToArray();
303 }
304 }
305 else
306 {
307 NrUnusedBits = Input.ReadByte();
308 if (NrUnusedBits < 0)
309 throw new EndOfStreamException();
310
311 if (--Len > int.MaxValue)
312 throw new NotSupportedException("BIT STRING too large.");
313
314 int c = (int)Len;
315 byte[] Bin = new byte[c];
316 Input.ReadAll(Bin, 0, c);
317
318 return Bin;
319 }
320 }
321
327 public static byte[] DecodeOctetString(Stream Input)
328 {
329 long Len = DecodeLength(Input);
330 if (Len == 0)
331 return new byte[0];
332
333 if (Len < 0)
334 {
335 using (MemoryStream ms = new MemoryStream())
336 {
337 while ((Len = DecodeIdentifier(Input, out bool _, out TagClass _)) != 0)
338 {
339 if (Len != 4)
340 throw new NotSupportedException("Expected OCTET STRING.");
341
342 byte[] Bin = DecodeOctetString(Input);
343 ms.Write(Bin, 0, Bin.Length);
344 }
345
346 if (DecodeLength(Input) != 0)
347 throw new InvalidOperationException("Expected zero length.");
348
349 return ms.ToArray();
350 }
351 }
352 else
353 {
354 if (Len > int.MaxValue)
355 throw new NotSupportedException("OCTET STRING too large.");
356
357 int c = (int)Len;
358 byte[] Bin = new byte[c];
359 Input.ReadAll(Bin, 0, c);
360
361 return Bin;
362 }
363 }
364
370 public static void DecodeNull(Stream Input)
371 {
372 if (DecodeLength(Input) != 0)
373 throw new InvalidOperationException("Expected zero length.");
374 }
375
381 public static int[] DecodeObjectId(Stream Input)
382 {
383 long Len = DecodeLength(Input);
384 if (Len == 0)
385 return new int[0];
386
387 if (Len < 0)
388 throw new NotSupportedException("Indefinite length not supported.");
389
390 List<int> Result = new List<int>();
391 long EndPos = Input.Position + Len;
392
393 Len = DecodeVarLenInt(Input);
394 Result.Add((int)(Len % 40));
395
396 Len /= 40;
397 if (Len > int.MaxValue)
398 throw new NotSupportedException("Invalid OBJECT IDENTIFIER");
399
400 Result.Add((int)Len);
401
402 while (Input.Position < EndPos)
403 {
404 Len = DecodeVarLenInt(Input);
405 if (Len > int.MaxValue)
406 throw new NotSupportedException("Invalid OBJECT IDENTIFIER");
407
408 Result.Add((int)Len);
409 }
410
411 return Result.ToArray();
412 }
413
419 public static int[] DecodeRelativeObjectId(Stream Input)
420 {
421 return DecodeObjectId(Input);
422 }
423
429 public static string DecodeBmpString(Stream Input)
430 {
431 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.BigEndianUnicode);
432 }
433
439 public static string DecodeIa5String(Stream Input)
440 {
441 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.ASCII);
442 }
443
449 public static string DecodeVisibleString(Stream Input)
450 {
451 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.ASCII);
452 }
453
459 public static string DecodeUtf8String(Stream Input)
460 {
461 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF8);
462 }
463
469 public static string DecodeUniversalString(Stream Input)
470 {
471 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF32);
472 }
473
479 public static string DecodePrintableString(Stream Input)
480 {
481 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.ASCII);
482 }
483
489 public static string DecodeNumericString(Stream Input)
490 {
491 return CommonTypes.GetString(DecodeOctetString(Input), Encoding.ASCII);
492 }
493
499 public static TimeSpan DecodeTime(Stream Input)
500 {
501 return TimeSpan.Parse(CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF8));
502 }
503
509 public static DateTime DecodeDate(Stream Input)
510 {
511 if (!XML.TryParse(CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF8), out DateTime TP))
512 throw new NotSupportedException("Unsupported DATE format.");
513
514 return TP;
515 }
516
522 public static TimeSpan DecodeTimeOfDay(Stream Input)
523 {
524 return TimeSpan.Parse(CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF8));
525 }
526
532 public static DateTime DecodeDateTime(Stream Input)
533 {
534 if (!XML.TryParse(CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF8), out DateTime TP))
535 throw new NotSupportedException("Unsupported DATE-TIME format.");
536
537 return TP;
538 }
539
545 public static Duration DecodeDuration(Stream Input)
546 {
547 if (!Duration.TryParse(CommonTypes.GetString(DecodeOctetString(Input), Encoding.UTF8), out Duration D))
548 throw new NotSupportedException("Unsupported DURATION format.");
549
550 return D;
551 }
552
553 }
554}
Implements static methods for Basic Encoding Rules (BER), as defined in X.690
Definition: BER.cs:14
static long DecodeIdentifier(Stream Input, out bool Constructed, out TagClass Class)
Decodes an identifier from the stream.
Definition: BER.cs:22
static TimeSpan DecodeTime(Stream Input)
Decodes a TIME value.
Definition: BER.cs:499
static TimeSpan DecodeTimeOfDay(Stream Input)
Decodes a TIME-OF-DAY value.
Definition: BER.cs:522
static void DecodeNull(Stream Input)
Decodes a NULL value.
Definition: BER.cs:370
static string DecodeIa5String(Stream Input)
Decodes a IA5String value.
Definition: BER.cs:439
static string DecodeVisibleString(Stream Input)
Decodes a VisibleString value.
Definition: BER.cs:449
static DateTime DecodeDateTime(Stream Input)
Decodes a DATE-TIME value.
Definition: BER.cs:532
static long DecodeINTEGER(Stream Input)
Decodes an INTEGER value.
Definition: BER.cs:131
static string DecodePrintableString(Stream Input)
Decodes a PrintableString value.
Definition: BER.cs:479
static long DecodeLength(Stream Input)
Decodes the length of a contents section.
Definition: BER.cs:63
static DateTime DecodeDate(Stream Input)
Decodes a DATE value.
Definition: BER.cs:509
static string DecodeBmpString(Stream Input)
Decodes a BmpString value.
Definition: BER.cs:429
static Duration DecodeDuration(Stream Input)
Decodes a DURATION value.
Definition: BER.cs:545
static byte[] DecodeBitString(Stream Input, out int NrUnusedBits)
Decodes a BIT STRING value.
Definition: BER.cs:279
static Enum DecodeEnum< T >(Stream Input)
Decodes an enumerated value.
Definition: BER.cs:152
static int[] DecodeRelativeObjectId(Stream Input)
Decodes a RELATIVE-OID value.
Definition: BER.cs:419
static double DecodeREAL(Stream Input)
Decodes a REAL value.
Definition: BER.cs:164
static string DecodeNumericString(Stream Input)
Decodes a NumericString value.
Definition: BER.cs:489
static bool DecodeBOOLEAN(Stream Input)
Decodes a BOOLEAN value.
Definition: BER.cs:114
static string DecodeUniversalString(Stream Input)
Decodes a UniversalString value.
Definition: BER.cs:469
static byte[] DecodeOctetString(Stream Input)
Decodes a OCTET STRING value.
Definition: BER.cs:327
static string DecodeUtf8String(Stream Input)
Decodes a Utf8String value.
Definition: BER.cs:459
static int[] DecodeObjectId(Stream Input)
Decodes an OBJECT IDENTIFIER value.
Definition: BER.cs:381
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:46
static string GetString(byte[] Data, Encoding DefaultEncoding)
Gets a string from its binary representation, taking any Byte Order Mark (BOM) into account.
Helps with common XML-related tasks.
Definition: XML.cs:19
static bool TryParse(string s, out DateTime Value)
Tries to decode a string encoded DateTime.
Definition: XML.cs:744
TagClass
TAG class
Definition: TagClass.cs:11
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:13
static bool TryParse(string s, out Duration Result)
Tries to parse a duration value.
Definition: Duration.cs:85