Обмен ключами Диффи-Хеллмана с использованием OpenSSL в Delphi - PullRequest
0 голосов
/ 10 мая 2018

Я хочу реализовать обмен ключами Диффи-Хеллмана в моем существующем протоколе. Я искал довольно много сайтов на эту тему, и самое большее, что я мог получить, это «вы обмениваетесь параметрами DH между сторонами, и это все». Было явно недостаточно информации по теме или я искал не в том месте.

После нескольких дней работы я нашел хорошие заголовочные файлы OpenSSL для Delphi (https://github.com/Arvur/OpenSSL-Delphi).. Используя эти заголовки, исходный код из OpenSSL и пару примеров программ, я создал полный обмен ключами Диффи-Хеллмана. от генерации параметров DH и открытых ключей до получения общего секрета. Для самого обмена я использовал простые файлы, но его можно использовать любым способом (например, сокетами).

procedure CommonSecretKeyGeneration;
var parameters_context:PEVP_PKEY_CTX;
key_generation_context:PEVP_PKEY_CTX;
key_generation_context2:PEVP_PKEY_CTX;
shared_context1:PEVP_PKEY_CTX;
shared_context2:PEVP_PKEY_CTX;
parameters:PEVP_PKEY;
parameters2:PEVP_PKEY;
private_key:PEVP_PKEY;
private_key2:PEVP_PKEY;
public_key:PEVP_PKEY;
public_key2:PEVP_PKEY;
bio_file:PBIO;
keylen:cardinal;
arr:array of byte;
str:string;
i:integer;
begin
  SSL_InitEVP;
  SSL_InitBIO;
  SSL_InitPEM;

  Log('-------------Generating parameters---------------');
  parameters_context:=EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nil);
  if parameters_context<>nil then Log('Context for parameters created')
  else
  begin
    Log('Failed to generate parameters context');
    exit;
  end;

  i:=EVP_PKEY_paramgen_init(parameters_context);
  if i=1 then Log('Parameter context init done')
  else
  begin
    Log('Error initializing parameter context, return='+inttostr(i));
    exit;
  end;

  //equal to EVP_PKEY_CTX_set_dh_paramgen_prime_len(parameters_context, 1024)
  i:=EVP_PKEY_CTX_ctrl(parameters_context, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN, EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN, 1024, nil);
  if i=1 then Log('Setting prime length done')
  else
  begin
    Log('Error setting prime length, return='+inttostr(i));
    exit;
  end;

  i:=EVP_PKEY_paramgen(parameters_context,@parameters);
  if i=1 then Log('Generation of parameters sucsessful')
  else
  begin
    Log('Error while generating parameters, return='+inttostr(i));
    exit;
  end;

  Log('-------------Output parameters to file---------------');
  //writing parameters to file
  bio_file:=BIO_new_file('C:\DH_parameters_test.pem', 'w');
  i:=PEM_write_bio_Parameters(bio_file,parameters);
  Log('PEM write return='+inttostr(i));
  BIO_free_all(bio_file);

  Log('-------------Client reading parameters---------------');
  //sending parameters via sockets
  //reading parameters
  bio_file:=BIO_new_file('C:\DH_parameters_test.pem', 'r');
  parameters2:=PEM_read_bio_Parameters(bio_file,nil);
  BIO_free_all(bio_file);
  if parameters2<>nil then Log('Readed parameters sucsess for client')
  else
  begin
    Log('Error reading parameters');
    exit;
  end;

  Log('-------------Generating private/public keys on server---------------');
  //making a key on server
  key_generation_context:=EVP_PKEY_CTX_new(parameters, nil);
  if key_generation_context<>nil then Log('Created key generation context')
  else
  begin
    Log('Error creating key generation context');
    exit;
  end;

  i:=EVP_PKEY_keygen_init(key_generation_context);
  if i=1 then Log('Initialized key generation sucsessfully')
  else
  begin
    Log('Error initializing key generation, return='+inttostr(i));
    exit;
  end;

  i:=EVP_PKEY_keygen(key_generation_context, @private_key);
  if i=1 then Log('Generated keys')
  else
  begin
    Log('Error generating keys, return='+inttostr(i));
    exit;
  end;

  Log('-------------Generating private/public keys on client---------------');
  //making key on client
  key_generation_context2:=EVP_PKEY_CTX_new(parameters2, nil);
  if key_generation_context<>nil then Log('Created key generation context on client')
  else
  begin
    Log('Error creating key generation context on client');
    exit;
  end;

  i:=EVP_PKEY_keygen_init(key_generation_context2);
  if i=1 then Log('Initialized key generation sucsessfully on client')
  else
  begin
    Log('Error initializing key generation on client, return='+inttostr(i));
    exit;
  end;

  i:=EVP_PKEY_keygen(key_generation_context2, @private_key2);
  if i=1 then Log('Generated keys on client')
  else
  begin
    Log('Error generating keys, return='+inttostr(i));
    exit;
  end;

  Log('-------------Public key exchange---------------');
  Log('-------------Outputing public key on server---------------');
  //outputing public keys
  bio_file:=BIO_new_file('C:\public_key1.pem', 'w');
  i:=PEM_write_bio_PUBKEY(bio_file,private_key);
  Log('PEM write return='+inttostr(i));
  BIO_free_all(bio_file);

  Log('-------------Outputing public key on client---------------');
  bio_file:=BIO_new_file('C:\public_key2.pem', 'w');
  i:=PEM_write_bio_PUBKEY(bio_file,private_key2);
  Log('PEM write return='+inttostr(i));
  BIO_free_all(bio_file);

  //public key exchange

  Log('-------------Reading public key1 (for client)---------------');
  //reading public keys
  bio_file:=BIO_new_file('C:\public_key1.pem', 'r');
  public_key:=PEM_read_bio_PUBKEY(bio_file,nil,nil,nil);
  BIO_free_all(bio_file);
  if public_key<>nil then Log('Readed public key1 sucsessfully')
  else
  begin
    Log('Error reading public key1');
    exit;
  end;

  Log('-------------Reading public key2 (for server)---------------');
  bio_file:=BIO_new_file('C:\public_key2.pem', 'r');
  public_key2:=PEM_read_bio_PUBKEY(bio_file,nil,nil,nil);
  BIO_free_all(bio_file);
  if public_key2<>nil then Log('Readed public key2 sucsessfully')
  else
  begin
    Log('Error reading public key2');
    exit;
  end;

  Log('-------------Calculating secret on server---------------');
  shared_context1:=EVP_PKEY_CTX_new(private_key,nil);
  if shared_context1<>nil then Log('Created shared context for key1')
  else
  begin
    Log('Error creating shared context for key1');
    exit;
  end;

  i:=EVP_PKEY_derive_init(shared_context1);
  if i=1 then Log('Derive init sucsessful on server')
  else
  begin
    Log('Error while initializing derive on server, return='+inttostr(i));
    exit;
  end;

  i:=EVP_PKEY_derive_set_peer(shared_context1,public_key2);
  if i=1 then Log('Set peer on server done')
  else
  begin
    Log('Error setting peer on server');
    exit;
  end;

  keylen:=0;
  Log('Before query secret key length='+inttostr(keylen));
  i:=EVP_PKEY_derive(shared_context1,nil,cardinal(@keylen));
  if i=1 then Log('Query secret key length sucsessful, len='+inttostr(keylen))
  else
  begin
    Log('Error query secret key length');
    exit;
  end;

  setlength(arr,keylen);
  FillChar(arr[0],length(arr),0);
  i:=EVP_PKEY_derive(shared_context1,@arr[0],cardinal(@keylen));
  if i=1 then
  begin
    Log('Output secret key sucsessful, len='+inttostr(keylen));
    str:='';
    for i:=0 to length(arr)-1 do
      str:=str+inttohex(arr[i],2);
    Log('Secret on server='+str);
  end
  else
  begin
    Log('Error query secret key');
    exit;
  end;

  Log('-------------Calculating secret on client---------------');
  shared_context2:=EVP_PKEY_CTX_new(private_key2,nil);
  if shared_context1<>nil then Log('Created shared context for key2')
  else
  begin
    Log('Error creating shared context for key2');
    exit;
  end;

  i:=EVP_PKEY_derive_init(shared_context2);
  if i=1 then Log('Derive init sucsessful on client')
  else
  begin
    Log('Error while initializing derive on client, return='+inttostr(i));
    exit;
  end;

  i:=EVP_PKEY_derive_set_peer(shared_context2,public_key);
  if i=1 then Log('Set peer on client done')
  else
  begin
    Log('Error setting peer on client');
    exit;
  end;

  keylen:=0;
  Log('Before query secret key length='+inttostr(keylen));
  i:=EVP_PKEY_derive(shared_context2,nil,cardinal(@keylen));
  if i=1 then Log('Query secret key length sucsessful, len='+inttostr(keylen))
  else
  begin
    Log('Error query secret key length');
    exit;
  end;

  setlength(arr,keylen);
  FillChar(arr[0],length(arr),0);
  i:=EVP_PKEY_derive(shared_context2,@arr[0],cardinal(@keylen));
  if i=1 then
  begin
    Log('Output secret key sucsessful, len='+inttostr(keylen));
    str:='';
    for i:=0 to length(arr)-1 do
      str:=str+inttohex(arr[i],2);
    Log('Secret on client='+str);
  end
  else
  begin
    Log('Error query secret key');
    exit;
  end;

  Log('===============DONE================');
end;

Вопрос:

  1. Я пропустил какую-либо важную часть обмена ключами DH? Достаточно ли этого, чтобы гарантировать, что обе стороны будут иметь один и тот же секретный ключ?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...