TPLB 3 OpenSSL 解密 AES-256-CBC 使用 Ruby 2.0.0 OpenSSL::Cipher 加密

TPLB 3 OpenSSL Decrypt AES-256-CBC Encrypted with Ruby 2.0.0 OpenSSL::Cipher

我正在从使用 OpenSSL::Cipher 使用 AES-256-CBC 加密数据的服务器发送一些信息。我在 Delphi XE8 中编码的应用程序中接收数据,并尝试使用 TPLB 3 OpenSSL 解密数据。从我尝试过的所有内容中,我得到了所有匹配的信息、密钥、iv 等),但在尝试解密时我仍然收到错误或垃圾数据。我假设我在 TPLB 3 setup/config 中缺少一些东西来让它正确解密,但我一辈子都弄不明白。非常感谢任何帮助。

Delphi 正在解密

function TLicenseReload.Decode(L, K, I: string): string;
var
  cdec: TOpenSSL_Codec;
  s: string;
  sOut,
  sIn: TStream;
begin
  Result := '';
  cdec := TOpenSSL_Codec.Create(nil);
  sIn := TStringStream.Create;
  sout := TStringStream.Create;
  try
    sIn.Write(L, length(L));
    sIn.Position := 0;

    cdec.SetKey(TEncoding.Default.GetBytes(K));
    cdec.SetIV(TEncoding.Default.GetBytes(I));
    cdec.Cipher := cipher_aes_256_cbc;
    cdec.PaddingScheme := {padNone;//}padPKCS;
    //cdec.LibName := 'libeay32.dll'; //toggled on and off to attempt to decrypt correctly
    //cdec.LibPath := ExtractFilePath(Application.Exename); //toggled on and off to attempt to decrypt correctly
    //cdec.RequiredVersion := '1.0.1.7'; //toggled on and off to attempt to decrypt correctly
    cdec.isLoaded := true; //receive an access violation if this is not set
    cdec.Decrypt(sOut, sIn);
    //s := sOut.DataString;   //was using TStringStream but wasn't working so switched to TStream
    sOut.ReadBuffer(s[1], sOut.Size - sOut.Position);
    result := s;
  finally
    sOut.Free;
    sIn.Free;
    cdec.Free;
  end;
end;

Ruby 加密

begin
unless loc.nil?
  cip = OpenSSL::Cipher.new('AES-256-CBC')
  cip.encrypt
  cip.key = Digest::SHA1.hexdigest(loc.l_hash[0..31].upcase).upcase
  lic_iv = cip.random_iv
  lic_iv = Base64.encode64(lic_iv)
  enc_lic_date = cip.update(loc.licensed_through.to_s + ':' + loc.customer.purchased.to_s) + cip.final
  enc_lic_date = Base64.encode64(enc_lic_date)#.encode('utf-8')
  #enc_lic_date << cip.final
end
rescue StandardError => e
  error_message = e.to_s
  puts e.to_s
end

编辑:

我回去仔细检查了所有内容(基本上是重新开始)。我已经确认在服务器上加密的字节(在进行 Base64 编码之前)与在客户端上解密(post Base64 解码)的字节相同。但是,我仍然 "junk" 出来了。

已更新(混乱)Delphi正在解密

function TLicenseReload.DecodeLicense(L, K, I: string): string;
var
  cdec: TOpenSSL_Codec;
  s: string;
  sOut,
  sIn: TStringStream;
  x,
  y: TBytes;
  z: string;
begin
  Result := '';
  cdec := TOpenSSL_Codec.Create(nil);
  sIn := TStringStream.Create;
  sout := TStringStream.Create;
  try
    SetLength(x, Length(K));
    SetLength(y, Length(DecodeBase64(I)));
    //SetLength(z, Length(DecodeBase64(L)));
    x := TEncoding.UTF8.GetBytes(K);
    y := DecodeBase64(I);
    //z := string(DecodeBase64(L));

    //sIn.WriteString(z);//, length(z));
    sIn.WriteData(DecodeBase64(L), length(DecodeBase64(L)));
    sIn.Position := 0;

    //cdec.SetKey(TEncoding.UTF8.GetBytes(unbaseit(K)));
    //cdec.SetIV(TEncoding.UTF8.GetBytes(unbaseit(I)));
    cdec.SetKey(TEncoding.UTF8.GetBytes(K));
    cdec.SetIV(DecodeBase64(I));
    cdec.Cipher := cipher_aes_256_cbc;
    cdec.PaddingScheme := padNone;//}padPKCS;
    //cdec.LibName := 'libeay32.dll';
    //cdec.LibPath := ExtractFilePath(Application.Exename);
    //cdec.RequiredVersion := '1.0.1.7';
    cdec.isLoaded := true;
    cdec.Decrypt(sOut, sIn);
    s := sOut.DataString;
    //sOut.ReadBuffer(s[1], sOut.Size - sOut.Position);
    result := s;
  finally
    sOut.Free;
    sIn.Free;
    cdec.Free;
  end;
end;

编辑 2 TPLB3 有两个填充选项,None 或 PKCS。设置 None 后,我得到了垃圾。设置 PKCS 后,我得到一个 "OpenSSL encryption error"。结果上的编码似乎无关紧要,它仍然是垃圾。

我能够将加密数据发送下来进行解密。我最终使用了 this post 中的函数和单元。我不得不稍微修改它们,并更新了几个函数调用以满足我的需要,我将在下面 post。

我之前看过 post,但无法让它工作,于是放弃并回到 TPLB3。在将我的头撞了好几个小时并在网上四处研究和挖掘之后,我与 TPLB3 如此接近,但我无法获得预期的结果。因此,在一位同事的建议下,我再次查看了这个并意识到当我第一次尝试时我确实从错误的编码字符串中传递了字节,我在寻求让 TPLB3 工作的过程中发现并追踪了这些字节.将其重新插入后,需要进行一些调整和更新(更新以防旧功能被删除)以使其在我的特定情况下正常工作。

  SALT_MAGIC: AnsiString = 'Salted__';
  SALT_MAGIC_LEN: integer = 8;
  SALT_SIZE = 8;

function EVP_Decrypt_AES256(const Value: TBytes; APassword: TBytes; AIV: TBytes): TBytes;
var
  cipher: PEVP_CIPHER;
  ctx: EVP_CIPHER_CTX;
  salt, key, iv, buf: TBytes;
  src_start, buf_start, out_len, attempt: integer;
begin
  cipher := EVP_aes_256_cbc;
  SetLength(salt, SALT_SIZE);
  // First read the magic text and the salt - if any
  if (AnsiString(TEncoding.ASCII.GetString(Value, 0, SALT_MAGIC_LEN)) = SALT_MAGIC) then
  begin
    Move(Value[SALT_MAGIC_LEN], salt[0], SALT_SIZE);
    EVP_GetKeyIV(APassword, cipher, salt, key, iv);
    src_start := SALT_MAGIC_LEN + SALT_SIZE;
  end
  else
  begin
    //EVP_GetKeyIV(APassword, cipher, nil, key, iv); //commented out because we are passing in a known iv
    key := APassword;
    iv := AIV;
    src_start := 0;
  end;

  EVP_CIPHER_CTX_init(@ctx);
  try
    EVP_DecryptInit_ex(@ctx, cipher, nil, @key[0], @iv[0]);
    SetLength(buf, Length(Value));
    buf_start := 0;
    //EVP_DecryptUpdate(@ctx, @buf[buf_start], @out_len, @Value[src_start], Length(Value) - src_start);
    EVP_DecryptUpdate(@ctx, @buf[buf_start], out_len, @Value[src_start], Length(Value) - src_start);
    Inc(buf_start, out_len);
    //EVP_DecryptFinal(@ctx, @buf[buf_start], @out_len);
    EVP_DecryptFinal_ex(@ctx, @buf[buf_start], out_len);
    Inc(buf_start, out_len);
    if ((length(buf) > 0) and (buf_start > 0) and (buf[0] <> 0)) then
      SetLength(buf, buf_start);
    result := buf;
  finally
    repeat
    until EVP_CIPHER_CTX_cleanup(@ctx) = 1;
  end;
end;

function EVP_GetSalt: TBytes;
begin
  SetLength(result, PKCS5_SALT_LEN);
  RAND_pseudo_bytes(@result[0], PKCS5_SALT_LEN);
end;

procedure EVP_GetKeyIV(APassword: TBytes; ACipher: PEVP_CIPHER; const ASalt: TBytes; out Key, IV: TBytes);
var
  ctx: EVP_MD_CTX;
  hash: PEVP_MD;
  mdbuff: TBytes;
  mds: cardinal;
  nkey, niv: integer;
begin
  hash := EVP_sha256;
  mds := 0;
  SetLength(mdbuff, EVP_MAX_MD_SIZE);

  nkey := ACipher.key_len;
  niv := ACipher.iv_len;
  SetLength(Key, nkey);
  SetLength(IV, nkey);  // Max size to start then reduce it at the end

  Assert(hash.md_size >= nkey);
  Assert(hash.md_size >= niv);

  // This is pretty much the same way that EVP_BytesToKey works. But that
  // allows multiple passes through the hashing loop and also allows to
  // choose different hashing methods. We have no need for this. The
  // OpenSSL docs say it is out of date and internet sources suggest using
  // something like PKCS5_v2_PBE_keyivgen and/or PKCS5_PBKDF2_HMAC_SHA1
  // but this method is easy to port to the DEC and DCP routines and easy to
  // use in other environments. Ultimately the Key and IV rely on the password
  // and the salt and can be easily reformed.

  // This method relies on the fact that the hashing method produces a key of
  // the correct size. EVP_BytesToKey goes through muptiple hashing passes if
  // necessary to make the key big enough when using smaller hashes.

  EVP_MD_CTX_init(@ctx);
  try
    // Key first
    EVP_DigestInit_ex(@ctx, hash, nil);
    EVP_DigestUpdate(@ctx, @APassword[0], Length(APassword));
    if (ASalt <> nil) then
      EVP_DigestUpdate(@ctx, @ASalt[0], Length(ASalt));
    EVP_DigestFinal_ex(@ctx, @Key[0], mds);

    // Derive IV next
    EVP_DigestInit_ex(@ctx, hash, nil);
    EVP_DigestUpdate(@ctx, @Key[0], mds);
    EVP_DigestUpdate(@ctx, @APassword[0], Length(APassword));
    if (ASalt <> nil) then
      EVP_DigestUpdate(@ctx, @ASalt[0], Length(ASalt));
    EVP_DigestFinal_ex(@ctx, @IV[0], mds);

    SetLength(IV, niv);
  finally
    EVP_MD_CTX_cleanup(@ctx);
  end;
end;

unit libeay32;

{
  Provided by user shunty from Whosebug
  

  Import unit for the OpenSSL libeay32.dll library.
  Originally based on the work by Marco Ferrante.
    http://www.csita.unige.it/
    http://www.disi.unige.it/
  then on the Indy libraries
  and, of course, the C source code from http://www.openssl.org

  Only the parts that we need to use have been translated/imported. There are
  a whole load of functions in the library that aren't included here

  2010-03-11 Why re-invent the wheel. Indy has done a large chunk of this
  already so use it - IdSSLOpenSSLHeaders
  Now we generally just include stuff that isn't available in the Indy code.
  Primarily encryption stuff rather than SSL stuff.
}

interface

uses
  SysUtils, Windows,
  IdSSLOpenSSLHeaders;

const
  LIBEAY_DLL_NAME = '.\OpenSSL_0_1l\libeay32.dll';
  PROC_ADD_ALL_ALGORITHMS_NOCONF = 'OPENSSL_add_all_algorithms_noconf';
  PROC_ADD_ALL_ALGORITHMS = 'OpenSSL_add_all_algorithms';

  EVP_PKEY_RSA = IdSSLOpenSSLHeaders.EVP_PKEY_RSA;
  PKCS5_SALT_LEN = IdSSLOpenSSLHeaders.PKCS5_SALT_LEN;
  EVP_MAX_KEY_LENGTH = IdSSLOpenSSLHeaders.EVP_MAX_KEY_LENGTH;
  EVP_MAX_IV_LENGTH = IdSSLOpenSSLHeaders.EVP_MAX_IV_LENGTH;
  EVP_MAX_MD_SIZE = IdSSLOpenSSLHeaders.EVP_MAX_MD_SIZE;

type
  PEVP_PKEY = IdSSLOpenSSLHeaders.PEVP_PKEY;
  PRSA = IdSSLOpenSSLHeaders.PRSA;
  EVP_MD_CTX = IdSSLOpenSSLHeaders.EVP_MD_CTX;
  EVP_CIPHER_CTX = IdSSLOpenSSLHeaders.EVP_CIPHER_CTX;
  PEVP_CIPHER = IdSSLOpenSSLHeaders.PEVP_CIPHER;
  PEVP_MD = IdSSLOpenSSLHeaders.PEVP_MD;

type
  TSSLProgressCallbackFunction = procedure (status: integer; value: integer; cb_arg: pointer);
  TSSLPasswordCallbackFunction = function (buffer: TBytes; size: integer; rwflag: integer; u: pointer): integer; cdecl;
  TOpenSSL_InitFunction = procedure; cdecl;

type
  PEK_ARRAY = ^EK_ARRAY;
  EK_ARRAY = array of PByteArray;
  PUBK_ARRAY = array of PEVP_PKEY;
  PPUBK_ARRAY = ^PUBK_ARRAY;

function EVP_aes_256_cbc: PEVP_CIPHER; cdecl;
function EVP_md5: PEVP_MD; cdecl;
function EVP_sha1: PEVP_MD; cdecl;
function EVP_sha256: PEVP_MD; cdecl;
function EVP_PKEY_assign(pkey: PEVP_PKEY; key_type: integer; key: Pointer): integer; cdecl;
function EVP_PKEY_new: PEVP_PKEY; cdecl;
procedure EVP_PKEY_free(key: PEVP_PKEY); cdecl;
function EVP_PKEY_assign_RSA(pkey: PEVP_PKEY; key: PRSA): integer;
function EVP_PKEY_size(pkey: PEVP_PKEY): integer; cdecl;

procedure EVP_CIPHER_CTX_init(a: PEVP_CIPHER_CTX); cdecl;
procedure EVP_CipherInit_ex(A: PEVP_CIPHER_CTX); cdecl;
function EVP_CIPHER_CTX_cleanup(a: PEVP_CIPHER_CTX): integer; cdecl;
function EVP_CIPHER_CTX_block_size(ctx: PEVP_CIPHER_CTX): integer; cdecl;
procedure EVP_MD_CTX_init(ctx: PEVP_MD_CTX); cdecl;
function EVP_MD_CTX_cleanup(ctx: PEVP_MD_CTX): integer; cdecl;
function EVP_BytesToKey(cipher_type: PEVP_CIPHER; md: PEVP_MD; salt: PByte; data: PByte; datal: integer; count: integer; key: PByte; iv: PByte): integer; cdecl;
function EVP_EncryptInit_ex(ctx: PEVP_CIPHER_CTX; cipher_type: PEVP_CIPHER; impl: PENGINE; key: PByte; iv: PByte): integer; cdecl;
function EVP_EncryptInit(ctx: PEVP_CIPHER_CTX; cipher_type: PEVP_CIPHER; key: PByte; iv: PByte): integer; cdecl;
function EVP_EncryptUpdate(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer; data_in: PByte; inl: integer): integer; cdecl;
function EVP_EncryptFinal(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer): integer; cdecl;
function EVP_DecryptInit_ex(ctx: PEVP_CIPHER_CTX; cipher_type: PEVP_CIPHER; impl: PENGINE; key: PByte; iv: PByte): integer; cdecl;
function EVP_DecryptInit(ctx: PEVP_CIPHER_CTX; cipher_type: PEVP_CIPHER; key: PByte; iv: PByte): integer; cdecl;
function EVP_DecryptUpdate(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer; data_in: PByte; inl: integer): integer; cdecl;
function EVP_DecryptFinal(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer): integer; cdecl;
function EVP_DecryptFinal_ex(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer): integer; cdecl;
function EVP_SealInit(ctx: PEVP_CIPHER_CTX; cipher_type: PEVP_CIPHER; ek: PEK_ARRAY; ekl: PIntegerArray; iv: PByte; pubk: PPUBK_ARRAY; npubk: integer): integer; cdecl;
function EVP_SealUpdate(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer; data_in: PByte; inl: integer): integer;
function EVP_SealFinal(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer): integer; cdecl;
function EVP_OpenInit(ctx: PEVP_CIPHER_CTX; cipher_type: PEVP_CIPHER; ek: PByte; ekl: integer; iv: PByte; priv: PEVP_PKEY): integer; cdecl;
function EVP_OpenUpdate(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer; data_in: PByte; inl: integer): integer;
function EVP_OpenFinal(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer): integer; cdecl;
procedure EVP_DigestInit(ctx: PEVP_MD_CTX; md: PEVP_MD); cdecl;
function EVP_DigestInit_ex(ctx: PEVP_MD_CTX; md: PEVP_MD; impl: PENGINE): integer; cdecl;
function EVP_DigestUpdate(ctx: PEVP_MD_CTX; data: PByte; cnt: integer): integer; cdecl;
function EVP_DigestFinal(ctx: PEVP_MD_CTX; md: PByte; var s: cardinal): integer; cdecl;
function EVP_DigestFinal_ex(ctx: PEVP_MD_CTX; md: PByte; var s: cardinal): integer; cdecl;
procedure EVP_SignInit(ctx: PEVP_MD_CTX; md: PEVP_MD);
function EVP_SignInit_ex(ctx: PEVP_MD_CTX; md: PEVP_MD; impl: PENGINE): integer;
function EVP_SignUpdate(ctx: PEVP_MD_CTX; data: PByte; cnt: integer): integer;
function EVP_SignFinal(ctx: PEVP_MD_CTX; sig: PByte; var s: integer; pkey: PEVP_PKEY): integer; cdecl;
procedure EVP_VerifyInit(ctx: PEVP_MD_CTX; md: PEVP_MD);
function EVP_VerifyInit_ex(ctx: PEVP_MD_CTX; md: PEVP_MD; impl: PENGINE): integer;
function EVP_VerifyUpdate(ctx: PEVP_MD_CTX; data: PByte; cnt: integer): integer;
function EVP_VerifyFinal(ctx: PEVP_MD_CTX; sig: PByte; s: integer; pkey: PEVP_PKEY): integer; cdecl;

function X509_get_pubkey(cert: PX509): PEVP_PKEY; cdecl;

procedure BIO_free_all(a: PBIO); cdecl;

function PEM_write_bio_RSA_PUBKEY(bp: PBIO; x: PRSA): integer; cdecl;
function PEM_read_bio_PUBKEY(bp: PBIO; x: PPEVP_PKEY; cb: TSSLPasswordCallbackFunction; u: pointer): PEVP_PKEY; cdecl;
function PEM_write_bio_PUBKEY(bp: PBIO; x: PEVP_PKEY): integer; cdecl;

function RAND_load_file(const filename: PAnsiChar; max_bytes: longint): integer; cdecl;
function RAND_bytes(buf: PByte; num: integer): integer; cdecl;
function RAND_pseudo_bytes(buf: PByte; num: integer): integer; cdecl;

function RSA_generate_key(num: integer; e: Cardinal; cb: TSSLProgressCallbackFunction; cb_arg: pointer): PRSA; cdecl;
procedure RSA_free(r: PRSA); cdecl;

implementation

resourcestring
  sLibeay32NotLoaded = 'libeay32.dll not loaded';
  sAddAllAlgorithmsProcNotFound = 'OpenSSL_add_all_algorithms procedure not defined in libeay32.dll';


function EVP_aes_256_cbc: PEVP_CIPHER; cdecl external LIBEAY_DLL_NAME;
function EVP_md5; cdecl external LIBEAY_DLL_NAME;
function EVP_sha1; cdecl external LIBEAY_DLL_NAME;
function EVP_sha256; cdecl external LIBEAY_DLL_NAME;
function EVP_PKEY_assign; cdecl external LIBEAY_DLL_NAME;
function EVP_PKEY_new; cdecl external LIBEAY_DLL_NAME;
procedure EVP_PKEY_free; cdecl external LIBEAY_DLL_NAME;
function EVP_PKEY_assign_RSA(pkey: PEVP_PKEY; key: PRSA): integer;
begin
  // Implemented as a macro in evp.h
  result := EVP_PKEY_assign(pkey, EVP_PKEY_RSA, PAnsiChar(key));
end;
function EVP_PKEY_size; cdecl external LIBEAY_DLL_NAME;

procedure EVP_CIPHER_CTX_init; cdecl external LIBEAY_DLL_NAME;
procedure EVP_CipherInit_ex; cdecl external LIBEAY_DLL_NAME;
function EVP_CIPHER_CTX_cleanup; cdecl external LIBEAY_DLL_NAME;
function EVP_CIPHER_CTX_block_size; cdecl external LIBEAY_DLL_NAME;
function EVP_BytesToKey; cdecl external LIBEAY_DLL_NAME;
function EVP_EncryptInit_ex; cdecl external LIBEAY_DLL_NAME;
function EVP_EncryptInit; cdecl external LIBEAY_DLL_NAME;
function EVP_EncryptUpdate; cdecl external LIBEAY_DLL_NAME;
function EVP_EncryptFinal; cdecl external LIBEAY_DLL_NAME;
function EVP_DecryptInit_ex; cdecl external LIBEAY_DLL_NAME;
function EVP_DecryptInit; cdecl external LIBEAY_DLL_NAME;
function EVP_DecryptUpdate; cdecl external LIBEAY_DLL_NAME;
function EVP_DecryptFinal; cdecl external LIBEAY_DLL_NAME;
function EVP_DecryptFinal_ex; cdecl external LIBEAY_DLL_NAME;
function EVP_SealInit; cdecl external LIBEAY_DLL_NAME;
function EVP_SealUpdate(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer; data_in: PByte; inl: integer): integer;
begin
  // EVP_SealUpdate is #defined to EVP_EncryptUpdate in evp.h
  result := EVP_EncryptUpdate(ctx, data_out, outl, data_in, inl);
end;
function EVP_SealFinal; cdecl external LIBEAY_DLL_NAME;
function EVP_OpenInit; cdecl external LIBEAY_DLL_NAME;
function EVP_OpenUpdate(ctx: PEVP_CIPHER_CTX; data_out: PByte; var outl: integer; data_in: PByte; inl: integer): integer;
begin
  // EVP_OpenUpdate is #defined to EVP_DecryptUpdate in evp.h
  result := EVP_DecryptUpdate(ctx, data_out, outl, data_in, inl);
end;
function EVP_OpenFinal; cdecl external LIBEAY_DLL_NAME;
procedure EVP_MD_CTX_init; cdecl external LIBEAY_DLL_NAME;
function EVP_MD_CTX_cleanup; cdecl external LIBEAY_DLL_NAME;
procedure EVP_DigestInit; external LIBEAY_DLL_NAME;
function EVP_DigestInit_ex; external LIBEAY_DLL_NAME;
function EVP_DigestUpdate; external LIBEAY_DLL_NAME;
function EVP_DigestFinal; external LIBEAY_DLL_NAME;
function EVP_DigestFinal_ex; external LIBEAY_DLL_NAME;
procedure EVP_SignInit(ctx: PEVP_MD_CTX; md: PEVP_MD);
begin
  // Defined as a macro in evp.h
  EVP_DigestInit(ctx, md);
end;
function EVP_SignInit_ex(ctx: PEVP_MD_CTX; md: PEVP_MD; impl: PENGINE): integer;
begin
  // Defined as a macro in evp.h
  result := EVP_DigestInit_ex(ctx, md, impl);
end;
function EVP_SignUpdate(ctx: PEVP_MD_CTX; data: PByte; cnt: integer): integer;
begin
  // Defined as a macro in evp.h
  result := EVP_DigestUpdate(ctx, data, cnt);
end;
function EVP_SignFinal; cdecl external LIBEAY_DLL_NAME;
procedure EVP_VerifyInit(ctx: PEVP_MD_CTX; md: PEVP_MD);
begin
  // Defined as a macro in evp.h
  EVP_DigestInit(ctx, md);
end;
function EVP_VerifyInit_ex(ctx: PEVP_MD_CTX; md: PEVP_MD; impl: PENGINE): integer;
begin
  // Defined as a macro in evp.h
  result := EVP_DigestInit_ex(ctx, md, impl);
end;
function EVP_VerifyUpdate(ctx: PEVP_MD_CTX; data: PByte; cnt: integer): integer;
begin
  // Defined as a macro in evp.h
  result := EVP_DigestUpdate(ctx, data, cnt);
end;
function EVP_VerifyFinal; cdecl external LIBEAY_DLL_NAME;

function X509_get_pubkey; cdecl; external LIBEAY_DLL_NAME;

procedure BIO_free_all; cdecl external LIBEAY_DLL_NAME;

function PEM_write_bio_RSA_PUBKEY; cdecl external LIBEAY_DLL_NAME;
function PEM_read_bio_PUBKEY; cdecl external LIBEAY_DLL_NAME;
function PEM_write_bio_PUBKEY; cdecl external LIBEAY_DLL_NAME;

function RAND_load_file; cdecl external LIBEAY_DLL_NAME;
function RAND_bytes; cdecl external LIBEAY_DLL_NAME;
function RAND_pseudo_bytes; cdecl external LIBEAY_DLL_NAME;

function RSA_generate_key; cdecl external LIBEAY_DLL_NAME;
procedure RSA_free; cdecl external LIBEAY_DLL_NAME;

end.