781 lines
27 KiB
C#
781 lines
27 KiB
C#
|
//+-------------------------------------------------------------------------------+
|
|||
|
//| Copyright (c) 2003 Liping Dai. All rights reserved. |
|
|||
|
//| Web: www.lipingshare.com |
|
|||
|
//| Email: lipingshare@yahoo.com |
|
|||
|
//| |
|
|||
|
//| Copyright and Permission Details: |
|
|||
|
//| ================================= |
|
|||
|
//| Permission is hereby granted, free of charge, to any person obtaining a copy |
|
|||
|
//| of this software and associated documentation files (the "Software"), to deal |
|
|||
|
//| in the Software without restriction, including without limitation the rights |
|
|||
|
//| to use, copy, modify, merge, publish, distribute, and/or sell copies of the |
|
|||
|
//| Software, subject to the following conditions: |
|
|||
|
//| |
|
|||
|
//| 1. Redistributions of source code must retain the above copyright notice, this|
|
|||
|
//| list of conditions and the following disclaimer. |
|
|||
|
//| |
|
|||
|
//| 2. Redistributions in binary form must reproduce the above copyright notice, |
|
|||
|
//| this list of conditions and the following disclaimer in the documentation |
|
|||
|
//| and/or other materials provided with the distribution. |
|
|||
|
//| |
|
|||
|
//| THE SOFTWARE PRODUCT IS PROVIDED <20>AS IS<49> WITHOUT WARRANTY OF ANY KIND, |
|
|||
|
//| EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
|||
|
//| WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR |
|
|||
|
//| A PARTICULAR PURPOSE. |
|
|||
|
//+-------------------------------------------------------------------------------+
|
|||
|
|
|||
|
using System;
|
|||
|
using System.IO;
|
|||
|
using System.Text;
|
|||
|
using Microsoft.Win32;
|
|||
|
|
|||
|
namespace LipingShare.LCLib.Asn1Processor
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Utility functions.
|
|||
|
/// </summary>
|
|||
|
internal class Asn1Util
|
|||
|
{
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Check if the string is ASN.1 encoded hex string.
|
|||
|
/// </summary>
|
|||
|
/// <param name="dataStr">The string.</param>
|
|||
|
/// <returns>true:Yes, false:No.</returns>
|
|||
|
public static bool IsAsn1EncodedHexStr(string dataStr)
|
|||
|
{
|
|||
|
bool retval = false;
|
|||
|
try
|
|||
|
{
|
|||
|
byte[] data = HexStrToBytes(dataStr);
|
|||
|
if (data.Length > 0)
|
|||
|
{
|
|||
|
Asn1Node node = new Asn1Node();
|
|||
|
retval = node.LoadData(data);
|
|||
|
}
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
retval = false;
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Format a string to have certain line length and character group length.
|
|||
|
/// Sample result FormatString(xstr,32,2):
|
|||
|
/// <code>07 AE 0B E7 84 5A D4 6C 6A BD DF 8F 89 88 9E F1</code>
|
|||
|
/// </summary>
|
|||
|
/// <param name="inStr">source string.</param>
|
|||
|
/// <param name="lineLen">line length.</param>
|
|||
|
/// <param name="groupLen">group length.</param>
|
|||
|
/// <returns></returns>
|
|||
|
public static string FormatString(string inStr, int lineLen, int groupLen)
|
|||
|
{
|
|||
|
char[] tmpCh = new char[inStr.Length * 2];
|
|||
|
int i, c = 0, linec = 0;
|
|||
|
int gc = 0;
|
|||
|
for (i = 0; i < inStr.Length; i++)
|
|||
|
{
|
|||
|
tmpCh[c++] = inStr[i];
|
|||
|
gc++;
|
|||
|
linec++;
|
|||
|
if (gc >= groupLen && groupLen > 0)
|
|||
|
{
|
|||
|
tmpCh[c++] = ' ';
|
|||
|
gc = 0;
|
|||
|
}
|
|||
|
if (linec >= lineLen)
|
|||
|
{
|
|||
|
tmpCh[c++] = '\r';
|
|||
|
tmpCh[c++] = '\n';
|
|||
|
linec = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
string retval = new string(tmpCh);
|
|||
|
retval = retval.TrimEnd('\0');
|
|||
|
retval = retval.TrimEnd('\n');
|
|||
|
retval = retval.TrimEnd('\r');
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Generate a string by duplicating <see cref="char"/> xch.
|
|||
|
/// </summary>
|
|||
|
/// <param name="len">duplicate times.</param>
|
|||
|
/// <param name="xch">the duplicated character.</param>
|
|||
|
/// <returns></returns>
|
|||
|
public static string GenStr(int len, char xch)
|
|||
|
{
|
|||
|
char[] ch = new char[len];
|
|||
|
for (int i = 0; i < len; i++)
|
|||
|
{
|
|||
|
ch[i] = xch;
|
|||
|
}
|
|||
|
return new string(ch);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert byte array to a <see cref="long"/> integer.
|
|||
|
/// </summary>
|
|||
|
/// <param name="bytes"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static long BytesToLong(byte[] bytes)
|
|||
|
{
|
|||
|
long tempInt = 0;
|
|||
|
for (int i = 0; i < bytes.Length; i++)
|
|||
|
{
|
|||
|
tempInt = tempInt << 8 | bytes[i];
|
|||
|
}
|
|||
|
return tempInt;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert a ASCII byte array to string, also filter out the null characters.
|
|||
|
/// </summary>
|
|||
|
/// <param name="bytes"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static string BytesToString(byte[] bytes)
|
|||
|
{
|
|||
|
string retval = "";
|
|||
|
if (bytes == null || bytes.Length < 1) return retval;
|
|||
|
char[] cretval = new char[bytes.Length];
|
|||
|
for (int i = 0, j = 0; i < bytes.Length; i++)
|
|||
|
{
|
|||
|
if (bytes[i] != '\0')
|
|||
|
{
|
|||
|
cretval[j++] = (char)bytes[i];
|
|||
|
}
|
|||
|
}
|
|||
|
retval = new string(cretval);
|
|||
|
retval = retval.TrimEnd('\0');
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert ASCII string to byte array.
|
|||
|
/// </summary>
|
|||
|
/// <param name="msg"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static byte[] StringToBytes(string msg)
|
|||
|
{
|
|||
|
byte[] retval = new byte[msg.Length];
|
|||
|
for (int i = 0; i < msg.Length; i++)
|
|||
|
{
|
|||
|
retval[i] = (byte)msg[i];
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Compare source and target byte array.
|
|||
|
/// </summary>
|
|||
|
/// <param name="source"></param>
|
|||
|
/// <param name="target"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static bool IsEqual(byte[] source, byte[] target)
|
|||
|
{
|
|||
|
if (source == null) return false;
|
|||
|
if (target == null) return false;
|
|||
|
if (source.Length != target.Length) return false;
|
|||
|
for (int i = 0; i < source.Length; i++)
|
|||
|
{
|
|||
|
if (source[i] != target[i]) return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Constant hex digits array.
|
|||
|
/// </summary>
|
|||
|
static char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7',
|
|||
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert a byte array to hex string.
|
|||
|
/// </summary>
|
|||
|
/// <param name="bytes">source array.</param>
|
|||
|
/// <returns>hex string.</returns>
|
|||
|
public static string ToHexString(byte[] bytes)
|
|||
|
{
|
|||
|
if (bytes == null) return "";
|
|||
|
char[] chars = new char[bytes.Length * 2];
|
|||
|
int b, i;
|
|||
|
for (i = 0; i < bytes.Length; i++)
|
|||
|
{
|
|||
|
b = bytes[i];
|
|||
|
chars[i * 2] = hexDigits[b >> 4];
|
|||
|
chars[i * 2 + 1] = hexDigits[b & 0xF];
|
|||
|
}
|
|||
|
return new string(chars);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Check if the character is a valid hex digits.
|
|||
|
/// </summary>
|
|||
|
/// <param name="ch">source character.</param>
|
|||
|
/// <returns>true:Valid, false:Invalid.</returns>
|
|||
|
public static bool IsValidHexDigits(char ch)
|
|||
|
{
|
|||
|
bool retval = false;
|
|||
|
for (int i = 0; i < hexDigits.Length; i++)
|
|||
|
{
|
|||
|
if (hexDigits[i] == ch)
|
|||
|
{
|
|||
|
retval = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Get hex digits value.
|
|||
|
/// </summary>
|
|||
|
/// <param name="ch">source character.</param>
|
|||
|
/// <returns>hex digits value.</returns>
|
|||
|
public static byte GetHexDigitsVal(char ch)
|
|||
|
{
|
|||
|
byte retval = 0;
|
|||
|
for (int i = 0; i < hexDigits.Length; i++)
|
|||
|
{
|
|||
|
if (hexDigits[i] == ch)
|
|||
|
{
|
|||
|
retval = (byte)i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert hex string to byte array.
|
|||
|
/// </summary>
|
|||
|
/// <param name="hexStr">Source hex string.</param>
|
|||
|
/// <returns>return byte array.</returns>
|
|||
|
public static byte[] HexStrToBytes(string hexStr)
|
|||
|
{
|
|||
|
hexStr = hexStr.Replace(" ", "");
|
|||
|
hexStr = hexStr.Replace("\r", "");
|
|||
|
hexStr = hexStr.Replace("\n", "");
|
|||
|
hexStr = hexStr.ToUpper();
|
|||
|
if ((hexStr.Length % 2) != 0) throw new Exception("Invalid Hex string: odd length.");
|
|||
|
int i;
|
|||
|
for (i = 0; i < hexStr.Length; i++)
|
|||
|
{
|
|||
|
if (!IsValidHexDigits(hexStr[i]))
|
|||
|
{
|
|||
|
throw new Exception("Invalid Hex string: included invalid character [" +
|
|||
|
hexStr[i] + "]");
|
|||
|
}
|
|||
|
}
|
|||
|
int bc = hexStr.Length / 2;
|
|||
|
byte[] retval = new byte[bc];
|
|||
|
int b1, b2, b;
|
|||
|
for (i = 0; i < bc; i++)
|
|||
|
{
|
|||
|
b1 = GetHexDigitsVal(hexStr[i * 2]);
|
|||
|
b2 = GetHexDigitsVal(hexStr[i * 2 + 1]);
|
|||
|
b = ((b1 << 4) | b2);
|
|||
|
retval[i] = (byte)b;
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Check if the source string is a valid hex string.
|
|||
|
/// </summary>
|
|||
|
/// <param name="hexStr">source string.</param>
|
|||
|
/// <returns>true:Valid, false:Invalid.</returns>
|
|||
|
public static bool IsHexStr(string hexStr)
|
|||
|
{
|
|||
|
byte[] bytes = null;
|
|||
|
try
|
|||
|
{
|
|||
|
bytes = HexStrToBytes(hexStr);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (bytes == null || bytes.Length < 0)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private const string PemStartStr = "-----BEGIN";
|
|||
|
private const string PemEndStr = "-----END";
|
|||
|
/// <summary>
|
|||
|
/// Check if the source string is PEM formated string.
|
|||
|
/// </summary>
|
|||
|
/// <param name="pemStr">source string.</param>
|
|||
|
/// <returns>true:Valid, false:Invalid.</returns>
|
|||
|
public static bool IsPemFormated(string pemStr)
|
|||
|
{
|
|||
|
byte[] data = null;
|
|||
|
try
|
|||
|
{
|
|||
|
data = PemToBytes(pemStr);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
return (data.Length > 0);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Check if a file is PEM formated.
|
|||
|
/// </summary>
|
|||
|
/// <param name="fileName">source file name.</param>
|
|||
|
/// <returns>true:Yes, false:No.</returns>
|
|||
|
public static bool IsPemFormatedFile(string fileName)
|
|||
|
{
|
|||
|
bool retval = false;
|
|||
|
try
|
|||
|
{
|
|||
|
FileStream fs = new FileStream(fileName, System.IO.FileMode.Open);
|
|||
|
byte[] data = new byte[fs.Length];
|
|||
|
fs.Read(data, 0, data.Length);
|
|||
|
fs.Close();
|
|||
|
string dataStr = Asn1Util.BytesToString(data);
|
|||
|
retval = IsPemFormated(dataStr);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
retval = false;
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert PEM formated string into <see cref="Stream"/> and set the Stream position to 0.
|
|||
|
/// </summary>
|
|||
|
/// <param name="pemStr">source string.</param>
|
|||
|
/// <returns>output stream.</returns>
|
|||
|
public static Stream PemToStream(string pemStr)
|
|||
|
{
|
|||
|
byte[] bytes = PemToBytes(pemStr);
|
|||
|
MemoryStream retval = new MemoryStream(bytes);
|
|||
|
retval.Position = 0;
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert PEM formated string into byte array.
|
|||
|
/// </summary>
|
|||
|
/// <param name="pemStr">source string.</param>
|
|||
|
/// <returns>output byte array.</returns>
|
|||
|
public static byte[] PemToBytes(string pemStr)
|
|||
|
{
|
|||
|
byte[] retval = null;
|
|||
|
string[] lines = pemStr.Split('\n');
|
|||
|
string base64Str = "";
|
|||
|
bool started = false, ended = false;
|
|||
|
string cline = "";
|
|||
|
for (int i = 0; i < lines.Length; i++)
|
|||
|
{
|
|||
|
cline = lines[i].ToUpper();
|
|||
|
if (cline == "") continue;
|
|||
|
if (cline.Length > PemStartStr.Length)
|
|||
|
{
|
|||
|
if (!started && cline.Substring(0, PemStartStr.Length) == PemStartStr)
|
|||
|
{
|
|||
|
started = true;
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
if (cline.Length > PemEndStr.Length)
|
|||
|
{
|
|||
|
if (cline.Substring(0, PemEndStr.Length) == PemEndStr)
|
|||
|
{
|
|||
|
ended = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (started)
|
|||
|
{
|
|||
|
base64Str += lines[i];
|
|||
|
}
|
|||
|
}
|
|||
|
if (!(started && ended))
|
|||
|
{
|
|||
|
throw new Exception("'BEGIN'/'END' line is missing.");
|
|||
|
}
|
|||
|
base64Str = base64Str.Replace("\r", "");
|
|||
|
base64Str = base64Str.Replace("\n", "");
|
|||
|
base64Str = base64Str.Replace("\n", " ");
|
|||
|
retval = Convert.FromBase64String(base64Str);
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert byte array to PEM formated string.
|
|||
|
/// </summary>
|
|||
|
/// <param name="data"></param>
|
|||
|
/// <returns></returns>
|
|||
|
public static string BytesToPem(byte[] data)
|
|||
|
{
|
|||
|
return BytesToPem(data, "");
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Retrieve PEM file heading.
|
|||
|
/// </summary>
|
|||
|
/// <param name="fileName">source file name.</param>
|
|||
|
/// <returns>heading string.</returns>
|
|||
|
public static string GetPemFileHeader(string fileName)
|
|||
|
{
|
|||
|
try
|
|||
|
{
|
|||
|
FileStream fs = new FileStream(fileName, FileMode.Open);
|
|||
|
byte[] data = new byte[fs.Length];
|
|||
|
fs.Read(data, 0, data.Length);
|
|||
|
fs.Close();
|
|||
|
string dataStr = Asn1Util.BytesToString(data);
|
|||
|
return GetPemHeader(dataStr);
|
|||
|
}
|
|||
|
catch
|
|||
|
{
|
|||
|
return "";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Retrieve PEM heading from a PEM formated string.
|
|||
|
/// </summary>
|
|||
|
/// <param name="pemStr">source string.</param>
|
|||
|
/// <returns>heading string.</returns>
|
|||
|
public static string GetPemHeader(string pemStr)
|
|||
|
{
|
|||
|
string[] lines = pemStr.Split('\n');
|
|||
|
bool started = false;
|
|||
|
string cline = "";
|
|||
|
for (int i = 0; i < lines.Length; i++)
|
|||
|
{
|
|||
|
cline = lines[i].ToUpper().Replace("\r", "");
|
|||
|
if (cline == "") continue;
|
|||
|
if (cline.Length > PemStartStr.Length)
|
|||
|
{
|
|||
|
if (!started && cline.Substring(0, PemStartStr.Length) == PemStartStr)
|
|||
|
{
|
|||
|
started = true;
|
|||
|
string retstr = lines[i].Substring(PemStartStr.Length,
|
|||
|
lines[i].Length -
|
|||
|
PemStartStr.Length).Replace("-----", "");
|
|||
|
return retstr.Replace("\r", "");
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
return "";
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Convert byte array to PEM formated string and set the heading as pemHeader.
|
|||
|
/// </summary>
|
|||
|
/// <param name="data">source array.</param>
|
|||
|
/// <param name="pemHeader">PEM heading.</param>
|
|||
|
/// <returns>PEM formated string.</returns>
|
|||
|
public static string BytesToPem(byte[] data, string pemHeader)
|
|||
|
{
|
|||
|
if (pemHeader == null || pemHeader.Length < 1)
|
|||
|
{
|
|||
|
pemHeader = "ASN.1 Editor Generated PEM File";
|
|||
|
}
|
|||
|
string retval = "";
|
|||
|
if (pemHeader.Length > 0 && pemHeader[0] != ' ')
|
|||
|
{
|
|||
|
pemHeader = " " + pemHeader;
|
|||
|
}
|
|||
|
retval = Convert.ToBase64String(data);
|
|||
|
retval = FormatString(retval, 64, 0);
|
|||
|
retval = "-----BEGIN" + pemHeader + "-----\r\n" +
|
|||
|
retval +
|
|||
|
"\r\n-----END" + pemHeader + "-----\r\n";
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Calculate how many bits is enough to hold ivalue.
|
|||
|
/// </summary>
|
|||
|
/// <param name="ivalue">source value.</param>
|
|||
|
/// <returns>bits number.</returns>
|
|||
|
public static int BitPrecision(ulong ivalue)
|
|||
|
{
|
|||
|
if (ivalue == 0) return 0;
|
|||
|
int l = 0, h = 8 * 4; // 4: sizeof(ulong)
|
|||
|
while (h - l > 1)
|
|||
|
{
|
|||
|
int t = (int)(l + h) / 2;
|
|||
|
if ((ivalue >> t) != 0)
|
|||
|
l = t;
|
|||
|
else
|
|||
|
h = t;
|
|||
|
}
|
|||
|
return h;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Calculate how many bytes is enough to hold the value.
|
|||
|
/// </summary>
|
|||
|
/// <param name="value">input value.</param>
|
|||
|
/// <returns>bytes number.</returns>
|
|||
|
public static int BytePrecision(ulong value)
|
|||
|
{
|
|||
|
int i;
|
|||
|
for (i = 4; i > 0; --i) // 4: sizeof(ulong)
|
|||
|
if ((value >> (i - 1) * 8) != 0)
|
|||
|
break;
|
|||
|
return i;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// ASN.1 DER length encoder.
|
|||
|
/// </summary>
|
|||
|
/// <param name="xdata">result output stream.</param>
|
|||
|
/// <param name="length">source length.</param>
|
|||
|
/// <returns>result bytes.</returns>
|
|||
|
public static int DERLengthEncode(Stream xdata, ulong length)
|
|||
|
{
|
|||
|
int i = 0;
|
|||
|
if (length <= 0x7f)
|
|||
|
{
|
|||
|
xdata.WriteByte((byte)length);
|
|||
|
i++;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
xdata.WriteByte((byte)(BytePrecision(length) | 0x80));
|
|||
|
i++;
|
|||
|
for (int j = BytePrecision((ulong)length); j > 0; --j)
|
|||
|
{
|
|||
|
xdata.WriteByte((byte)(length >> (j - 1) * 8));
|
|||
|
i++;
|
|||
|
}
|
|||
|
}
|
|||
|
return i;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// ASN.1 DER length decoder.
|
|||
|
/// </summary>
|
|||
|
/// <param name="bt">Source stream.</param>
|
|||
|
/// <param name="isIndefiniteLength">Output parameter.</param>
|
|||
|
/// <returns>Output length.</returns>
|
|||
|
public static long DerLengthDecode(Stream bt, ref bool isIndefiniteLength)
|
|||
|
{
|
|||
|
isIndefiniteLength = false;
|
|||
|
long length = 0;
|
|||
|
byte b;
|
|||
|
b = (byte)bt.ReadByte();
|
|||
|
if ((b & 0x80) == 0)
|
|||
|
{
|
|||
|
length = b;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
long lengthBytes = b & 0x7f;
|
|||
|
if (lengthBytes == 0)
|
|||
|
{
|
|||
|
isIndefiniteLength = true;
|
|||
|
return -2; // Indefinite length.
|
|||
|
}
|
|||
|
|
|||
|
length = 0;
|
|||
|
while (lengthBytes-- > 0)
|
|||
|
{
|
|||
|
if ((length >> (8 * (4 - 1))) > 0) // 4: sizeof(long)
|
|||
|
{
|
|||
|
return -1; // Length overflow.
|
|||
|
}
|
|||
|
b = (byte)bt.ReadByte();
|
|||
|
length = (length << 8) | b;
|
|||
|
}
|
|||
|
|
|||
|
if (length <= 0x7f)
|
|||
|
{
|
|||
|
return -1; // Indicated false node
|
|||
|
}
|
|||
|
}
|
|||
|
return length;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Decode tag value to return tag name.
|
|||
|
/// </summary>
|
|||
|
/// <param name="tag">input tag.</param>
|
|||
|
/// <returns>tag name.</returns>
|
|||
|
static public string GetTagName(byte tag)
|
|||
|
{
|
|||
|
string retval = "";
|
|||
|
if ((tag & Asn1TagClasses.CLASS_MASK) != 0)
|
|||
|
{
|
|||
|
switch (tag & Asn1TagClasses.CLASS_MASK)
|
|||
|
{
|
|||
|
case Asn1TagClasses.CONTEXT_SPECIFIC:
|
|||
|
retval += "CONTEXT SPECIFIC (" + ((int)(tag & Asn1Tag.TAG_MASK)).ToString() + ")";
|
|||
|
break;
|
|||
|
case Asn1TagClasses.APPLICATION:
|
|||
|
retval += "APPLICATION (" + ((int)(tag & Asn1Tag.TAG_MASK)).ToString() + ")";
|
|||
|
break;
|
|||
|
case Asn1TagClasses.PRIVATE:
|
|||
|
retval += "PRIVATE (" + ((int)(tag & Asn1Tag.TAG_MASK)).ToString() + ")";
|
|||
|
break;
|
|||
|
case Asn1TagClasses.CONSTRUCTED:
|
|||
|
retval += "CONSTRUCTED (" + ((int)(tag & Asn1Tag.TAG_MASK)).ToString() + ")";
|
|||
|
break;
|
|||
|
case Asn1TagClasses.UNIVERSAL:
|
|||
|
retval += "UNIVERSAL (" + ((int)(tag & Asn1Tag.TAG_MASK)).ToString() + ")";
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
switch (tag & Asn1Tag.TAG_MASK)
|
|||
|
{
|
|||
|
case Asn1Tag.BOOLEAN:
|
|||
|
retval += "BOOLEAN";
|
|||
|
break;
|
|||
|
case Asn1Tag.INTEGER:
|
|||
|
retval += "INTEGER";
|
|||
|
break;
|
|||
|
case Asn1Tag.BIT_STRING:
|
|||
|
retval += "BIT STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.OCTET_STRING:
|
|||
|
retval += "OCTET STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.TAG_NULL:
|
|||
|
retval += "NULL";
|
|||
|
break;
|
|||
|
case Asn1Tag.OBJECT_IDENTIFIER:
|
|||
|
retval += "OBJECT IDENTIFIER";
|
|||
|
break;
|
|||
|
case Asn1Tag.OBJECT_DESCRIPTOR:
|
|||
|
retval += "OBJECT DESCRIPTOR";
|
|||
|
break;
|
|||
|
case Asn1Tag.RELATIVE_OID:
|
|||
|
retval += "RELATIVE-OID";
|
|||
|
break;
|
|||
|
case Asn1Tag.EXTERNAL:
|
|||
|
retval += "EXTERNAL";
|
|||
|
break;
|
|||
|
case Asn1Tag.REAL:
|
|||
|
retval += "REAL";
|
|||
|
break;
|
|||
|
case Asn1Tag.ENUMERATED:
|
|||
|
retval += "ENUMERATED";
|
|||
|
break;
|
|||
|
case Asn1Tag.UTF8_STRING:
|
|||
|
retval += "UTF8 STRING";
|
|||
|
break;
|
|||
|
case (Asn1Tag.SEQUENCE):
|
|||
|
retval += "SEQUENCE";
|
|||
|
break;
|
|||
|
case (Asn1Tag.SET):
|
|||
|
retval += "SET";
|
|||
|
break;
|
|||
|
case Asn1Tag.NUMERIC_STRING:
|
|||
|
retval += "NUMERIC STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.PRINTABLE_STRING:
|
|||
|
retval += "PRINTABLE STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.T61_STRING:
|
|||
|
retval += "T61 STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.VIDEOTEXT_STRING:
|
|||
|
retval += "VIDEOTEXT STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.IA5_STRING:
|
|||
|
retval += "IA5 STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.UTC_TIME:
|
|||
|
retval += "UTC TIME";
|
|||
|
break;
|
|||
|
case Asn1Tag.GENERALIZED_TIME:
|
|||
|
retval += "GENERALIZED TIME";
|
|||
|
break;
|
|||
|
case Asn1Tag.GRAPHIC_STRING:
|
|||
|
retval += "GRAPHIC STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.VISIBLE_STRING:
|
|||
|
retval += "VISIBLE STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.GENERAL_STRING:
|
|||
|
retval += "GENERAL STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.UNIVERSAL_STRING:
|
|||
|
retval += "UNIVERSAL STRING";
|
|||
|
break;
|
|||
|
case Asn1Tag.BMPSTRING:
|
|||
|
retval += "BMP STRING";
|
|||
|
break;
|
|||
|
default:
|
|||
|
retval += "UNKNOWN TAG";
|
|||
|
break;
|
|||
|
};
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
#if UNITYIAP_DISABLED
|
|||
|
/// <summary>
|
|||
|
/// Read registry information from local machine entrys.
|
|||
|
/// </summary>
|
|||
|
/// <param name="path"></param>
|
|||
|
/// <param name="name"></param>
|
|||
|
/// <returns></returns>
|
|||
|
static public object ReadRegInfo(string path, string name)
|
|||
|
{
|
|||
|
object retval = null;
|
|||
|
Microsoft.Win32.RegistryKey regKey;
|
|||
|
regKey = Registry.LocalMachine.OpenSubKey(path, false);
|
|||
|
if (regKey!=null)
|
|||
|
{
|
|||
|
retval = regKey.GetValue(name);
|
|||
|
}
|
|||
|
return retval;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Write information into local machine registry entry.
|
|||
|
/// </summary>
|
|||
|
/// <param name="path"></param>
|
|||
|
/// <param name="name"></param>
|
|||
|
/// <param name="data"></param>
|
|||
|
static public void WriteRegInfo(string path, string name, object data)
|
|||
|
{
|
|||
|
Microsoft.Win32.RegistryKey regKey;
|
|||
|
regKey = Registry.LocalMachine.OpenSubKey(path, true);
|
|||
|
if (regKey == null)
|
|||
|
{
|
|||
|
regKey = Registry.LocalMachine.CreateSubKey(path);
|
|||
|
}
|
|||
|
if (regKey != null)
|
|||
|
{
|
|||
|
regKey.SetValue(name, data);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Constructor.
|
|||
|
/// </summary>
|
|||
|
private Asn1Util()
|
|||
|
{
|
|||
|
//Private constructor.
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|