У меня есть клиент, предоставляющий API, который предписывает отправлять им данные, которые должны быть зашифрованы с помощью AES, 128-битного ключа, режима ECB и PKCS5Padding . Я пытаюсь использовать LockBox 3 в Delphi 10.3 Rio и не получаю ту же зашифрованную строку, что и онлайн-инструмент тестирования , на который они указывали для проверки. Это близко, но не совсем там.
С большим количеством чтения здесь о Unicode , PKCS5Padding и связанных вопросах , я пришел к концу того, что попробовать. Я должен признать, что я не особо разбираюсь в шифровании и столько читал, сколько смог, чтобы обдумать это, прежде чем задавать вопросы.
Есть пара вещей, на которые я хотел бы получить подтверждение:
- Разница между паролем и ключом . Я читал, что LB3 использует пароль для генерации ключа, но у меня есть конкретные инструкции от клиента о том, как должен генерироваться ключ, поэтому я создал свой собственный ключ в кодировке Base64 и вызываю InitFromStream для его инициализации. Я полагаю, что это занимает место установки пароля, правильно? Или, может быть, пароли используются только асимметричными шифрами (не симметричными, как AES)?
- PKCS5Padding : меня беспокоило то, что я прочитал на справочном сайте LB3 , что заполнение выполняется разумно, в зависимости от выбора шифра, режима цепочки и т. Д. значит нет способа заставить его использовать определенный метод заполнения? Я преобразовал данные в байтовый массив и реализовал его с помощью собственного PKCS5Padding, но я думаю, что LB3 все еще может быть дополнен. (Я пытался просмотреть код и не нашел никаких доказательств того, что он делает.)
Должен ли я использовать другую библиотеку шифрования в Delphi для этого? Я извлек DelphiEncryptionCompendium и DcPCryptV2 , но я обнаружил, что LB3, похоже, имеет большинство поддержки, и я чувствовал, что это было легче всего работать, особенно в моей версии Delphi для Unicode. Кроме того, я использовал 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 отличаются от того, что создает онлайн-инструмент .
Почему?