如何解决如何使用CryptoApi导入PKCS#8
我有一个PKCS#8密钥,我拼命尝试导入CryptoAPI,但没有成功。我有:
-----BEGIN PRIVATE KEY-----
<privatekey>
-----END PRIVATE KEY-----
包含以下内容:
Private Key algo RSA
Private Format PKCS#8
ASN1 Dump
RSA Private CRT Key [.....]
modulus: .....
public exponent: .....
我尝试这样导入密钥:
if not CryptStringToBinaryA(
PansiChar(aBase64PrivateKey),// pszString: LPCSTR;
length(aBase64PrivateKey),// cchString: DWORD;
CRYPT_STRING_BASE64HEADER,// dwFlags: DWORD;
nil,// pbBinary: pByte;
@cbPrivKey,// pcbBinary: PDWORD;
nil,// pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
setlength(pPrivKey,cbPrivKey);
if not CryptStringToBinaryA(
PansiChar(aBase64PrivateKey),// dwFlags: DWORD;
@pPrivKey[0],// pdwSkip: PDWORD;
nil) then raiseLastOsError; // pdwFlags: PDWORD
//init pKeyBlob
if not CryptDecodeObjectEx(
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,// dwCertEncodingType: DWORD;
PKCS_PRIVATE_KEY_INFO,// lpszStructType: LPCSTR;
@pPrivKey[0],// const pbEncoded: PBYTE;
cbPrivKey,// cbEncoded: DWORD;
0,// pDecodePara: PCRYPT_DECODE_PARA;
nil,// pvStructInfo: Pointer;
@cbKeyBlob) then raiseLastOsError; // pcbStructInfo: PDWORD
setlength(pKeyBlob,cbKeyBlob);
if not CryptDecodeObjectEx(
X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,// pDecodePara: PCRYPT_DECODE_PARA;
@pKeyBlob[0],// pvStructInfo: Pointer;
@cbKeyBlob) then raiseLastOsError; // pcbStructInfo: PDWORD
//acquire a handle to a particular key container
if (not CryptAcquireContextA(@hProv,// phProv: PHCRYPTPROV;
nil,// pszContainer: PAnsiChar;
nil,// pszProvider: PAnsiChar;
PROV_RSA_AES,// dwProvType: DWORD;
CRYPT_VERIFYCONTEXT)) then raiselastOsError; // dwFlags: DWORD
try
// Now import the key.
if not CryptImportKey(hProv,// hProv: HCRYPTPROV;
@pKeyBlob[0],// const pbData: PBYTE;
cbKeyBlob,// dwDataLen: DWORD;
0,// hPubKey: HCRYPTKEY;
0,// dwFlags: DWORD;
@hRSAKey) then raiseLastOsError; // phKey: PHCRYPTKEY
但是CryptImportKey
失败,并出现“提供程序的版本错误” ,我想是因为它正在等待PKCS#1密钥。如何导入 PKCS#8 密钥?
解决方法
要将 PKCS#8 格式转换为 legacy 或 CNG 加密api需要几个步骤。
首先需要使用CryptStringToBinaryA
通过CRYPT_STRING_BASE64HEADER
将字符串转换为二进制
比用PKCS_PRIVATE_KEY_INFO
调用CryptDecodeObjectEx
(如果加密的私钥需要使用PKCS_ENCRYPTED_PRIVATE_KEY_INFO
)
再次需要使用CryptDecodeObjectEx
来调用PKCS_RSA_PRIVATE_KEY
(对于旧版加密api,而对于{em> CNG )则是CNG_RSA_PUBLIC_KEY_BLOB
。
现在我们可以致电BCryptImportKeyPair
或CryptImportKey
对于导入公共密钥,需要使用X509_PUBLIC_KEY_INFO
,对于来自cert的公共密钥-X509_CERT_TO_BE_SIGNED
(对于 CNG ,+ CNG_RSA_PUBLIC_KEY_BLOB
,对于旧版可以使用{{1 }})
用code表示旧版
CryptImportPublicKeyInfo
code for CNG
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
ULONG CryptImportPublicKey(_Out_ HCRYPTKEY *phKey,_In_ HCRYPTPROV hProv,_In_ PCUCHAR pbKeyOrCert,_In_ ULONG cbKeyOrCert,_In_ bool bCert)
{
ULONG cb;
union {
PVOID pvStructInfo;
PCERT_INFO pCertInfo;
PCERT_PUBLIC_KEY_INFO PublicKeyInfo;
};
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,bCert ? X509_CERT_TO_BE_SIGNED : X509_PUBLIC_KEY_INFO,pbKeyOrCert,cbKeyOrCert,CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG,&pvStructInfo,&cb));
if (dwError == NOERROR)
{
PVOID pv = pvStructInfo;
if (bCert)
{
PublicKeyInfo = &pCertInfo->SubjectPublicKeyInfo;
}
dwError = BOOL_TO_ERROR(CryptImportPublicKeyInfo(hProv,X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,PublicKeyInfo,phKey));
LocalFree(pv);
}
return dwError;
}
ULONG CryptImportPrivateKey(_Out_ HCRYPTKEY* phKey,_In_ PCUCHAR pbKey,_In_ ULONG cbKey)
{
ULONG cb;
PCRYPT_PRIVATE_KEY_INFO PrivateKeyInfo;
ULONG dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,PKCS_PRIVATE_KEY_INFO,pbKey,cbKey,(void**)&PrivateKeyInfo,&cb));
if (dwError == NOERROR)
{
PUBLICKEYSTRUC* ppks;
dwError = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,PKCS_RSA_PRIVATE_KEY,PrivateKeyInfo->PrivateKey.pbData,PrivateKeyInfo->PrivateKey.cbData,CRYPT_DECODE_ALLOC_FLAG,(void**)&ppks,&cb));
LocalFree(PrivateKeyInfo);
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(CryptImportKey(hProv,(PUCHAR)ppks,cb,CRYPT_EXPORTABLE,phKey));
LocalFree(ppks);
}
}
return dwError;
}
enum BLOB_TYPE { bt_priv,bt_pub,bt_cert };
ULONG CryptImportKey(_Out_ HCRYPTKEY *phKey,_In_ BLOB_TYPE bt,_In_ PCSTR szKey,_In_ ULONG cchKey)
{
PUCHAR pbKey = 0;
ULONG cbKey = 0;
ULONG dwError;
while (CryptStringToBinaryA(szKey,cchKey,CRYPT_STRING_BASE64HEADER,&cbKey,0))
{
if (pbKey)
{
switch (bt)
{
case bt_priv:
dwError = CryptImportPrivateKey(phKey,hProv,cbKey);
break;
case bt_pub:
dwError = CryptImportPublicKey(phKey,false);
break;
case bt_cert:
dwError = CryptImportPublicKey(phKey,true);
break;
default: dwError = ERROR_INVALID_PARAMETER;
}
_freea(pbKey);
return dwError;
}
if (!(pbKey = (PUCHAR)_malloca(cbKey)))
{
break;
}
}
dwError = GetLastError();
if (pbKey) _freea(pbKey);
return dwError;
}
void DoLegacyTest(_In_ PCSTR szToBeSigned,_In_ PCSTR szPrivateKey,_In_ ULONG cchPrivateKey,_In_ PCSTR szPublicKeyOrCert,_In_ ULONG cchPublicKeyOrCert,_In_ bool bCert)
{
HCRYPTPROV hProv;
if (CryptAcquireContextW(&hProv,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,CRYPT_VERIFYCONTEXT))
{
HCRYPTKEY hKey;
HCRYPTHASH hHash;
if (CryptCreateHash(hProv,CALG_SHA_256,&hHash))
{
if (CryptHashData(hHash,(PUCHAR)szToBeSigned,(ULONG)strlen(szToBeSigned),0))
{
PUCHAR pbSignature = 0;
ULONG cbSignature = 0;
BOOL fOk = false;
if (NOERROR == CryptImportKey(&hKey,bt_priv,szPrivateKey,cchPrivateKey))
{
ULONG dwKeySpec,cb;
if (CryptGetKeyParam(hKey,KP_ALGID,(PUCHAR)&dwKeySpec,&(cb = sizeof(dwKeySpec)),0))
{
switch (dwKeySpec)
{
case CALG_RSA_KEYX:
dwKeySpec = AT_KEYEXCHANGE;
break;
case CALG_RSA_SIGN:
dwKeySpec = AT_SIGNATURE;
break;
default: dwKeySpec = 0;
}
if (CryptGetKeyParam(hKey,KP_BLOCKLEN,(PUCHAR)&cbSignature,&(cb = sizeof(cbSignature)),0))
{
pbSignature = (PUCHAR)alloca(cbSignature >>= 3);
fOk = CryptSignHashW(hHash,dwKeySpec,pbSignature,&cbSignature);
}
}
CryptDestroyKey(hKey);
}
if (fOk)
{
if (NOERROR == CryptImportKey(&hKey,bCert ? bt_cert : bt_pub,szPublicKeyOrCert,cchPublicKeyOrCert))
{
if (!CryptVerifySignatureW(hHash,cbSignature,hKey,0))
{
__debugbreak();
}
CryptDestroyKey(hKey);
}
}
}
CryptDestroyHash(hHash);
}
CryptReleaseContext(hProv,0);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。