TPLB 3 OpenSSL解密AES-256-CBC使用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 < e error_message = e.to_s puts e.to_s end 

编辑:

我回去仔细检查了一切(基本上重新开始)。 我已经确认在服务器上加密的字节(在它们被Base64加密之前)与客户端上正在解密的字节(在Base64解码后)相同。 但是,我仍然在“垃圾”。

更新(凌乱)Delphi Decrypting

 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有两个填充选项,无或PKCS。 如果没有设置,我会得到垃圾。 使用PKCS设置我得到“OpenSSL加密错误”。 对结果的编码似乎并不重要,它仍然是垃圾。

我能够将发送的加密数据解密。 我最后使用了这篇文章中的函数和单元。 我不得不稍微修改它们,并更新了几个函数调用以满足我的需求,我将在下面发布。

我之前看过这个post,无法让它工作并放弃并回到TPLB3。 在我的头撞墙几个小时并在网上研究和挖掘之后,我与TPLB3如此接近,我无法得到预期的结果。 所以在一位同事的建议下,我再次看了一遍,并意识到当我第一次尝试它时,我确实从错误的编码字符串中传递了字节,我在寻找TPLB3的过程中找到并跟踪了这些字符串。 一旦我重新插入它,它需要一些调整和更新(更新以防万一旧的function被删除),以使其适用于我的具体情况。

  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 StackOverflow https://stackoverflow.com/questions/9723963/delphi-pascal-example-for-calling-openssl-evp-functions 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\1_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. 

Interesting Posts