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 encoding\decoding クラスは .NET フレームワークの内部にあるようです。もしそうなら、彼らはどこにいますか? (connect.microsoft.com にメンバーの公開を依頼したい)

4

1 に答える 1

6

BERデコードを使用して上記のバイト配列を対応するOIDに変換するにはどうすればよいですか?

OIDバイト配列を抽出した後、を使用してそれをOID文字列に変換できますOidByteArrayToString()。.NETライブラリで同様の関数が見つからなかったため、以下のコードを含めました。

SubjectPublicKeyInfo ASN.1データをDERまたはBER形式で解析(または解析を試みる)するにはどうすればよいですか?

.NETSDKでもTLVパーサーを見つけることができませんでした。以下は、BERTLVパーサーの実装ですBerTlv。DERはBERのサブセットであるため、解析は同じように機能します。BER-TLVbyte[]配列を指定するとBerTlv、サブTLVのアクセスをサポートするオブジェクトのリストが返されます。

DERのencoding\decodingクラスは.NETFrameworkの内部にあるようです。もしそうなら、彼らはどこにいますか?(これらのメンバーを公開するように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 に答える