调用OpenSSL EVP功能的Delphi / Pascal示例 [英] Delphi / Pascal Example for Calling OpenSSL EVP functions

查看:1766
本文介绍了调用OpenSSL EVP功能的Delphi / Pascal示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有人有一个Delphi / Pascal例子来调用以下OpenSSL函数...



http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages /openssl/src/openssl.pas?revision=17634&view=markup



我对此感兴趣:

 程序EVP_CIPHER_CTX_init(a:PEVP_CIPHER_CTX); 

函数EVP_CIPHER_CTX_cleanup(a:PEVP_CIPHER_CTX):cint;

函数EVP_CIPHER_CTX_set_key_length(x:PEVP_CIPHER_CTX; keylen:cint):cint;

函数EVP_CIPHER_CTX_ctrl(ctx:PEVP_CIPHER_CTX; type_,arg:cint; ptr:Pointer):cint;
//
function EVP_EncryptInit(ctx:PEVP_CIPHER_CTX; const chipher_:PEVP_CIPHER; const key,iv:PByte):cint;

函数EVP_EncryptUpdate(ctx:PEVP_CIPHER_CTX; out_:pcuchar; outlen:pcint; const in_:pcuchar; inlen:cint):cint;

函数EVP_EncryptFinal(ctx:PEVP_CIPHER_CTX; out_data:PByte; outlen:pcint):cint;

函数EVP_DecryptInit(ctx:PEVP_CIPHER_CTX; chiphir_type:PEVP_CIPHER; const key,iv:PByte):cint;

函数EVP_DecryptUpdate(ctx:PEVP_CIPHER_CTX; out_data:PByte; outl:pcint; const in_:PByte; inl:cint):cint;

函数EVP_DecryptFinal(ctx:PEVP_CIPHER_CTX; outm:PByte; outlen:pcint):cint;

谢谢!



p.s。我看过 http://www.disi.unige.it/person/FerranteM/delphiopenssl/



不幸的是,该库不包括这些功能。

解决方案

是从我曾经工作的一些代码中直接抽出的几个例程。他们使用你提到的大多数加密方法。正如在评论中提到的,你真的需要使用OpenSSL文档。我通过读取它们并浏览openssl.exe程序的C源来创建下面的内容。 (从openssl.org下载)



这不是完美的,并且做了几个假设,但它显示了在Delphi中使用例程的基础知识。



原来的灵感,正如我之前在SO(!)上提到的几次,都是从 http://www.disi.unige.it/person/FerranteM/delphiopenssl/



编辑:在创建这些方法时,添加了底部的导入单元,以补充Indy头文件中的内容。我最近没有看过,有些可能已经在Indy中可用了。

  function EVP_Encrypt_AES256(Value: TBytes; APassword:TBytes):TBytes; 
var
cipher:PEVP_CIPHER;
ctx:EVP_CIPHER_CTX;
salt,key,iv,buf:TBytes;
block_size:integer;
buf_start,out_len:integer;
begin
cipher:= EVP_aes_256_cbc;
salt:= EVP_GetSalt;
EVP_GetKeyIV(APassword,cipher,salt,key,iv);

EVP_CIPHER_CTX_init(@ctx);
try
EVP_EncryptInit(@ctx,cipher,@key [0],@iv [0]);
block_size:= EVP_CIPHER_CTX_block_size(@ctx);
SetLength(buf,Length(Value)+ block_size + SALT_MAGIC_LEN + PKCS5_SALT_LEN);
buf_start:= 0;
Move(PAnsiChar(SALT_MAGIC)^,buf [buf_start],SALT_MAGIC_LEN);
Inc(buf_start,SALT_MAGIC_LEN);
Move(salt [0],buf [buf_start],PKCS5_SALT_LEN);
Inc(buf_start,PKCS5_SALT_LEN);
EVP_EncryptUpdate(@ctx,@buf [buf_start],@out_len,@Value [0],Length(Value));
Inc(buf_start,out_len);
EVP_EncryptFinal(@ctx,@buf [buf_start],@out_len);
Inc(buf_start,out_len);
SetLength(buf,buf_start);
result:= buf;
finally
EVP_CIPHER_CTX_cleanup(@ctx);
结束
结束

