3

我需要对 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 将这些成员公开)

4

1 回答 1

6

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

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

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

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

看来 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;
    }
}
于 2012-07-08T03:09:25.187 回答