Использование OpenSSL для генерации пар ключей - PullRequest
2 голосов
/ 18 марта 2019

Я использую delphiopenssl wrapper для генерации файлов ключей формата .pem.Я использую Пример генерации ключа RSA для генерации этих ключей.

Что мне нужно

Два дня назад я надеялся найти простойспособ генерировать ключи RSA и использовать их для шифрования / дешифрования некоторых строк или буфера TBytes.Теперь, после поиска каждого возможного решения, я решил использовать OpenSSL для выполнения работы

Моя проблема

Дело в том, что я не могу создать файлы с введенным именем файла для функции.Но я все еще получаю файл с именем «C» или «m» (без расширения), который содержит открытый и закрытый ключи вместе в формате PEM, и что более странно, я даю функции два имени файла для открытого и закрытого ключа

Что я пробовал

  • Я искал документацию для используемых методов openssl, так что я знаю, как отладить это, но безуспешно.
  • Я попытался использовать командную строку Openssl.exe, чтобы сделать то же самое, и это сработало, поэтому я знаю, что это не ошибка в openssl.
  • сначала я не смог скомпилировать код из-за [dcc32 Error] CryptoUtils.pas(399): E2010 Incompatible types: 'PAnsiChar' and 'PWideChar' иМое решение состояло в том, чтобы набрать приведение к PAnsiChar там, где это необходимо, и убедиться, что все входные данные не совпадают, поэтому я мог попробовать не Unicode-тест, но без успеха.вызов функции, где я получаю 0 в результате (в расплывчатых документах 0 означает успех), но я всегда получаю один и тот же результат (имя файла C или M в выходном каталоге).
  • Я пытался посмотретьдля другогоРеализации на других языках с документацией, но опять-таки нет верного решения, которое каждый волшебным образом решил без проблем

этот код отвечает

procedure GenerateKeyPair;
var
  kp: TKeyPairGenerator;
begin
kp := TKeyPairGenerator.Create;
kp.KeyFileNames(GetCurrentDir + '\mykeys');  // it create a pair c:\temp\mykeys.key
                                    // and c:\temp\mykeys.pub
kp.Password := 'mypasswd';          // Required
kp.GenerateRSA;
end;


procedure TMainForm.Button2Click(Sender: TObject);
begin
  InitOpenSSL;

  GenerateKeyPair;

  FreeOpenSSL;
end;

function TKeyPairGenerator.GenerateRSA: Integer;
var
  rsa: pRSA;
  PrivateKeyOut, PublicKeyOut, ErrMsg: pBIO;
  buff: array [0..1023] of char;
  enc: pEVP_CIPHER;

begin

Result := 0;

if (fPrivateKeyFile = '') or (fPublicKeyFile = '') then
  raise EOpenSSL.Create('Key filenames must be specified.');
if (fPassword = '') then
  raise EOpenSSL.Create('A password must be specified.');

ERR_load_crypto_strings;
OpenSSL_add_all_ciphers;

enc := EVP_des_ede3_cbc; ///??????

// Load a pseudo random file
RAND_load_file(PAnsiChar(fSeedFile), -1);

rsa := RSA_generate_key(fKeyLength, RSA_F4, nil, ErrMsg);
if rsa=nil then
  begin
  BIO_reset(ErrMsg);
  BIO_read(ErrMsg, @buff, 1024);
  raise EOpenSSL.Create(PChar(@buff));
  end;

PrivateKeyOut := BIO_new(BIO_s_file());
if BIO_write_filename(PrivateKeyOut, PAnsiChar(fPrivateKeyFile)) <> 0 then Result := - 1; // I get a 1 here meaning failure whit out any useful info
PublicKeyOut := BIO_new(BIO_s_file());
if BIO_write_filename(PublicKeyOut, PAnsiChar(fPublicKeyFile)) <> 0 then Result := ERR_peek_last_error; // ERR_peek_last_error returns 0

PEM_write_bio_RSAPrivateKey(PrivateKeyOut, rsa, enc, nil, 0, nil, PChar(fPassword));
PEM_write_bio_RSAPublicKey(PublicKeyOut, rsa);

if rsa <> nil then RSA_free(rsa);
if PrivateKeyOut <> nil then BIO_free_all(PrivateKeyOut);
if PublicKeyOut <> nil then BIO_free_all(PublicKeyOut);
end;

и это содержимое файлаnamed C

