MHumm / DelphiEncryptionCompendium

Cryptographic library for Embarcadero Delphi and potentially for FPC as well
Apache License 2.0
255 stars 66 forks source link

Urgent: Migration from DEC 5.2 library. Help wanted #41

Closed infosystems-mn closed 2 years ago

infosystems-mn commented 2 years ago

I am trying to migrate from the DEC 5.2 version to the current one for Linux. I have written my own wrapper for the old version of the library and I use this wrapper in my projects. But I see very many changes in the new DEC, I have dozens of compilation errors. Please help me how to approach this migration.

uses DecUtil, DECCipher, DECHash, DECFmt;

var ACipherClass: TDECCipherClass = TCipher_Rijndael; ACipherMode: TCipherMode = cmCBCx; AHashClass: TDECHashClass = THash_Whirlpool; ATextFormat: TDECFormatClass = TFormat_Mime64; AKDFIndex: LongWord = 1;

function Encrypt(const AText: WideString; const APassword: WideString): WideString; var ASalt: Binary; AData: Binary; APass: Binary; begin with ValidCipher(ACipherClass).Create, Context do try ASalt := .... ; APass := ValidHash(AHashClass).KDFx(APassword[1], System.Length(APassword) SizeOf(APassword[1]), ASalt[1], System.Length(ASalt), KeySize, TFormat_Copy, AKDFIndex); Mode := ACipherMode; Init(APass); SetLength(AData, System.Length(AText) SizeOf(AText[1])); Encode(AText[1], AData[1], System.Length(AData)); Result := ValidFormat(ATextFormat).Encode(ASalt + AData + CalcMAC); finally Free; end; end;

MHumm commented 2 years ago

Sorry for not answering earlier! I'll also try to find more time over the weekend.

Yes, there were quite a lot of architectural changes between 5.2 and 6.0 in order to improve architecture to get a better and more modern basis for everything still to come.

A few pointers out of my head right now:

  1. The units have more "speaking" names now. DecFmt is DECFormat now and the KDFx method you are using is in DECHashAuthentication.
  2. I hope you have seen the documentation in the DOCS subfolder? It contains a version history as well which lists many if not all the changes.
  3. The binary data type got removed. It was an alias to some string type and I thing it would not have been cross platform compatible, thus I dropped it. Either use the RawByteString variants where possible of TBytes based ones.
  4. If I'd be you I'd get rid of the with statement, as is makes reading the code quite hard at times.

I hope to find the time for more answers over the weekend.

MHumm commented 2 years ago

I started work on this by putting your supplied code into a console application using the DEC 5.2 libraries. It compiles and for this salt: '1234567890' this call: WriteLn(Encrypt('My text to encrypt', '1234')); produces this output: MTIzNDU2Nzg5MHYmO9Zrg4hSi7T+6NvU/pBZnCtlTCdRobnjoBMIIIwfCMnyZO/HDa7xQhOG4z9RaynSjNQ= Can you confirm the output is correct? I'd start my conversion work after lunch.

MHumm commented 2 years ago

Ok, here's my final version now. I completely removed that confusing width and at some places removed the class type use, as in the new architecture some functionality has been moved from the base classes into inherited classes from which the actual classes inherit in turn. Unfortunately for these inherited "middle" classes no class type declarations exist yet. I make a note on my todo list now to add them in DEC 6.5.

The complete .dpr file is attached as ZIP-file as well, as GitHub creates issues with the code formatting.

`program Issue41_DEC52;

{$APPTYPE CONSOLE}

{$R *.res}

uses System.SysUtils, DECCipherBase, DECCiphers, DECHash, DECFormatBase, DECFormat;

var ACipherMode: TCipherMode = cmCBCx;

ACipher : TCipher_AES; // note: bit size of the AES variant used depends on // init vector length. In DEC 6.5 which is still in // the works, we additionally will have TDEC_AES128, // TDEC_AES192 and TDEC_AES256 AHash : THash_Whirlpool0; // I do not recommend to use this variant, as this // is the original faulty one. It is provided for // compatibility reasons. Better use THashWhirlpool1

ATextFormat: TDECFormatClass = TFormat_Base64; AKDFIndex: UInt32 = 1; // better avoid LongWord as on iOS and Linux 64 this is UInt64!

function Encrypt(const AText: WideString; const APassword: WideString): WideString; var ASalt : RawByteString; AData : RawByteString; APass : RawByteString; PW : TBytes; Encoded : TBytes; begin ACipher := TCipher_AES.Create; try ASalt := '1234567890';

AHash := THash_Whirlpool0.Create;
try
  PW := AHash.KDFx(APassword[1],
                   System.Length(APassword) * SizeOf(APassword[1]),
                   ASalt[1],
                   System.Length(ASalt),
                   ACipher.Context.KeySize,
                   AKDFIndex);

  SetLength(APass, Length(PW));
  Move(PW[0], APass[1], Length(APass));

  ACipher.Mode := ACipherMode;
  ACipher.Init(APass);
  Encoded := ACipher.EncodeStringToBytes(AText);
  SetLength(AData, Length(Encoded));
  Move(Encoded[0], AData[1], Length(Encoded));

  Result := WideString(ValidFormat(ATextFormat).Encode(ASalt + AData + ACipher.CalcMAC));
finally
  AHash.Free;
end;

finally ACipher.Free; end; end;

begin try WriteLn(Encrypt('My text to encrypt', '1234')); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end;

ReadLn; end. Issue41_DEC52.zip `

infosystems-mn commented 2 years ago

Thanks a lot MHumm,

I spent too much time and was not success. The result is exactly same. Appreciate.