函数EVP_GetSalt:TBytes;
begin
SetLength(result,PKCS5_SALT_LEN);
RAND_pseudo_bytes(@result [0],PKCS5_SALT_LEN);
结束

程序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); //最大大小开始,然后减少它

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

//这与EVP_BytesToKey的工作方式几乎一样。但是
//允许多次通过哈希循环,并允许
//选择不同的哈希方法。我们不需要这个。
// OpenSSL文件说它已经过时了,互联网资源建议使用
//类似PKCS5_v2_PBE_keyivgen和/或PKCS5_PBKDF2_HMAC_SHA1
//但是这个方法很容易到达DEC, DCP例程,并且易于
//在其他环境中使用。最终,Key和IV依靠密码
//和盐,可以轻松地进行改造。

//此方法依赖于哈希方法产生一个
//的正确大小的事实。如果
//需要使用较小的哈希值使密钥足够大,则EVP_BytesToKey会通过muptiple散列传递。

EVP_MD_CTX_init(@ctx);
try
//第一个
EVP_DigestInit_ex(@ctx,hash,nil);
EVP_DigestUpdate(@ctx,@APassword [0],Length(APassword));
if(ASalt EVP_DigestUpdate(@ctx,@ASalt [0],Length(ASalt));
EVP_DigestFinal_ex(@ctx,@Key [0],mds);

//派生IV下一个
EVP_DigestInit_ex(@ctx,hash,nil);
EVP_DigestUpdate(@ctx,@Key [0],mds);
EVP_DigestUpdate(@ctx,@APassword [0],Length(APassword));
if(ASalt EVP_DigestUpdate(@ctx,@ASalt [0],Length(ASalt));
EVP_DigestFinal_ex(@ctx,@IV [0],mds);

SetLength(IV,niv);
finally
EVP_MD_CTX_cleanup(@ctx);
结束
结束

解密:

 code> function EVP_Decrypt_AES256(const Value:TBytes; APassword:TBytes):TBytes; 
var
cipher:PEVP_CIPHER;
ctx:EVP_CIPHER_CTX;
salt,key,iv,buf:TBytes;
src_start,buf_start,out_len:integer;
begin
cipher:= EVP_aes_256_cbc;
SetLength(salt,SALT_SIZE);
//首先读取魔术文本和盐 - 如果有任何
if(AnsiString(TEXCoding.ASCII.GetString(Value,0,SALT_MAGIC_LEN))= SALT_MAGIC)则
begin
移动(值[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);
src_start:= 0;
结束

EVP_CIPHER_CTX_init(@ctx);
try
EVP_DecryptInit(@ctx,cipher,@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);
Inc(buf_start,out_len);
EVP_DecryptFinal(@ctx,@buf [buf_start],@out_len);
Inc(buf_start,out_len);
SetLength(buf,buf_start);
result:= buf;
finally
EVP_CIPHER_CTX_cleanup(@ctx);
结束
结束

我的额外导入单位:

 单位libeay32; 

{
OpenSSL libeay32.dll库的导入单位。
最初是基于Marco Ferrante的工作。
http://www.csita.unige.it/
http://www.disi.unige.it/
然后在Indy图书馆
,当然,来自http://www.openssl.org的C源代码

只有我们需要使用的部分已被翻译/导入。
图书馆中不包括这些功能的全部功能

2010-03-11为什么重新发明车轮? Indy已经完成了这个
的大块,所以使用它 - IdSSLOpenSSLHeaders
现在我们通常只是包含在Indy代码中不可用的东西。
主要是加密的东西而不是SSL的东西。
}

接口

使用
SysUtils,Windows,
IdSSLOpenSSLHeaders;

const
LIBEAY_DLL_NAME ='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 = PByteArray的数组;
PUBK_ARRAY = PEVP_PKEY的数组;
PPUBK_ARRAY = ^ PUBK_ARRAY;

函数EVP_aes_256_cbc:PEVP_CIPHER; cdecl;
函数EVP_md5:PEVP_MD; cdecl;
函数EVP_sha1:PEVP_MD; cdecl;
函数EVP_sha256:PEVP_MD; cdecl;
函数EVP_PKEY_assign(pkey:PEVP_PKEY; key_type:integer; key:Pointer):integer; cdecl;
函数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;
函数EVP_PKEY_size(pkey:PEVP_PKEY):integer; cdecl;

程序EVP_CIPHER_CTX_init(a:PEVP_CIPHER_CTX); cdecl;
函数EVP_CIPHER_CTX_cleanup(a:PEVP_CIPHER_CTX):integer; cdecl;
函数EVP_CIPHER_CTX_block_size(ctx:PEVP_CIPHER_CTX):integer; cdecl;
程序EVP_MD_CTX_init(ctx:PEVP_MD_CTX); cdecl;
函数EVP_MD_CTX_cleanup(ctx:PEVP_MD_CTX):integer; cdecl;
函数EVP_BytesToKey(cipher_type:PEVP_CIPHER; md:PEVP_MD; salt:PByte; data:PByte; datal:integer; count:integer; key:PByte; iv:PByte):integer; cdecl;
函数EVP_EncryptInit_ex(ctx:PEVP_CIPHER_CTX; cipher_type:PEVP_CIPHER; impl:PENGINE; key:PByte; iv:PByte):integer; cdecl;
函数EVP_EncryptInit(ctx:PEVP_CIPHER_CTX; cipher_type:PEVP_CIPHER; key:PByte; iv:PByte):integer; cdecl;
函数EVP_EncryptUpdate(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer; data_in:PByte; inl:integer):integer; cdecl;
函数EVP_EncryptFinal(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer):integer; cdecl;
函数EVP_DecryptInit_ex(ctx:PEVP_CIPHER_CTX; cipher_type:PEVP_CIPHER; impl:PENGINE; key:PByte; iv:PByte):integer; cdecl;
函数EVP_DecryptInit(ctx:PEVP_CIPHER_CTX; cipher_type:PEVP_CIPHER; key:PByte; iv:PByte):integer; cdecl;
函数EVP_DecryptUpdate(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer; data_in:PByte; inl:integer):integer; cdecl;
函数EVP_DecryptFinal(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer):integer; cdecl;
函数EVP_SealInit(ctx:PEVP_CIPHER_CTX; cipher_type:PEVP_CIPHER; ek:PEK_ARRAY; ekl:PIntegerArray; iv:PByte; pubk:PPUBK_ARRAY; npubk:integer):integer; cdecl;
函数EVP_SealUpdate(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer; data_in:PByte; inl:integer):integer;
函数EVP_SealFinal(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer):integer; cdecl;
函数EVP_OpenInit(ctx:PEVP_CIPHER_CTX; cipher_type:PEVP_CIPHER; ek:PByte; ekl:integer; iv:PByte; priv:PEVP_PKEY):integer; cdecl;
函数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;
函数EVP_DigestInit_ex(ctx:PEVP_MD_CTX; md:PEVP_MD; impl:PENGINE):integer; cdecl;
函数EVP_DigestUpdate(ctx:PEVP_MD_CTX; data:PByte; cnt:integer):integer; cdecl;
函数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;
程序EVP_SignInit(ctx:PEVP_MD_CTX; md:PEVP_MD);
函数EVP_SignInit_ex(ctx:PEVP_MD_CTX; md:PEVP_MD; impl:PENGINE):integer;
函数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);
函数EVP_VerifyInit_ex(ctx:PEVP_MD_CTX; md:PEVP_MD; impl:PENGINE):integer;
函数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;

函数X509_get_pubkey(cert:PX509):PEVP_PKEY; cdecl;

procedure BIO_free_all(a:PBIO); cdecl;

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

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

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

执行

resourcestring
sLibeay32NotLoaded ='libeay32.dll未加载';
sAddAllAlgorithmsProcNotFound ='OpenSSL_add_all_algorithms过程未在libeay32.dll中定义;


函数EVP_aes_256_cbc:PEVP_CIPHER; cdecl外部LIBEAY_DLL_NAME;
函数EVP_md5; cdecl外部LIBEAY_DLL_NAME;
函数EVP_sha1; cdecl外部LIBEAY_DLL_NAME;
函数EVP_sha256; cdecl外部LIBEAY_DLL_NAME;
函数EVP_PKEY_assign; cdecl外部LIBEAY_DLL_NAME;
函数EVP_PKEY_new; cdecl外部LIBEAY_DLL_NAME;
程序EVP_PKEY_free; cdecl外部LIBEAY_DLL_NAME;
function EVP_PKEY_assign_RSA(pkey:PEVP_PKEY; key:PRSA):integer;
begin
//在evp.h
中实现为一个宏结果:= EVP_PKEY_assign(pkey,EVP_PKEY_RSA,PAnsiChar(key));
结束
函数EVP_PKEY_size; cdecl外部LIBEAY_DLL_NAME;

程序EVP_CIPHER_CTX_init; cdecl外部LIBEAY_DLL_NAME;
函数EVP_CIPHER_CTX_cleanup; cdecl外部LIBEAY_DLL_NAME;
函数EVP_CIPHER_CTX_block_size; cdecl外部LIBEAY_DLL_NAME;
函数EVP_BytesToKey; cdecl外部LIBEAY_DLL_NAME;
function EVP_EncryptInit_ex; cdecl外部LIBEAY_DLL_NAME;
函数EVP_EncryptInit; cdecl外部LIBEAY_DLL_NAME;
函数EVP_EncryptUpdate; cdecl外部LIBEAY_DLL_NAME;
函数EVP_EncryptFinal; cdecl外部LIBEAY_DLL_NAME;
函数EVP_DecryptInit_ex; cdecl外部LIBEAY_DLL_NAME;
函数EVP_DecryptInit; cdecl外部LIBEAY_DLL_NAME;
函数EVP_DecryptUpdate; cdecl外部LIBEAY_DLL_NAME;
函数EVP_DecryptFinal; cdecl外部LIBEAY_DLL_NAME;
函数EVP_SealInit; cdecl外部LIBEAY_DLL_NAME;
函数EVP_SealUpdate(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer; data_in:PByte; inl:integer):integer;
begin
// EVP_SealUpdate被定义为EVP_EncryptUpdate,在evp.h
result:= EVP_EncryptUpdate(ctx,data_out,outl,data_in,inl);
结束
函数EVP_SealFinal; cdecl外部LIBEAY_DLL_NAME;
函数EVP_OpenInit; cdecl外部LIBEAY_DLL_NAME;
函数EVP_OpenUpdate(ctx:PEVP_CIPHER_CTX; data_out:PByte; var outl:integer; data_in:PByte; inl:integer):integer;
begin
// EVP_OpenUpdate被定义为EVP_DecryptUpdate在evp.h
result:= EVP_DecryptUpdate(ctx,data_out,outl,data_in,inl);
结束
函数EVP_OpenFinal; cdecl外部LIBEAY_DLL_NAME;
程序EVP_MD_CTX_init; cdecl外部LIBEAY_DLL_NAME;
函数EVP_MD_CTX_cleanup; cdecl外部LIBEAY_DLL_NAME;
程序EVP_DigestInit;外部LIBEAY_DLL_NAME;
函数EVP_DigestInit_ex;外部LIBEAY_DLL_NAME;
函数EVP_DigestUpdate;外部LIBEAY_DLL_NAME;
函数EVP_DigestFinal;外部LIBEAY_DLL_NAME;
function EVP_DigestFinal_ex;外部LIBEAY_DLL_NAME;
程序EVP_SignInit(ctx:PEVP_MD_CTX; md:PEVP_MD);
begin
//定义为evp.h中的宏
EVP_DigestInit(ctx,md);
结束
函数EVP_SignInit_ex(ctx:PEVP_MD_CTX; md:PEVP_MD; impl:PENGINE):integer;
begin
//定义为evp.h中的宏
result:= EVP_DigestInit_ex(ctx,md,impl);
结束
函数EVP_SignUpdate(ctx:PEVP_MD_CTX; data:PByte; cnt:integer):integer;
begin
//定义为evp.h中的宏
result:= EVP_DigestUpdate(ctx,data,cnt);
结束
函数EVP_SignFinal; cdecl外部LIBEAY_DLL_NAME;
procedure EVP_VerifyInit(ctx:PEVP_MD_CTX; md:PEVP_MD);
begin
//定义为evp.h中的宏
EVP_DigestInit(ctx,md);
结束
函数EVP_VerifyInit_ex(ctx:PEVP_MD_CTX; md:PEVP_MD; impl:PENGINE):integer;
begin
//定义为evp.h中的宏
result:= EVP_DigestInit_ex(ctx,md,impl);
结束
函数EVP_VerifyUpdate(ctx:PEVP_MD_CTX; data:PByte; cnt:integer):integer;
begin
//定义为evp.h中的宏
result:= EVP_DigestUpdate(ctx,data,cnt);
结束
函数EVP_VerifyFinal; cdecl外部LIBEAY_DLL_NAME;

函数X509_get_pubkey; cdecl;外部LIBEAY_DLL_NAME;

procedure BIO_free_all; cdecl外部LIBEAY_DLL_NAME;

函数PEM_write_bio_RSA_PUBKEY; cdecl外部LIBEAY_DLL_NAME;
函数PEM_read_bio_PUBKEY; cdecl外部LIBEAY_DLL_NAME;
函数PEM_write_bio_PUBKEY; cdecl外部LIBEAY_DLL_NAME;

函数RAND_load_file; cdecl外部LIBEAY_DLL_NAME;
函数RAND_bytes; cdecl外部LIBEAY_DLL_NAME;
函数RAND_pseudo_bytes; cdecl外部的LIBEAY_DLL_NAME;

函数RSA_generate_key; cdecl外部LIBEAY_DLL_NAME;
程序RSA_free; cdecl外部LIBEAY_DLL_NAME;

结束。


Does anyone have a Delphi / Pascal example for calling the below OpenSSL functions...

http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/packages/openssl/src/openssl.pas?revision=17634&view=markup

I am specifically interested in:

procedure EVP_CIPHER_CTX_init(a: PEVP_CIPHER_CTX);

function EVP_CIPHER_CTX_cleanup(a: PEVP_CIPHER_CTX): cint;

function EVP_CIPHER_CTX_set_key_length(x: PEVP_CIPHER_CTX; keylen: cint): cint;

function EVP_CIPHER_CTX_ctrl(ctx: PEVP_CIPHER_CTX; type_, arg: cint; ptr: Pointer): cint;
//
function EVP_EncryptInit(ctx: PEVP_CIPHER_CTX; const chipher_: PEVP_CIPHER;const key, iv: PByte): cint;

function EVP_EncryptUpdate(ctx: PEVP_CIPHER_CTX; out_: pcuchar;outlen: pcint; const in_: pcuchar; inlen: cint): cint;

function EVP_EncryptFinal(ctx: PEVP_CIPHER_CTX; out_data: PByte; outlen: pcint): cint;

function EVP_DecryptInit(ctx: PEVP_CIPHER_CTX; chiphir_type: PEVP_CIPHER;const key, iv: PByte): cint;

function EVP_DecryptUpdate(ctx: PEVP_CIPHER_CTX; out_data: PByte;outl: pcint; const in_: PByte; inl: cint): cint;

function EVP_DecryptFinal(ctx: PEVP_CIPHER_CTX; outm: PByte; outlen: pcint): cint;

Thank you!

p.s. I have seen http://www.disi.unige.it/person/FerranteM/delphiopenssl/

Unfortunately that library does not include those functions.

解决方案

Here are a couple of routines taken straight out of some code I once worked on. They use most of the encryption methods you mention. As mentioned in the comments you really need to get intimate with the OpenSSL docs. I created the stuff below by reading them and going through the C source for the openssl.exe program. (Downloaded from openssl.org).

It's not perfect and makes a couple of assumptions but it does show the basics of using the routines in Delphi.

The original inspiration, as I have mentioned several times before on SO(!), was taken from the stuff at http://www.disi.unige.it/person/FerranteM/delphiopenssl/ that you've already linked to above.

EDIT: Added an import unit at the bottom to supplement what was in the Indy headers when I created these methods. I haven't looked recently so some of this may already be available in Indy.

function EVP_Encrypt_AES256(Value: TBytes; APassword: TBytes): TBytes;
var
  cipher: PEVP_CIPHER;
  ctx: EVP_CIPHER_CTX;
  salt, key, iv, buf: TBytes;
  block_size: integer;
  buf_start, out_len: integer;
begin
  cipher := EVP_aes_256_cbc;
  salt := EVP_GetSalt;
  EVP_GetKeyIV(APassword, cipher, salt, key, iv);

  EVP_CIPHER_CTX_init(@ctx);
  try
    EVP_EncryptInit(@ctx, cipher, @key[0], @iv[0]);
    block_size := EVP_CIPHER_CTX_block_size(@ctx);
    SetLength(buf, Length(Value) + block_size + SALT_MAGIC_LEN + PKCS5_SALT_LEN);
    buf_start := 0;
    Move(PAnsiChar(SALT_MAGIC)^, buf[buf_start], SALT_MAGIC_LEN);
    Inc(buf_start, SALT_MAGIC_LEN);
    Move(salt[0], buf[buf_start], PKCS5_SALT_LEN);
    Inc(buf_start, PKCS5_SALT_LEN);
    EVP_EncryptUpdate(@ctx, @buf[buf_start], @out_len, @Value[0], Length(Value));
    Inc(buf_start, out_len);
    EVP_EncryptFinal(@ctx, @buf[buf_start], @out_len);
    Inc(buf_start, out_len);
    SetLength(buf, buf_start);
    result := buf;
  finally
    EVP_CIPHER_CTX_cleanup(@ctx);
  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;

Decryption:

function EVP_Decrypt_AES256(const Value: TBytes; APassword: TBytes): TBytes;
var
  cipher: PEVP_CIPHER;
  ctx: EVP_CIPHER_CTX;
  salt, key, iv, buf: TBytes;
  src_start, buf_start, out_len: 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);
    src_start := 0;
  end;

  EVP_CIPHER_CTX_init(@ctx);
  try
    EVP_DecryptInit(@ctx, cipher, @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);
    Inc(buf_start, out_len);
    EVP_DecryptFinal(@ctx, @buf[buf_start], @out_len);
    Inc(buf_start, out_len);
    SetLength(buf, buf_start);
    result := buf;
  finally
    EVP_CIPHER_CTX_cleanup(@ctx);
  end;
end;

My extra import unit:

unit libeay32;

{
  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 = '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;
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_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;
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_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.

这篇关于调用OpenSSL EVP功能的Delphi / Pascal示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