-----BEGIN RSA PUBLIC KEY-----
MIIBBgKB/gC1aSSL+rlH/owIISeoNNO9mVmlPfWVsnRloFUHlYQMZyVovcTHZZhd
CvweTjMlwRHTqNAnX3CpFSwjcf5FVyiB7qoWQHDXlTSLD4kFQzUfGVTorwuB1jii
Su3tt3GCJE//xE5RWrsAIETuxIk2ZSkf4T0htAu44gBbup7CT4cSOaUeTr6/D9WL
xl+jGCi9d4oG+JkVJ21VHl1O5/UG4HRKiKx+PfNrBZvR4COVzYV6clXv7fd2EZo7
Gbz/d3yUG9jVMuQmbSDA0Ew3vE9iYTIpXeGSM1aZKgkOWqehO7b8yIqhmUbW2Yl5
sydL/xx7WEsQuTqvPST1lkpfdyIpAgMBAAE=
-----END RSA PUBLIC KEY-----
xng1PPL79FUIjo1i3Fjg1qagYELOy023nnekp9ZzgPrVsuZT4fnXTaqFHoOjhTr
IqhHVMsaUIxG0OOdmkDZzWbHjlJbA3BpNvB0NqSlb8vQrg+d9Tq4wh4heKNl/Wim
IocSUi3qULEC29H2rA2VnutilcpDTcc4fiKwWlAnYGOQieVHMnNGP+RrCqjIzurN
M4aTK7mRna3OGYOZBl89xDd9elmYtToFrb/aVEgE2FY3190AosRyb/9bjR+ol39Y
XrtXKAPOwGum6O9Vc5jTAw6wC6OTpCTZXw6NuIm6WST0u5Aknvc0mGEx/w8yYxil
fJvavRADkWIBYLvWj5tzm2pOeT3C1SoCqtEwmpK4eZpR+TeODsje4blaGIeIMtOl
BOnGZSy8KLk36kH2mT6pO3/QHNK7yZEhyd9uw7Hol8pFk8ZrCPu25vju8UnC0/k6
djExrjl2+V/EGeO8k79W2kpHjIIcY5SG+hNI909j/OIwJH8UJCmQrSPaxSloUquy
upQPhPhaz1UKrZJw/u7oKHzeYPFI9NmWBbz18Iax52wsmHaw/mqwt8h96wUujVB2
CWG0IfW+LF7r6rZ6wREW72ldMLiKpGAucbaGBpGKbMLpbai9BTmkpdtpi/PH7yOG
8/gS2Av6VvD2wzdNt94Zqqlz+qN3K/t4qIjOIBHSpCcm7DJLQWK452xheZpiYlP0
hBAX7V9WvnQcuhfiX0zm097dmqcjySzpKL53T7dk3dNoHsbPPzKrS/WDMvGZLMwF
4hifva+O3lnI/DlBZymcPNlPNwTTztDDWxFwv2Y9jq20yXbJLjEP1Qjpk+oS9dVh
HTTun0ZkrfzVaXcfcWggKWrpiTIen2jCqqVSMyS0xe4h9v+/gjkMA54OzN+zPyIH
zpgRmHxVIXYQ+AuK1zEf6lZaeeUiKWG4ywpgML3X4Ln5SWNZA0iLYQKr98XDn3VJ
WoVA1sVqsi2cuq+9Td2Z9TbD4FCxZlrrOZCN5x+YaMjp+KzFA5m+7rEvS96Z+Kit
Pw1mZkrQ2QioXOmkDiqypFk08Z8BiPIb+hklXrrD7Vkp3VdMO9UQpKppfZFMQ0mG
6OGcf51kBKtfEPcHEBkQM/sPw5H4zC+pRaxBseL/5Fzcq/B5ywPzEjMfQc4sjpTi
uFZFA9rVzikCOEv1R8MPrdiFKzrBv7xR1SjA+W8DeTJaeXmHRTzT75rovvH2GUvP
RUMyGKfp1MXIFzyU5FA4xgPVPve2K/+P
-----END RSA PRIVATE KEY-----

Мой вопрос , как решить эту проблему или есть какие-либо документы по поводу этих методов, которые я могу прочитать.

OpenSSL версия 1.0.2 из Indyсервера.

Примечание: Я отправил запрос на добавление функции ( System.Cryptography ), которому интересно голосовать за дело

Ответы [ 2 ]

