如何将对象标识符转换为十六进制字符串

时间:2010-07-31 01:08:21

标签: x509certificate x509

是否有任何[非编程语言特定]方法来获取对象标识符的十六进制版本?

例如:

  

OID 1.2.840.10040.4.1:dsa

     

hex string = 2a 86 48 ce 38 04 01

似乎没有一个易于访问的列表。我正在寻找X509证书中使用的OID

4 个答案:

答案 0 :(得分:6)

您可以使用CryptEncodeObjectEx解码包含OID的大多数加密对象。

对于OID,编码和解码很简单,因此您可以手动执行此操作。

两个第一个数字1.2将以一种特殊的方式编码。例如,x.y将被编码为40 * x + y。在1.2的情况下,我们有40 * 1 + 2 = 42或0x2a。

所有下一个字符将被解释为7位数字,其中最高位(如果我们从0开始,则位号为7)为0,则字节是最后一位,如果该位不是最后一位,则为1。例如,840是0x348。要对此进行编码,我们应该使用最后一个中的2个字节将保存为0x48。在前一个应该保存0x3与0x48的额外位(因为7位编码而不是8位编码)。所以我们应该在第一个字节中编码0x3 * 2 = 0x6。因为0x6将不是整数编码中的最后一个字节(接下来是0x48字节),我们应该将0x80添加到编码值。所以我们收到0x80 + 0x6 = 0x86。因此840将被编码为0x86和0x48。

以同样的方式10040是0x2738。最后一个字节是0x38,第一个字节是0x27 * 2(因为7位编码):0x27 * 2 = 0x4e。因为0x4e不是最后一个字节,所以我们应该将0x80添加到编码值:0x4e + 0x80 = 0xce。因此10040将被编码为两个字节0xce和0x38。

4和1将被编码为0x04和0x01。

所以1.2.840.10040.4.1应编码为2a 86 48 ce 38 04 01,就像你已经知道的那样。

所有这些都可以在ITU-T X.690(ISO / IEC 8825-1)的8.19中阅读

根据评论

更新:编码/解码程序出错了。 OID“1.2.840.113549.1.1.1”将表示为2A 86 48 86 F7 0D 01 01 01,而不是像您所写的那样2a 86 48 83 f6 8d 01 01 01。要验证这一点,您可以使用以下小型C程序:

#define STRICT
#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#pragma comment (lib, "Crypt32.lib")

void PrintOffset(DWORD dwMargineOffset)
{
    while (dwMargineOffset--)
        _tprintf (TEXT(" "));
}

void HexDump (PBYTE pData, DWORD dwDataLength)
{
    while (dwDataLength--) {
        _tprintf (TEXT("%02X"), *pData++);
        if (dwDataLength) _tprintf (TEXT(" "));
    }
}

void DumpOID (DWORD dwMargineOffset, PBYTE pData, DWORD dwDataLength)
{
    PCCRYPT_OID_INFO pCryptOidInfo;
    DWORD dw, i;
    char szOID[256];
    // i
    // first byte is encoded as x.y 40*x+y = 43 = 0x2B
    //
    //_tprintf(TEXT("%d.%d"), *pData/40, *pData%40);
    i = wsprintfA (szOID, "%d.%d", *pData/40, *pData%40);
    dwDataLength--;
    pData++;

    while (dwDataLength--) {
        if (*pData & 0x80) {
            dw = 0;
#pragma warning(disable:4127)
            while (TRUE) {
#pragma warning(default:4127)
                dw <<= 7;  // *128
                dw += (*pData & 0x7F);
                if (*pData++ & 0x80)
                    dwDataLength--;
                else
                    break;
            }
            //_tprintf(TEXT(".%d"), dw);
            i += wsprintfA (szOID+i, ".%d", dw);
        }
        else
            //_tprintf(TEXT(".%d"), *pData++);
            i += wsprintfA (szOID+i, ".%d", *pData++);
    }

    PrintOffset(dwMargineOffset);
    _tprintf (TEXT("%hs"), szOID);

    // try find OID in the list of known IODs
    pCryptOidInfo = CryptFindOIDInfo (CRYPT_OID_INFO_OID_KEY, szOID, 0);
    if (pCryptOidInfo)
        _tprintf (TEXT(" (\"%ls\")"), pCryptOidInfo->pwszName);
    else
        _tprintf (TEXT(" (Unknown OID)"));
}

int main()
{
    BOOL bIsSuccess;
    DWORD cbEncoded = 0;
    PBYTE pbyData = NULL;
    BYTE byData[] = {0x2a, 0x86, 0x48, 0x83, 0xf6, 0x8d, 0x01, 0x01, 0x01};
    BYTE byData2[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01};
    LPSTR pszOid = "1.2.840.113549.1.1.1";
    DumpOID (0, byData, sizeof(byData));
    _tprintf (TEXT("\n"));
    DumpOID (0, byData2, sizeof(byData2));
    _tprintf (TEXT("\n"));

    bIsSuccess = CryptEncodeObjectEx (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
                                      X509_OBJECT_IDENTIFIER,
                                      (const void *)&pszOid,
                                      CRYPT_ENCODE_ALLOC_FLAG,
                                      NULL,
                                      &pbyData,
                                      &cbEncoded);
    if (bIsSuccess) {
        HexDump (pbyData, cbEncoded);
        _tprintf (TEXT("\n"));
        pbyData = (PBYTE) LocalFree (pbyData);
    }

    return 0;
}

程序产生以下输出06 09 2A 86 48 86 F7 0D 01 01 01,其中BER编码的第一个字节0x06表示OID数据类型,下一个字节0x09表示数据长度,接下来的9个字节2A 86 48 86 F7 0D 01 01 01是编码的OID 1.2 .840.113549.1.1.1。

该程序的完整输出是

1.2.840.8226433.1.1 (Unknown OID)
1.2.840.113549.1.1.1 ("RSA")
06 09 2A 86 48 86 F7 0D 01 01 01

答案 1 :(得分:2)

您已经解释了如何转换0到65536(0xFFFF)之间的值。

你能解释一下你对更高值的计算吗?像113549?

答案 2 :(得分:1)

我终于明白了。谢谢。我写了RSA编码的序列。 (当RSADSI为113549时)

113549是1bb8d(Hexa)

作为二进制格式,1bb8d是0001 1011 1011 1000 1001。

是7位编码,表示为

00 0110 | 111 0111 | 000 1001

=&GT; 0x06 | 0x77 | 0X0D

=&GT; 0×06 + 0x80的| 0x77 0x80的+ | 0X0D

=&GT; 0x86 0xf7 0x0d

====================================

0x86 | 0xf7 | 0X0D

答案 3 :(得分:0)

00

Hexa:113549

二进制:1bb8d

第1步:使用0001 1011 1011 1000 1101位创建组:

7

第2步:*0*0001 10 |11 1011 1 |000 1101位添加额外位(8仅添加到最右边的字节中,0添加到所有其他字节中):

1

第3步:将二进制转换为十六进制:

*1*000 0110 | *1*111 0111 | *0*000 1101