- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要使用 Windows 的 Cryptography API: Next Generation 验证消息的签名.我有消息、它的签名和 PEM 格式的公钥,以及展示所需行为的原型(prototype)实现。
我需要修复的代码有一个问题:将公钥转换为 CNG 使用的 key blob。
目前,我正在解码公钥
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETHfi8foQF4UtSNVxSFxeu7W+gMxd
SGElhdo7825SD3Lyb+Sqh4G6Kra0ro1BdrM6Qx+hsUx4Qwdby7QY0pzxyA==
-----END PUBLIC KEY-----
使用 CryptStringToBinaryA
,它产生以下二进制数据:
30 59 30 13 06 07 2A 86 48 CE 3D 02 01 06 08 2A
86 48 CE 3D 03 01 07 03 42 00 04 4C 77 E2 F1 FA
10 17 85 2D 48 D5 71 48 5C 5E BB B5 BE 80 CC 5D
48 61 25 85 DA 3B F3 6E 52 0F 72 F2 6F E4 AA 87
81 BA 2A B6 B4 AE 8D 41 76 B3 3A 43 1F A1 B1 4C
78 43 07 5B CB B4 18 D2 9C F1 C8
一切看起来都很好。据推测,这是 DER 格式,使用 ASN.1。它的大小为 91 字节,指定椭圆曲线密码术 (ECDSA prime256v1
),其中 [x]
和 [y]
条目从偏移量 27 (每个总共 32 个字节)。
因为我需要一个 key blob 传递给 BCryptImportKeyPair ,特别是 BCRYPT_ECCKEY_BLOB
:
typedef struct _BCRYPT_ECCKEY_BLOB
{
ULONG dwMagic;
ULONG cbKey;
} BCRYPT_ECCKEY_BLOB, *PBCRYPT_ECCKEY_BLOB;
我的原型(prototype)通过提供 BCRYPT_ECDSA_PUBLIC_P256_MAGIC
和长度 32,后跟来自上面公钥的相应 64 字节,创建了一个临时的。
现在可行了,但我显然想要实现更强大的功能。该 key 似乎对填充适当的 CNG key blob 所需的所有数据进行了编码,但我找不到任何可帮助我解析此信息的 API。
CNG(或 Wincrypt)是否提供任何允许我构建 CNG key blob 或以其他方式从 PEM key 中获取 BCRYPT_KEY_HANDLE
的功能?还是我只能实现自己的 ASN.1 解析器?
最佳答案
将 PEM 公钥转换为 CNG - 接下来是通用步骤:
CryptStringToBinaryA
用于将字符串转换为二进制CryptDecodeObjectEx
和 X509_PUBLIC_KEY_INFO
- 转换二进制到 CERT_PUBLIC_KEY_INFO
CryptImportPublicKeyInfoEx2
- 将 CERT_PUBLIC_KEY_INFO
导入到 CNG代码示例
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG PemToCNG(_In_ PCSTR pszString, _Out_ BCRYPT_KEY_HANDLE* phKey)
{
PBYTE pb = 0;
ULONG cb = 0;
ULONG dwError;
while (NOERROR == (dwError = BOOL_TO_ERROR(
CryptStringToBinaryA(pszString, 0, CRYPT_STRING_BASE64_ANY, pb, &cb, 0, 0))))
{
if (pb)
{
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
if (NOERROR == (dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
X509_PUBLIC_KEY_INFO, pb, cb,
CRYPT_DECODE_ALLOC_FLAG|
CRYPT_DECODE_NOCOPY_FLAG|
CRYPT_DECODE_SHARE_OID_STRING_FLAG,
0, &PublicKeyInfo, &cb))))
{
dwError = BOOL_TO_ERROR(CryptImportPublicKeyInfoEx2(
X509_ASN_ENCODING, PublicKeyInfo, 0, 0, phKey));
LocalFree(PublicKeyInfo);
}
break;
}
if (!(pb = (PBYTE)LocalAlloc(0, cb)))
{
dwError = GetLastError();
break;
}
}
if (pb)
{
LocalFree(pb);
}
return dwError;
}
void TestPem()
{
static const char Pem[] =
"-----BEGIN PUBLIC KEY-----\r\n"
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETHfi8foQF4UtSNVxSFxeu7W+gMxd\r\n"
"SGElhdo7825SD3Lyb+Sqh4G6Kra0ro1BdrM6Qx+hsUx4Qwdby7QY0pzxyA==\r\n"
"-----END PUBLIC KEY-----";
BCRYPT_KEY_HANDLE hKey;
if (NOERROR == PemToCNG(Pem, &hKey))
{
PBYTE pb = 0;
ULONG cb = 0;
while (0 <= BCryptExportKey(hKey, 0, BCRYPT_PUBLIC_KEY_BLOB, pb, cb, &cb, 0))
{
if (pb)
{
PSTR psz = 0;
ULONG cch = 0;
while (CryptBinaryToStringA(pb, cb, CRYPT_STRING_HEXASCII, psz, &cch))
{
if (psz)
{
DbgPrint(psz);
break;
}
psz = (PSTR)alloca(cch * sizeof(char));
}
break;
}
pb = (PBYTE)alloca(cb);
}
BCryptDestroyKey(hKey);
}
}
输出是
45 43 53 31 20 00 00 00 4c 77 e2 f1 fa 10 17 85 ECS1 ...Lw......
2d 48 d5 71 48 5c 5e bb b5 be 80 cc 5d 48 61 25 -H.qH\^.....]Ha
85 da 3b f3 6e 52 0f 72 f2 6f e4 aa 87 81 ba 2a ..;.nR.r.o.....*
b6 b4 ae 8d 41 76 b3 3a 43 1f a1 b1 4c 78 43 07 ....Av.:C...LxC.
5b cb b4 18 d2 9c f1 c8 [.......
关于c++ - 如何将 PEM 格式的公钥转换为 CNG key blob?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68373965/
我是一名优秀的程序员,十分优秀!