是否有任何[非编程语言特定]方法来获取对象标识符的十六进制版本?
例如:
OID 1.2.840.10040.4.1:dsa
hex string = 2a 86 48 ce 38 04 01
似乎没有一个易于访问的列表。我正在寻找X509证书中使用的OID
答案 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