2

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

前任:

OID 1.2.840.10040.4.1:dsa

十六进制字符串 = 2a 86 48 ce 38 04 01

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

4

4 回答 4

6

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

在 OID 的情况下,编码和解码很简单,因此您可以手动执行此操作。

两个第一个数字 1.2 将使用一种特殊的方式进行编码。例如 xy 将被编码为 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
于 2010-08-03T23:59:29.237 回答
2

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

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

于 2012-03-24T23:07:44.860 回答
1

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

113549 是 1bb8d(Hexa)

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

它是7位编码,所以表示为

00 0110 | 111 0111 | 000 1001

=> 0x06 | 0x77 | 0x0d

=> 0x06+0x80|0x77+0x80|0x0d

=> 0x86 0xf7 0x0d

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

0x86 | 0xf7 | 0x0d

于 2013-07-12T05:32:21.190 回答
0

为了113549

六边形:1bb8d

二进制:0001 1011 1011 1000 1101

第 1 步:7使用位创建组:

*0*0001 10 |11 1011 1 |000 1101

第 2 步:为位添加额外位80仅添加到最右边的字节并1添加到所有其他字节):

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

Step3:将二进制转换为十六进制:

0x86 | 0xf7 | 0x0d

于 2015-11-05T16:46:05.777 回答