2 голосов
/ 19 марта 2019

Это мое решение рассматриваемой проблемы

Проблема: Создайте пары ключей RSA (общедоступные / частные), а затем прочитайте их из файла, потока или даже TBytes буфер.

Найденные решения:

  • Первое, что вы можете найти (Google), это Turbo Pack LockBox для Delphiно проблема в том, что он не поддерживает более 1048 битных размеров ключей (на момент написания), что намного ниже текущего минимального размера ключа (2048 на момент написания), так что вы можете опустить это из возможных решений (хотя этоимеет встроенную реализацию того, что мне нужно).
  • Оболочка для CryptoAPI.Идея прекрасна, потому что у вас есть возможность использовать собственную Crypto Library от Microsoft, которая облегчит ее развертывание (поскольку она встроена в саму ОС).Тем не менее, Pascal практически не поддерживается (он написан на c ++) и потребует огромных усилий для поддержки и поддержки, и он не является кроссплатформенным.
  • Оболочка для OpenSSl.Теперь это отличная идея, потому что библиотека уже используется одним из великих проектов с открытым исходным кодом Indy и поиск других проектов с открытым исходным кодом будет иметь больше шансов на успех

    1. zizzo81 / delphiopenssl имеет свою собственную оболочку для OpenSSL и замечательных демонстраций, но, как говорится в вопросе, в этом исходном коде есть проблема или две, и я не смог опубликовать проблему на GitHub по одной уважительной причине, проект не поддерживаетсяи это только импортированная версия со старого сайта.
    2. lminuti / Delphi-OpenSSL основана на Indy Wrappers IdSSLOpenSSLHeaders.pas и предоставляет основные функции для этой проблемы (шифрование / дешифрование, но негенерировать).

Окончательное решение:

в конце мне нужно было добавить что-то в lminuti / Delphi-OpenSSL за его завершение и спасибо за allen-drennan , ответ на этот вопрос был очень легким.

Я тоже раздвоил the lminuti / Delphi-OpenSSL , чтобы представить изменения, относящиеся к этому вопросу (форк содержит готовое к использованию руководство по этой проблеме)

Ошибки, которые я нашел и исправил текущийОболочка в базовом проекте использует PEM_read_bio_PubKey для чтения файлов с открытым ключом в традиционных форматах PEM (что больше не является стандартом), а также PEM_write_bio_RSAPrivateKey , который также устарел (я не исправилна данный момент)

Ссылки, которые я нашел полезными:

2 голосов
/ 19 марта 2019

Вместо этого я обычно создаю открытый и закрытый ключи отдельно, используя API-интерфейсы PEM_write_bio_ * для создания TBytes. Когда у вас есть TBytes для открытого и закрытого ключа, вы можете использовать Delphi TFile.WriteAllBytes () в модуле System.IOUtils, чтобы сохранить TBytes в файл.

function CreateCertificate_PKCS(out APublicKey, APrivateKey: TBytes): Boolean;
var
  Bignum: PBIGNUM;
  RSA: PRSA;
  PrivateKey, PublicKey: PBIO;
  KeyLength: Integer;
begin
  Result := False;
  Bignum := BN_new();
  try
    if BN_set_word(Bignum, RSA_F4) = 1 then
    begin
      RSA := RSA_new;
      try
        if RSA_generate_key_ex(RSA, 2048, Bignum, nil) = 1 then
        begin
          { Write the public key }
          PublicKey := BIO_new(BIO_s_mem);
          try
            PEM_write_bio_RSAPublicKey(PublicKey, RSA);
            KeyLength := BIO_pending(PublicKey);
            SetLength(APublicKey, KeyLength);
            BIO_read(PublicKey, @APublicKey[0], KeyLength);
          finally
            BIO_free(PublicKey);
          end;

          { Write the private key }
          PrivateKey := BIO_new(BIO_s_mem);
          try
            PEM_write_bio_RSAPrivateKey(PrivateKey, RSA, nil, nil, 0, nil, nil);
            KeyLength := BIO_pending(PrivateKey);
            SetLength(APrivateKey, KeyLength);
            BIO_read(PrivateKey, @APrivateKey[0], KeyLength);
          finally
            BIO_free(PrivateKey);
          end;

          Result := True;
        end;
      finally
        RSA_free(RSA);
      end;
    end;
  finally
    BN_free(Bignum);
  end;
end;
...