2

BER 데이터를 인코딩하고 디코딩해야합니다. .NET은 정적 방법은 LDAP 인증서에 사용되는개체에 System.DirectoryServices.Protocols.BerConverter.Encode ("???", myData)와 함께 BER 인코딩을 사용하는 방법

 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 인코딩 아래와 같이 첫 번째 매개 변수에 문자열을 입력하라고 요구, 그리고 다른 많은 형식으로 평범 클래스를 System.DirectoryServices.Protocols.BerConverter

있습니다.

이 클래스에서 인코딩 또는 디코딩 방법을 알려주는 정보에 만족합니다. Stack Overflow 나 Google (또는 Bing)의 처음 몇 페이지에는 관련이 없습니다.

상담자 BER 디코딩을 사용하여 해당 OID에 위의 바이트 배열로 변환하려면 어떻게

  • ?

  • SubjectPublicKeyInfo ASN.1 데이터를 DER 또는 BER 형식으로 구문 분석 (또는 구문 분석) 할 수 있습니까?

  • DER 인코딩 \ 디코딩 클래스가 .NET 프레임 워크 내부에있는 것 같습니다. 그렇다면 그들은 어디에 있습니까?

+0

이 질문에 답이없는 경우 일반 용도의 TLV 구문 분석기를 제안합니다. 위의 함수는 DirectoryServices에 매우 특정한 것처럼 보입니다. – user845279

답변

5

가 어떻게 BER 디코딩을 사용하여 해당 OID에 위의 바이트 배열을 변환합니까 (나는이 멤버는 공개 할 connect.microsoft.com을 요청하고 싶습니다)?

OID 바이트 배열을 추출한 후에는 OidByteArrayToString()을 사용하여 OID 문자열로 변환 할 수 있습니다. .NET 라이브러리에서 비슷한 기능을 찾을 수 없으므로 아래 코드를 포함 시켰습니다.

SubjectPublicKeyInfo ASN.1 데이터를 DER 또는 BER 형식으로 구문 분석 (또는 구문 분석) 할 수 있습니까?

.NET SDK에서도 TLV 구문 분석기를 찾을 수 없었습니다. 아래는 BER TLV 구문 분석기 인 BerTlv의 구현입니다. DER은 BER의 하위 집합이므로 파싱도 같은 방식으로 작동합니다. BER-TLV byte[] 배열이 주어지면 sub TLV 액세스를 지원하는 BerTlv 개체 목록을 반환합니다.

DER 인코딩 \ 디코딩 클래스가 .NET 프레임 워크 내부에있는 것 같습니다. 그렇다면 그들은 어디에 있습니까? (connect.microsoft.com에게이 회원들을 공개하도록 요청하고 싶습니다.)

아마도 다른 사람이이 질문에 대답 할 수 있습니다.

요약 여기

는 아래에 제공된 코드를 사용하는 방법의 예입니다. 이전 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; 
    } 
} 
+0

이 구문 분석 코드를 제공해 주셔서 감사합니다. 그것은 저에게 많은 일을 덜어 줬습니다. 매우 간결합니다. – dviljoen

+0

감사합니다. 훌륭하게 작동합니다. 나중에 참조 할 수 있도록 여기서 버그 하나를 발견했습니다. BerTlv tlv = new BerTlv (tag, length, rawData.Length - length, rawData.Length - 길이)는 'BerTlv' 클래스의'parseTlv' 함수에서'BerTlv tlv = new BerTlv (tag, length, i-length, rawData) rawData); – kspearrin