encoding - 如何使用 BER 编码对象 System.DirectoryServices.Protocols.BerConverter.Encode ("???", myData)

标签 encoding character-encoding ldap x509certificate directoryservices

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

最佳答案

How do I convert the byte array above to the corresponding OID using BER decoding?

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

How can I parse (or attempt to parse) SubjectPublicKeyInfo ASN.1 data in DER or BER format?

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

It seems the DER encoding\decoding classes are internal to the .NET framework. If so, where are they? (I'd like to ask connect.microsoft.com to make these members public)

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

总结

这是您如何使用下面提供的代码的示例。我使用了你之前提供的公钥数据 post .应该增强 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;
    }
}

关于encoding - 如何使用 BER 编码对象 System.DirectoryServices.Protocols.BerConverter.Encode ("???", myData),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11269401/

相关文章:

python - 在 Python 中,如何将 8 位二进制数转换为 ASCII 字符?

java - Spring Framework 中邮件的重音支持

java - sql 查询中的外来/重音字符

使用 LDAP 的 IIS 基本身份验证

tomcat kerberos认证+ldap授权

java - RESTEasy 的错误特殊字符编码

java - 字节数组的最短字符串编码

.net - Server.UrlEncode 与 Uri.EscapeDataString

bash - openssl enc -base64 -d 在一定长度后不解码字符串

django-auth-ldap 认证失败