Так и не удалось завести RSA в стандартном модуле, пришлось дергать ещё функции:
- Код: Выделить всё
uses
...
OpenSSL, dynlibs;
type
TPEM_write_bio_RSAPrivateKey = function(Pri: PBIO; KeyPair: PRSA;
var1, var2, var3, var4, var5: pointer): integer; cdecl;
TPEM_write_bio_RSAPublicKey = function(Pri: PBIO; KeyPair: PRSA): integer; cdecl;
...
var
PEM_write_bio_RSAPrivateKey: TPEM_write_bio_RSAPrivateKey;
PEM_write_bio_RSAPublicKey: TPEM_write_bio_RSAPublicKey;
implementation
{$R *.lfm}
procedure DoLoadOpenSSL;
var
hlib: TLibHandle;
begin
hlib := LoadLibrary(DLLSSLName + '.so');
PEM_write_bio_RSAPrivateKey :=
TPEM_write_bio_RSAPrivateKey(GetProcAddress(hlib, 'PEM_write_bio_RSAPrivateKey'));
if PEM_write_bio_RSAPrivateKey = nil then
ShowMessage('');
PEM_write_bio_RSAPublicKey :=
TPEM_write_bio_RSAPublicKey(GetProcAddress(hlib, 'PEM_write_bio_RSAPublicKey'));
if PEM_write_bio_RSAPublicKey = nil then
ShowMessage('');
end;
...
initialization
DoLoadOpenSSL;
end.
Дальше пошло чуть проще, генерация ключей:
- Код: Выделить всё
function GenRsaKeys(KeySize: integer; var PriKey: string; var PubKey: string): PRSA;
const
PUB_EXP = 3;
var
PriLen, PubLen: integer;
KeyPair: PRSA;
Pri: PBIO;
Pub: PBIO;
begin
KeyPair := RsaGenerateKey(KeySize, PUB_EXP, nil, nil);
Pri := BioNew(BioSMem);
Pub := BioNew(BioSMem);
PEM_write_bio_RSAPrivateKey(pri, keypair, nil, nil, nil, nil, nil);
PEM_write_bio_RSAPublicKey(pub, keypair);
Prilen := BioCtrlPending(pri);
Publen := BioCtrlPending(pub);
SetLength(PriKey, PriLen + 1);
SetLength(PubKey, PubLen + 1);
BioRead(pri, PriKey, PriLen);
BioRead(pub, PubKey, PubLen);
BioFreeAll(pub);
BioFreeAll(pri);
Result := keypair;
end;
Шифрование и расшифровка:
- Код: Выделить всё
function EncryptRsa(KeyPair: PRSA; var OrigMsg: PByte; LenMsg: integer;
var EncMsg: PByte; var EncLen: integer; var err: PChar): integer;
begin
EncLen := RSA_public_encrypt(LenMsg, OrigMsg, EncMsg, KeyPair, RSA_PKCS1_OAEP_PADDING);
if EncLen = -1 then
begin
ERR_load_crypto_strings();
Err_Error_String(ErrGetError(), err);
Result := 0;
end
else
Result := EncLen;
end;
function DecryptRsa(KeyPair: PRSA; var OrigMsg: PByte; var LenMsg: integer;
var EncMsg: PByte; var EncLen: integer; var err: PChar): integer;
begin
LenMsg := RSA_private_decrypt(EncLen, EncMsg, OrigMsg, KeyPair,
RSA_PKCS1_OAEP_PADDING);
if LenMsg = -1 then
begin
ERR_load_crypto_strings();
Err_Error_String(ErrGetError(), err);
Result := 0;
end
else
Result := LenMsg;
end;
Ну и тестовый код демонстрации шифровки и расшифровки:
- Код: Выделить всё
function GetHexTable(Buf: Pointer; iLen: integer): string;
var
i: integer;
begin
Result := '';
for i := 0 to iLen do
Result += IntToHex(integer(PByte(Buf + i)^), 2) + ', ';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
PriKey: string;
PubKey: string;
RSA: PRSA;
OrigMsg, EncMsg: PChar;
EncLen: integer;
err: PChar;
OrigLen: integer;
begin
Memo.Clear;
// Генерируем пару ключей
PubKey := '';
PriKey := '';
RSA := GenRsaKeys(512, PriKey, PubKey);
// Отображаем это в мемо
memo.Append(PriKey);
memo.Append('');
memo.Append(PubKey);
Memo.Append('');
// Выделяем память
Getmem(err, MAX_PATH);
Getmem(OrigMsg, MAX_PATH);
// Выводим оригинальное сообщение и закидываем это в буффер
Memo.Append('--- ORIG MSG ---');
Memo.Append('Hello World');
strcopy(PChar(OrigMsg), PChar('Hello World'));
OrigLen := strlen(OrigMsg);
// Получаем будущий размер закодированных данных
EncLen := RSA_size(RSA);
GetMem(EncMsg, EncLen);
// Кодируем данные
EncLen := EncryptRsa(RSA, PBYTE(OrigMsg), OrigLen, PByte(EncMsg), EncLen, err);
if EncLen = 0 then
ShowMessage(err);
// Выводим в HEX виде закодированные данные
Memo.Append('');
Memo.Append('--- ENCODED MESSAGE ---');
Memo.Append(GetHexTable(EncMsg, EncLen));
Memo.Append('');
// Перезаписывем буфер
Memo.Append('--- DESTROY BUFFER ---');
Memo.Append('Destroy data in buffer (=');
strcopy(PChar(OrigMsg), PChar('Destroy data in buffer (='));
Memo.Append('');
// Расшифровываем данные
OrigLen := DecryptRsa(RSA, PBYTE(OrigMsg), OrigLen, PByte(EncMsg), EncLen, err);
if OrigLen = 0 then
ShowMessage(err);
// Выводим расшифрованные данные
Memo.Append('--- DECODED MSG ---');
PByte(OrigMsg+OrigLen)^ := 0;
Memo.Append(OrigMsg);
// Освобождаем буферы за собой
Freemem(err);
Freemem(OrigMsg);
Freemem(EncMsg);
end;
Вроде всё работает, единственная проблема заключается в том, что я не могу (или не понимаю) как сохранить ключи и загрузить их обратно, буду очень признателен за помощь...
Добавлено спустя 5 часов 45 минут 58 секунд:
В общем вернувшись с работы, залез в доки и понял, что ключи вида
- Код: Выделить всё
-----BEGIN RSA PRIVATE KEY-----
-----BEGIN RSA PUBLIC KEY-----
Называются PEM ключами или ключами в PEM формате, соответственно их можно загрузить из памяти или из файла, что бы загрузить из файлы следует использовать функцию fopen и передавать в файловый дескриптор в
- Код: Выделить всё
RSA *PEM_read_RSA_PUBKEY(FILE *fp, RSA **x, pem_password_cb *cb, void *u);
...
и должно быть аналогично для private key
Но совместим ли FILE fpc и C?! хз, должен быть по идеи совместим, ведь дескрипторы выдаёт ОС, а вот как они хранятся в проге вот это без IDA не разберешь... По этому проще открыть файл или считать из БД в буфер и от него создать BIO_new_mem_buf и от него уже работать как с обычным BIO, исходника пока нет, я спать, если что выложу в своём блоге...