我有一个提供API的客户端,该API指示必须使用 AES,128位密钥,ECB模式和PKCS5Padding 对其进行加密。我正在尝试在Delphi 10.3 Rio中使用LockBox 3,并且没有得到与他们指向进行验证的online test tool相同的加密字符串。它很近,但还不在那里。
在这里,有关Unicode,PKCS5Padding和related questions的阅读很多,我已经结束了尝试的工作。我必须承认我在加密方面做得并不多,并且在提出问题之前已经尽我所能阅读了很多内容。
我想确认以下几点:
我应该在Delphi中使用其他加密库来完成此操作吗?我已经检查了DelphiEncryptionCompendium和DcPCryptV2,但是我发现LB3似乎得到了最大的支持,并且我觉得这是最容易使用的,尤其是在我的Unicode版本的Delphi中。另外,我已经使用LockBox 2很多年了,所以我觉得它会更加熟悉(事实并非如此)。
为了说明我的尝试,我将代码从项目中提取到控制台应用程序。也许我上面的假设是正确的,并且我的代码或LB3参数中有一个明显的错误,我不知道有人会指出:
program LB3ConsoleTest;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Classes, System.NetEncoding,
uTPLb_Codec, uTPLb_CryptographicLibrary,
uTPLb_StreamUtils, uTPLb_Constants;
var
Codec: TCodec;
CryptographicLibrary: TCryptographicLibrary;
function PKCS5PadStringToBytes(RawData: string; const PadSize: Integer): TBytes;
{ implement our own block padding }
var
DataLen: Integer;
PKCS5PaddingCount: ShortInt;
begin
Result := TEncoding.UTF8.GetBytes(RawData);
DataLen := Length(RawData);
PKCS5PaddingCount := PadSize - DataLen mod PadSize;
if PKCS5PaddingCount = 0 then
PKCS5PaddingCount := PadSize;
Inc(DataLen, PKCS5PaddingCount);
SetLength(Result, DataLen);
FillChar(Result[DataLen - PKCS5PaddingCount], PKCS5PaddingCount, PKCS5PaddingCount);
end;
procedure InitializeAESKey(const AESKey: string);
{ convert the string to a byte array,
use that to initialize a ByteStream,
and call LB3's InitFromStream }
var
AESKeyBytes: TBytes;
AESKeyStream: TBytesStream;
begin
AESKeyBytes := TEncoding.UTF8.GetBytes(AESKey);
AESKeyStream := TBytesStream.Create(AESKeyBytes);
Codec.InitFromStream(AESKeyStream);
end;
const
RawData = '{"invoice_id":"456456000018047","clerk_id":"0023000130234234","trans_amount":1150034534,"cust_code":"19455605000987890641","trans_type":"TYPE1"}';
AESKeyStr = 'CEAA31AD1EE4BDC8';
var
DataBytes: TBytes;
DataStream: TBytesStream;
ResultStream: TBytesStream;
ResultBytes: TBytes;
Base64Encoder: TBase64Encoding;
begin
// create the LockBox3 objects
Codec := TCodec.Create(nil);
CryptographicLibrary := TCryptographicLibrary.Create(nil);
try
// setup LB3 for AES, 128-bit key, ECB
Codec.CryptoLibrary := CryptographicLibrary;
Codec.StreamCipherId := uTPLb_Constants.BlockCipher_ProgId;
Codec.BlockCipherId := Format(uTPLb_Constants.AES_ProgId, [128]);
Codec.ChainModeId := uTPLb_Constants.ECB_ProgId;
// prep the data, the key, and the resulting stream
DataBytes := PKCS5PadStringToBytes(RawData, 8);
DataStream := TBytesStream.Create(DataBytes);
InitializeAESKey(AESKeyStr);
ResultStream := TBytesStream.Create;
// ENCRYPT!
Codec.EncryptStream(DataStream, ResultStream);
// take the result stream, convert it to a byte array
ResultStream.Seek(0, soFromBeginning);
ResultBytes := Stream_to_Bytes(ResultStream);
// convert the byte array to a Base64-encoded string and display
Base64Encoder := TBase64Encoding.Create(0);
Writeln(Base64Encoder.EncodeBytesToString(ResultBytes));
Readln;
finally
Codec.Free;
CryptographicLibrary.Free;
end;
end.
此程序会生成一个加密的字符串,长度为216个字符,最后一个25个字符与online tool的字符不同。
为什么?
答案 0 :(得分:1)
AES使用16字节的块,而不是8字节。
因此,您需要具有16个字节填充的PKCS7,而不是固定为8个字节的PKCS5。
请尝试
DataBytes := PKCS5PadStringToBytes(RawData, 16);
还可以考虑更改链接模式,使其远离ECB which is pretty weak, so is to be avoided for any serious work。