是否有任何 [非特定于编程语言的] 方法来获取对象标识符的十六进制版本?
前任:
OID 1.2.840.10040.4.1:dsa
十六进制字符串 = 2a 86 48 ce 38 04 01
他们似乎没有一个易于访问的列表。我正在寻找 X509 证书中使用的 OID
是否有任何 [非特定于编程语言的] 方法来获取对象标识符的十六进制版本?
前任:
OID 1.2.840.10040.4.1:dsa
十六进制字符串 = 2a 86 48 ce 38 04 01
他们似乎没有一个易于访问的列表。我正在寻找 X509 证书中使用的 OID
您可以使用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
您已经解释了如何对 0 到 65536 (0xFFFF) 之间的值进行转换。
你能解释一下你对更高值的计算吗?喜欢 113549 吗?
我终于明白了。谢谢你。我写了 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
为了113549
六边形:1bb8d
二进制:0001 1011 1011 1000 1101
第 1 步:7
使用位创建组:
*0*0001 10 |11 1011 1 |000 1101
第 2 步:为位添加额外位8
(0
仅添加到最右边的字节并1
添加到所有其他字节):
*1*000 0110 | *1*111 0111 | *0*000 1101
Step3:将二进制转换为十六进制:
0x86 | 0xf7 | 0x0d