用openssl4delphi编写一个AES-256-cbc例子

openssl4delphi是笔者将openssl3翻译为pascal的一个原生库,完全脱离了dll依赖。

我将此链接的c代码转为了pascal语言

EVP Symmetric Encryption and Decryption - OpenSSLWiki

program demo_wiki_aes;

{$APPTYPE CONSOLE}
//{$I DICompilers.inc}


uses
  {$IFDEF EurekaLog}
  EMemLeaks,
  EResLeaks,
  EDebugExports,
  EDebugJCL,
  EFixSafeCallException,
  EMapWin32,
  EAppConsole,
  EDialogConsole,
  ExceptionLog7,
  {$ENDIF EurekaLog}
  SysUtils,
  System.NetEncoding,
  openssl.api,
  openssl3.crypto.evp.evp_lib,
  OpenSSL3.Err,
  OpenSSL3.crypto.err.err_prn,
  openssl3.crypto.evp.evp_enc,
  openssl3.crypto.evp.e_aes,
  openssl3.crypto.sha.sha1_one,
  openssl3.crypto.evp.evp_key,
  openssl3.crypto.bio.bio_lib,
  openssl3.crypto.evp.bio_b64,
  openssl3.crypto.bio.bss_mem,
  openssl3.crypto.bio.bio_dump,
  openssl3.crypto.evp.legacy_sha,
  System.TypInfo,
  libc.error in 'libc\libc.error.pas',
  openssl3.test.testutil.output in 'test\openssl3.test.testutil.output.pas',
  basic_output in 'test\basic_output.pas';

//https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption
procedure handleErrors;
begin
    ERR_print_errors_fp(@System.ErrOutput);
    abort();
end;

function encrypt( plaintext : PByte; plaintext_len : integer; key, iv, ciphertext : PByte):integer;
var
  ctx            : PEVP_CIPHER_CTX;
  len,
  ciphertext_len : integer;
begin
    { Create and initialise the context }
    ctx := EVP_CIPHER_CTX_new ;
    if nil = ctx then
        handleErrors;
    {
     * Initialise the encryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     }
    if 1 <> EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc, nil, key, iv ) then
        handleErrors;
    {
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     }
    if 1 <> EVP_EncryptUpdate(ctx, ciphertext, @len, plaintext, plaintext_len) then
        handleErrors;
    ciphertext_len := len;
    {
     * Finalise the encryption. Further ciphertext bytes may be written at
     * this stage.
     }
    if 1 <> EVP_EncryptFinal_ex(ctx, ciphertext + len, @len) then
        handleErrors;
    ciphertext_len  := ciphertext_len + len;
    { Clean up }
    EVP_CIPHER_CTX_free(ctx);
    Result := ciphertext_len;
end;


function decrypt( ciphertext : PByte; ciphertext_len : integer; key, iv, plaintext : PByte):integer;
var
  ctx           : PEVP_CIPHER_CTX;
  len,
  plaintext_len : integer;
begin
    { Create and initialise the context }
    ctx := EVP_CIPHER_CTX_new ;
    if nil = ctx then
        handleErrors;
    {
     * Initialise the decryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     }
    if 1 <> EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc, nil, key, iv )then
        handleErrors;
    {
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary.
     }
    if 1 <> EVP_DecryptUpdate(ctx, plaintext, @len, ciphertext, ciphertext_len) then
        handleErrors;
    plaintext_len := len;
    {
     * Finalise the decryption. Further plaintext bytes may be written at
     * this stage.
     }
    if 1 <> EVP_DecryptFinal_ex(ctx, plaintext + len, @len) then
        handleErrors;
    plaintext_len  := plaintext_len + len;
    { Clean up }
    EVP_CIPHER_CTX_free(ctx);
    Result := plaintext_len;
end;

type
   SSL_string = AnsiString;
   UTF8Char = AnsiChar;

const
   msg: SSL_String = 'The quick brown fox jumps over the lazy dog';

function main:integer;
var
  key,
  iv,
  plaintext     : TBytes;
  ciphertext    : array[0..127] of Byte;
  decryptedtext : array[0..127] of UTF8Char;
  enc_b64 : array of AnsiChar;
  decryptedtext_len, len, enc_len_b64,
  ciphertext_len , len_b64   : integer;
  S: string;
  F: PTextFile;
begin
    {
     * Set up the key and iv. Do I need to say to not hard code these in a
     * real application? :-)
     }
    { A 256 bit key }
    key := StrToBytes(SSL_String('01234567890123456789012345678901'));
    { A 128 bit IV }
    iv := StrToBytes(SSL_String('0123456789012345'));
    { Message to be encrypted }
    plaintext := StrToBytes(msg);

    {
     * Buffer for ciphertext. Ensure the buffer is long enough for the
     * ciphertext which may be longer than the plaintext, depending on the
     * algorithm and mode.
     }
    { Buffer for the decrypted text }
    { Encrypt the plaintext }
    ciphertext_len := encrypt (PByte(plaintext), Length(plaintext), PByte(key), PByte(iv),
                              PByte(@ciphertext));
    { Do something useful with the ciphertext here }
    Writeln('Ciphertext is:');
    F := @System.Output;
    len := (Length(msg) + 0) * SizeOf(UTF8Char);
    len  := ((len div AES_BLOCK_SIZE) + int(0 <> (len mod AES_BLOCK_SIZE))) * AES_BLOCK_SIZE;
    len_b64 := (len + 2) div 3 * 4 + ((len + 2) div 3 * 4 + 63) div 64;
    if (SizeOf(UTF8Char) = 2) and (len_b64 mod 2 = 1) then
        Inc(len_b64,1);
    enc_len_b64 := 0;
    SetLength(enc_b64, len_b64);
    base64encode(PByte(@ciphertext), len, PAnsiChar(enc_b64), @enc_len_b64, 0);
    S := TNetEncoding.Base64.EncodeBytesToString(ciphertext);
    S := Copy(S, 1, enc_len_b64);
    Writeln(PAnsiChar(enc_b64));
    Writeln(S);
    //BIO_dump_fp(F, PByte(@ciphertext), ciphertext_len);
    { Decrypt the ciphertext }
    decryptedtext_len := decrypt(@ciphertext, ciphertext_len, PByte(key), PByte(iv),
                                @decryptedtext);
    { Add a nil terminator. We are expecting printable text }
    decryptedtext[decryptedtext_len] := #0;
    { Show the decrypted text }
    Writeln('Decrypted text is:');
    if SizeOf(UTF8Char) = 2 then
       Writeln(Format('%s', [PChar(@decryptedtext)]))
    Else
       Writeln(Format('%s', [PAnsiChar(@decryptedtext)]));

    Setlength(key, 0);
    Setlength(iv, 0);
    Setlength(plaintext, 0);
    //SetLength(ciphertext, 0);
    Result := 0;
end;



begin
  try
    Main;
  except
    on e:Exception do
      WriteLn(e.Message);
  end;
end.

运行结果如下:

 

然后用一个在线AES网站进行测试

Online AES Calculator(Encryption and Decryption)

结果完全正确,说明加密解密和base64编码的源代码是对的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值