Reputation: 2591
I'm using delphiopenssl wrapper to generate .pem format key files. I'm using Generate RSA Key example to generate these keys.
What I need
Two days ago I was hoping to find a simple way to generate RSA keys and use them to encrypt/dcrypt some strings or TBytes Buffer. Now after searching every possible solution I decided to use OpenSSL todo the job
My problem
the thing is I cant create the files with inputted file name to the function. But I still get a file named 'C' or 'm' (without an extension) that contains the public and private key together in PEM format and what is weirder is I'm giving the function two file names for Public and Private key
What I tried
[dcc32 Error] CryptoUtils.pas(399): E2010 Incompatible types: 'PAnsiChar' and 'PWideChar'
and my solution was to type cast to PAnsiChar
where needed and made sure that all input is ansistring so I could try a non Unicode test but with no success.this the code responsible
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;
and this is the content of the file 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-----
My question how to solve this or Is there any docs about those methods I can read .
OpenSSL version 1.0.2 from Indy servers.
Side note: I submitted a feature request (System.Cryptography) for whom interested to vote for the cause
Upvotes: 4
Views: 2024
Reputation: 2591
This is my solution to the problem in question
The problem: Generate an RSA Key Pairs (public/private) and then read them from file, stream or even a TBytes
buffer.
Solutions Found:
a Wrapper for OpenSSl. Now that is an awesome Idea because the library is already used by one of the great open source projects Indy and searching for other open source projects would have higher possibility of success
Finale Solution:
at the end I needed to add something to lminuti/Delphi-OpenSSL for it to be completed and thanks for allen-drennan answer to this question it was very easy.
I also forked the lminuti/Delphi-OpenSSL to present the changes concerned by this question (the fork contains a ready to use tutorial for this problem)
Bugs I found and fixed the current wrapper in the base project uses PEM_read_bio_PubKey to read Public key files in Traditional PEM formats (which is not the standard anymore) also it uses PEM_write_bio_RSAPrivateKey which is deprecated as well (I did not fix this for the moment)
References I found useful:
Upvotes: 3
Reputation: 291
I instead, usually create the public and private key separately using PEM_write_bio_* APIs to create TBytes. Once you have the TBytes for the public and private key you can use Delphi's TFile.WriteAllBytes() in the System.IOUtils unit to save the TBytes to a file.
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;
Upvotes: 3