LockBox 3加密不匹配的在线工具,可疑的填充或密钥问题

时间:2019-03-13 08:24:14

标签: delphi encryption lockbox-3

我有一个提供API的客户端,该API指示必须使用 AES,128位密钥,ECB模式和PKCS5Padding 对其进行加密。我正在尝试在Delphi 10.3 Rio中使用LockBox 3,并且没有得到与他们指向进行验证的online test tool相同的加密字符串。它很近,但还不在那里。

在这里,有关UnicodePKCS5Paddingrelated questions的阅读很多,我已经结束了尝试的工作。我必须承认我在加密方面做得并不多,并且在提出问题之前已经尽我所能阅读了很多内容。

我想确认以下几点:

  • 密码和密钥之间的区别。我已经了解到LB3使用密码来生成密钥,但是我从客户端获得了有关如何生成密钥的特定说明,因此我制作了自己的Base64编码密钥,并正在调用InitFromStream对其进行初始化。我相信这可以代替设置密码,对吗?也许密码仅由非对称密码使用(而不是非对称密码,例如AES)?
  • PKCS5Padding :我对在LB3 Help site上读到的内容感到担心,认为填充是根据密码的选择,链接模式等来智能地完成的。这是否意味着没有强制它使用特定填充方法的方法?我已经将数据转换为字节数组并由自己的PKCS5Padding实现,但我认为LB3可能仍在填充。 (我尝试浏览代码,但没有发现任何证据表明它在做什么。)

我应该在Delphi中使用其他加密库来完成此操作吗?我已经检查了DelphiEncryptionCompendiumDcPCryptV2,但是我发现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的字符不同。

为什么?

1 个答案:

答案 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