如何将 BER 编码与对象 System.DirectoryServices.Protocols.BerConverter.Encode( "???" , myData) 一起使用



我需要对BER数据进行编码和解码。 .NET 具有类System.DirectoryServices.Protocols.BerConverter

静态方法要求我在第一个参数中输入一个字符串,如下所示

        byte[] oid = { 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // Object ID for RSA
        var result2 = System.DirectoryServices.Protocols.BerConverter.Decoding("?what goes here?", oid);

BER编码用于LDAP,证书,并且在许多其他格式中很常见。

我会很高兴有信息告诉我如何在这门课上编码或解码。 在Stack Overflow或Google(或Bing)的前几页中没有任何关于此的内容。

问题

  • 如何使用 BER 解码将上面的字节数组转换为相应的 OID?

  • 如何解析(或尝试解析)DER或BER格式的SubjectPublicKeyInfo ASN.1数据?

  • 似乎DER编码\解码类是.NET框架的内部。 如果是这样,它们在哪里? (我想请 connect.microsoft.com 公开这些成员)

如何使用 BER 解码将上面的字节数组转换为相应的 OID?

提取 OID 字节数组后,可以使用 OidByteArrayToString() 将其转换为 OID 字符串。我包含了下面的代码,因为我在 .NET 库中找不到类似的函数。

如何解析(或尝试解析)DER或BER格式的SubjectPublicKeyInfo ASN.1数据?

我也无法在.NET SDK中找到TLV解析器。下面是 BER TLV 解析器的实现,BerTlv 。由于 DER 是 BER 的子集,因此解析的工作方式相同。给定一个 BER-TLV byte[]数组,它将返回支持访问子 TLV 的BerTlv对象列表。

似乎DER编码\解码类是.NET框架的内部。如果是这样,它们在哪里?(我想请 connect.microsoft.com 公开这些成员)

也许其他人可以回答这个问题。

总结

下面是如何使用下面提供的代码的示例。我使用了您在上一篇文章中提供的公钥数据。BerTlv 可能应该增强以支持像 BerTlv.getValue(rootTlvs, '/30/30/06'); 这样的查询。

public static void Main(string[] args)
{
    string pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB";
    byte[] pubkeyByteArray = Convert.FromBase64String(pubkey);
    List<BerTlv> rootTlvs = BerTlv.parseTlv(pubkeyByteArray);
    BerTlv firstTlv = rootTlvs.Where(tlv => tlv.Tag == 0x30).First();//first sequence (tag 30)
    BerTlv secondTlv = firstTlv.SubTlv.Where(tlv => tlv.Tag == 0x30).First();//second sequence (tag 30)
    BerTlv oid = secondTlv.SubTlv.Where(tlv => tlv.Tag == 0x06).First();//OID tag (tag 30)
    string strOid = OidByteArrayToString(oid.Value);
    Console.WriteLine(strOid);
}

输出:

1.2.840.113549.1.1.1

OID 编码/解码

public static byte[] OidStringToByteArray(string oid)
{
    string[] split = oid.Split('.');
    List<byte> retVal = new List<byte>();
    //root arc
    if (split.Length > 0)
        retVal.Add((byte)(Convert.ToInt32(split[0])*40));
    //first arc
    if (split.Length > 1)
        retVal[0] += Convert.ToByte(split[1]);
    //subsequent arcs
    for (int i = 2; i < split.Length; i++)
    {
        int arc_value = Convert.ToInt32(split[i]);
        Stack<byte> bytes = new Stack<byte>();
        while (arc_value != 0)
        {
            byte val = (byte) ((arc_value & 0x7F) | (bytes.Count == 0 ? 0x0:0x80));
            arc_value >>= 7;
            bytes.Push(val);
        }
        retVal.AddRange(bytes);
    }
    return retVal.ToArray();
}
public static string OidByteArrayToString(byte[] oid)
{
    StringBuilder retVal = new StringBuilder();
    //first byte
    if (oid.Length > 0)
        retVal.Append(String.Format("{0}.{1}", oid[0] / 40, oid[0] % 40));
    // subsequent bytes
    int current_arc = 0;
    for (int i = 1; i < oid.Length; i++)
    {
        current_arc = (current_arc <<= 7) | oid[i] & 0x7F;
        //check if last byte of arc value
        if ((oid[i] & 0x80) == 0)
        {
            retVal.Append('.');
            retVal.Append(Convert.ToString(current_arc));
            current_arc = 0;
        }
    }
    return retVal.ToString();
}

BER-TLV 解析器

class BerTlv
{
    private int tag;
    private int length;
    private int valueOffset;
    private byte[] rawData;
    private List<BerTlv> subTlv;
    private BerTlv(int tag, int length, int valueOffset, byte[] rawData)
    {
        this.tag = tag;
        this.length = length;
        this.valueOffset = valueOffset;
        this.rawData = rawData;
        this.subTlv = new List<BerTlv>();
    }
    public int Tag
    {
        get { return tag; }
    }
    public byte[] RawData
    {
        get { return rawData; }
    }
    public byte[] Value
    {
        get
        {
            byte[] result = new byte[length];
            Array.Copy(rawData, valueOffset, result, 0, length);
            return result;
        }
    }
    public List<BerTlv> SubTlv
    {
        get { return subTlv; }
    }
    public static List<BerTlv> parseTlv(byte[] rawTlv)
    {
        List<BerTlv> result = new List<BerTlv>();
        parseTlv(rawTlv, result);
        return result;
    }
    private static void parseTlv(byte[] rawTlv, List<BerTlv> result)
    {
        for (int i = 0, start=0; i < rawTlv.Length; start=i)
        {
            //parse Tag
            bool constructed_tlv = (rawTlv[i] & 0x20) != 0;
            bool more_bytes = (rawTlv[i] & 0x1F) == 0x1F;
            while (more_bytes && (rawTlv[++i] & 0x80) != 0) ;
            i++;
            int tag = Util.getInt(rawTlv, start, i-start);
            //parse Length
            bool multiByte_Length = (rawTlv[i] & 0x80) != 0;
            int length = multiByte_Length ? Util.getInt(rawTlv, i+1, rawTlv[i] & 0x1F) : rawTlv[i];
            i = multiByte_Length ? i + (rawTlv[i] & 0x1F) + 1: i + 1;
            i += length;
            byte[] rawData = new byte[i - start];
            Array.Copy(rawTlv, start, rawData, 0, i - start);
            BerTlv tlv = new BerTlv(tag, length, i - length, rawData);
            result.Add(tlv);
            if (constructed_tlv)
                parseTlv(tlv.Value, tlv.subTlv);
        }
    }
}

下面是一个实用程序类,其中包含上述类中使用的一些函数。为了清楚起见,它是如何工作的。

class Util
{
    public static string getHexString(byte[] arr)
    {
        StringBuilder sb = new StringBuilder(arr.Length * 2);
        foreach (byte b in arr)
        {
            sb.AppendFormat("{0:X2}", b);
        }
        return sb.ToString();
    }
    public static byte[] getBytes(String str)
    {
        byte[] result = new byte[str.Length >> 1];
        for (int i = 0; i < result.Length; i++)
        {
            result[i] = (byte)Convert.ToInt32(str.Substring(i * 2, 2), 16);
        }
        return result;
    }
    public static int getInt(byte[] data, int offset, int length)
    {
        int result = 0;
        for (int i = 0; i < length; i++)
        {
            result = (result << 8) | data[offset + i];
        }
        return result;
    }
}

最新更新