gpt4 book ai didi

delphi - 如何使用 CryptoAPI 加载 OpenSSL 生成的 RSA1024 纯文本公钥?

转载 作者:行者123 更新时间:2023-12-02 11:50:47 25 4
gpt4 key购买 nike

我使用 OpenSSL 使用以下命令生成了公钥,以创建 1024 位 RSA key ,然后导出公钥,从而在 .pem 文件中提供公钥。

> openssl genrsa -out private_key.pem 1024
> openssl rsa -pubout -in private_key.pem -out public_key.pem

我正在使用私钥在 PHP 中签署一些数据,并希望使用 CryptoAPI 在 Windows 中验证签名。如果可能的话,我不想链接到 Windows OpenSSL 端口。

公钥是文本格式。如何成功加载它并使用它来验证签名?

当前方法

我正在尝试使用 CryptImportKey 导入格式如下的公钥 blob:

  • PUBLICKEYSTRUC
  • 以下字节数组的大小,DWORD
  • 作为字节数组的键(窄/ANSI 字符串)

采用压缩结构。

key 字节数组只是公钥 .pem 文件的内容,包括 BEGIN 和 END 语句,作为 ANSI(非 Unicode)字符串。请注意,我使用的是 Unicode 应用程序,但加密 API 似乎没有 ANSI/Unicode 版本。 (是吗?)

当我执行此操作时,CryptImportKey 失败,GetLastError 的值为 0x80090005NTE_BAD_DATA。我不知道为什么这是......因此问题:)

代码

公钥 blob 结构定义为:

TPublicKeyBlob = packed record
strict private
FHeader : BLOBHEADER;
FKeyLength : DWORD;
FKey : array[0..4095] of Byte;
public
procedure Init(const KeyStr : string);
function Size : DWORD;
end;

方法有:

procedure TPublicKeyBlob.Init(const KeyStr: string);
var
KeyAnsi : AnsiString;
begin
KeyAnsi := AnsiString(KeyStr);
if Length(KeyAnsi) > Length(FKey) then
raise Exception.Create('Key too long');

FHeader.bType := PLAINTEXTKEYBLOB;
FHeader.bVersion := CUR_BLOB_VERSION;
FHeader.reserved := 0;
FHeader.aiKeyAlg := CALG_RSA_KEYX;

FKeyLength := Length(KeyAnsi) * sizeof(KeyAnsi[1]);
assert(sizeof(KeyAnsi[1]) = 1); // Should be single byte strings!

Move(KeyAnsi[1], FKey[0], Length(KeyAnsi) * sizeof(KeyAnsi[1]));
end;

function TPublicKeyBlob.Size: DWORD;
begin
// Return only the used size - not all the byte array will be used
Result := SizeOf(FHeader) + Sizeof(FKeyLength) + FKeyLength;
end;

这应该创建一个与 Microsoft Importing a Plaintext Key example 中的示例相匹配的内存布局。 。或许。 CALG_RSA_KEYX 对于 RSA 1024 位 key (或者更确切地说,生成的公钥)是否正确?我对 Move() 的使用正确吗? (应该类似于 memcpy,如果您是 C 程序员,但参数是 source、dest、size,并且字符串是 1 索引,但数组是 0 索引。) 应该 Size()返回整个结构的大小,还是仅返回键数组?

参数是字符串形式的公钥(如下)。

然后按如下方式使用:

function TLicenseInfo.VerifySignature: Boolean;
const
PublicKeyStr = '-----BEGIN PUBLIC KEY-----' +
'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeyh3x8qbGgq+ZlXm4erhjFMKY' +
'RGhAyFc8DUupkaLlSSzXDcHHC27VtuxAKtAVvm97OGJMbdbtAUy6rmVH0GSQmP+0' +
'Mct+7ncQRfpXJ4kAYg3gpv4dSsBl83rWDuQ06QDPjIT7eMdNMuUTm11GIYFnvyv4' +
'C9Vn92hBC2QeRRlslwIDAQAB' +
'-----END PUBLIC KEY-----';
var
hCryptProv, hHash: wcrypt2.HCRYPTPROV;
hKey: Cardinal;
PublicKeyBlob : TPublicKeyBlob;
begin
Result := False;

PublicKeyBlob.Init(PublicKeyStr);

if not CryptAcquireContext(@hCryptProv, 'Test', nil, PROV_RSA_FULL, 0) then
if not CryptAcquireContext(@hCryptProv, 'Test', nil, PROV_RSA_FULL, CRYPT_NEWKEYSET) then
Exit;

try
if CryptImportKey(hCryptProv, @PublicKeyBlob, PublicKeyBlob.Size, 0, 0, @hKey) then
// ^ this is the line that fails
begin
// ... check the signature.
end;
finally
CryptReleaseContext(hCryptProv, 0);
end;
end;

调用 CryptImportKey 的标记行失败,GetLastError 返回 0x80090005NTE_BAD_DATA

我已经尝试了很多变体 - 算法的一些变体,试验大小,删除 key 字符串的 BEGIN 和 END 部分等。但我不熟悉 Crypto API,而且我确保这对其他人来说是显而易见的:)

最佳答案

我很多年前(2012年)回答过类似的问题:https://stackoverflow.com/a/10827239/707093

基本上,你必须使用 CryptStringToBinary解码 BASE64 值,然后使用 CryptDecodeObjectExCryptImportKey 。显示如何执行此操作的 C 示例位于 https://www.idrix.fr/Root/Samples/capi_pem.cpp 。将其转换为 delphi 并不太困难。

我希望这会有所帮助。

关于delphi - 如何使用 CryptoAPI 加载 OpenSSL 生成的 RSA1024 纯文本公钥?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30970259/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com