Вопрос пользователя заключается в том, как загрузить публичный ключ, сгенерированный с помощью OpenSSL, в формате RSA1024, для использования в CryptoAPI на платформе Windows, не прибегая к использованию Windows OpenSSL порт. Проблема заключается в ошибке NTE_BAD_DATA, возникающей при попытке импорта ключа с помощью функции CryptImportKey.
Описание проблемы
Пользователь сгенерировал публичный ключ с помощью OpenSSL и экспортировал его в файл формата .pem. Затем он попытался использовать функцию CryptImportKey для импорта ключа в формате, который соответствует структуре PUBLICKEYSTRUC. Однако, при попытке импорта ключа, функция вернула ошибку NTE_BAD_DATA. Это произошло из-за того, что данные из файла .pem содержали дополнительные метаданные, такие как BEGIN и END строки, которые не соответствуют формату, ожидаемому CryptoAPI.
Подтвержденный ответ
Для решения проблемы необходимо сначала декодировать BASE64 строку публичного ключа, полученную из файла .pem, и удалить метаданные, такие как BEGIN и END строки. После этого можно использовать функции CryptStringToBinary и CryptDecodeObjectEx для преобразования строки в формат, который может быть импортирован функцией CryptImportKey.
Альтернативный ответ
Альтернативный ответ предлагает использовать пример кода на C, который демонстрирует процесс декодирования файла .pem и импорта ключа в CryptoAPI. Этот пример можно перевести на язык Delphi, чтобы использовать в собственном проекте.
Пример кода на Object Pascal (Delphi)
program CryptImportPublicKey;
{$APPTYPE CONSOLE}
uses
System.SysUtils,
DCPhoenix.Crypt32,
System.Classes;
type
TPublicKeyBlob = record
FHeader: BLOBHEADER;
FKeyLength: DWORD;
FKey: array[0..4095] of Byte;
end;
TBlobHeader = record
bType: BYTE;
bVersion: BYTE;
reserved: DWORD;
aiKeyAlg: ALG_ID;
end;
TBlobHeaderHelper = helper for TBlobHeader
public
constructor Create: procedure;
function SizeOfBlob: DWORD;
end;
{ TBlobHeader }
constructor TBlobHeaderHelper.Create;
begin
bType := PLAINTEXTKEYBLOB;
bVersion := CUR_BLOB_VERSION;
reserved := 0;
aiKeyAlg := CALG_RSA_KEYX;
end;
function TBlobHeaderHelper.SizeOfBlob: DWORD;
begin
Result := SizeOf(TBlobHeader) + SizeOf(FKeyLength);
end;
var
CryptProv: HCryptProv;
PublicKeyBlob: TPublicKeyBlob;
PublicKeyStr: string;
KeyBlob: AnsiString;
HKey: HCRYPTKEY;
BufSize: DWORD;
Buf: Pointer;
begin
PublicKeyStr :=
'-----BEGIN PUBLIC KEY-----' +
'MIGfMA0GCSqGSIb3DQE...' +
'-----END PUBLIC KEY-----';
// Удаляем метаданные из строки ключа
PublicKeyStr := Copy(PublicKeyStr, 24, Length(PublicKeyStr) - 24 - 12);
// Декодируем строку в бинарный формат
BufSize := Length(PublicKeyStr) * SizeOf(AnsiChar);
GetMem(Buf, BufSize);
try
// Декодируем строку Base64 в бинарные данные
if not CryptStringToBinary(PChar(PublicKeyStr), Length(PublicKeyStr), CRYPT_ENCODED | CRYPT_STRING_ANYBASE64, Buf, BufSize, nil, nil) then
RaiseLastOSError;
// Проверяем, достаточно ли памяти было выделено
if BufSize < SizeOf(TBlobHeader) + SizeOf(FKeyLength) then
RaiseLastOSError;
// Заполняем заголовок BLOB
with TBlobHeaderHelper(PublicKeyBlob.FHeader) do
Create;
// Записываем длину ключа
PublicKeyBlob.FKeyLength := BufSize - SizeOf(TBlobHeader) - SizeOf(FKeyLength);
// Копируем бинарные данные в структуру BLOB
Move(PtrAdd(Buf, SizeOf(TBlobHeader) + SizeOf(FKeyLength)), PublicKeyBlob.FKey[0], PublicKeyBlob.FKeyLength);
// Получаем контекст криптопровайдера
if not CryptAcquireContext(@CryptProv, nil, nil, PROV_RSA_FULL, 0) then
RaiseLastOSError;
try
// Импортируем ключ
if not CryptImportKey(CryptProv, @PublicKeyBlob, PublicKeyBlob.SizeOfBlob + PublicKeyBlob.FKeyLength, 0, 0, @HKey) then
RaiseLastOSError;
// Здесь можно продолжить работу с ключом
// ...
finally
// Освобождаем контекст криптопровайдера
CryptReleaseContext(CryptProv, 0);
end;
finally
FreeMem(Buf, BufSize);
end;
end.
end.
Заключение
Для успешной загрузки публичного ключа в CryptoAPI необходимо выполнить следующие шаги:
1. Удалить метаданные из строки ключа (например, BEGIN и END строки).
2. Декодировать строку в бинарный формат с помощью CryptStringToBinary.
3. Сформировать структуру PUBLICKEYSTRUC с использованием декодированных данных.
4. Импортировать ключ в CryptoAPI с помощью CryptImportKey.
Следуя этим шагам, вы сможете успешно загрузить публичный ключ RSA1024 и использовать его для верификации подписей в Windows.
Пользователь столкнулся с проблемой загрузки публичного ключа RSA1024 в формате, сгенерированного с помощью OpenSSL, в CryptoAPI для использования в приложении на Delphi, и пытается решить возникшую ошибку `NTE_BAD_DATA`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.