2

I'm having trouble encrypting and decrypting some information with the DCP Crypt library. I'm using Delphi XE and the functions posted at PHP to Delphi and back Encryption-Decryption using Rijndael, but it doesn't work.

I think my problem is because the key I'm using is in hex mode instead of binary.

var 
  Key, IV: ansiString;
  Data: ansiString;
begin
  Key := '09CB0785F13CD0D557C0940E72E0DCDC86CDC89769044E95DB51A782E7D996FFF3';
  Iv  := '09CB0785F13CD0D557C0940E72E0DCDC';

  Data := <?xml version="1.0" encoding="UTF-8"?><MyNode><Head><CustNo>...';

When I use the EncryptData function, must I pass the public key in binary or in hex?

 asCryptBody := EncryptData(asXMLBody, Public_Key, Init_vector);

or

 asCryptBody := EncryptData(asXMLBody, HexToStrBin(Public_Key), HexToStrBin(Init_vector));

where

function StrBinToHex(const s: AnsiString): AnsiString;
var
  i:integer;
begin
  result := '';
  for i := 1 to length(s) do
    result := result + inttohex(Ord(s[i]),1);
end;

function HexToStrBin(const s: AnsiString): AnsiString;
var
  i:integer;
begin
  result := '';
  for i := 1 to (length(s) div 2) do
    result := result + char( strtoint('$'+ copy(s,(i*2)-1,2)) );
end;

I've tried two ways, but the encryption still differs from PHP encryption.

Maybe the functions HexToStrBin and StrBinToHex are the problem?

Community
  • 1
  • 1
JosepMaria
  • 99
  • 1
  • 10
  • Have you attempted to debug this. You have two programs that produce different output. Debug them to find out where they diverge. Fix the problem and repeat until the output matches. – David Heffernan Jun 12 '13 at 13:41
  • Look at your key length after you've converted it with HexToStrBin - the PHP function you linked to will barf with that so clearly you're using different keys and so will get different results. The answer to "should they be binary or hex" is "They should be the *same* between PHP and Delphi"! (But it's likely your HexToStrBin is a step in the right direction). As David says, a little more debugging is needed. Lots of "echo" statements in the PHP and step through the Delphi. – shunty Jun 12 '13 at 15:58
  • 1
    Encryption is always about binary. So I'd expect to see byte based types like `TBytes`, `array of byte` or (avoid if you can `RawByteString`) somewhere. I'd start converting all your code to use byte based types, then compare against the PHP for equal resutls, then - if you still need strings - step by stap go backwards towards your current code and check where something throws in a wrong conversion. – Jeroen Wiert Pluimers Jun 12 '13 at 17:12
  • Please, in future edit your questions to specify Delphi version in the TAGS ! As of kow, i suspect your problem is with `result := result + char` which better be `result := result + AnsiChar` like in your 1st listing. Additionally, i hope you understand that your code is very suboptimal and would only be used rarely, would not be in the usual program activity. Also better use `RawByteString` than `AnsiString` of unknown (hardly predictable) codepage. TBytes is yet better though. Also you didn't show PHP code. Does PHP encrypt binary or hex? Maybe make PHP encrypt and log HEX and compare HEXes? – Arioch 'The Jun 12 '13 at 20:50
  • BTW, is DCPCrypt thoroughly tested with post-2007 Delphi ? i remember implementing win64 asm helpers for encryption libs of Spring4Delphi and i was impressed with test covering. Knowing nothing about crypto algorythms i made the porting in half-a-day cause those tests always made very clear if encryption is working or not. But can you be sure that DCPCrtpy is bug-free in XE ? – Arioch 'The Jun 12 '13 at 21:02

1 Answers1

1

Many thanks to all for your answers. Now is solved. The problem was: - My key and ini.vector is an string with hex values - Then i must convert the key and the initialization vector from an ansistring with hex value of key to TByte with myself function: StrHexToTBytes - Before crypt, do not add the padding. - Do not base64decode the crypted TBytes result and put it into a string with TEncoding.Default.GetString - Then for my use i pass this string result to an string with hex values.

As i posted int the titlle, the Delphi version is XE.

function StrHexToTBytes(const Hexstr: AnsiString): TBytes;
var
  i: Integer;
begin
  SetLength(Result, Length(Hexstr) div 2);
  for i:=0 to (Length(Hexstr) div 2 - 1) do
     Result[i]:= StrToInt('$' + Copy(Hexstr, (i * 2) + 1, 2));
end;

function EncryptData(const Data, AHexKey, AHexIv: AnsiString): Ansistring;
var
  cipher: TDCP_rijndael;
  key, iv, src, dest : TBytes;
  slen: integer;
begin

  /// La clau pública és una cadena de valors Hexadecimals, i s'ha de convertir a un array de Bytes.
  /// The Key and IV are an Hex ansistring, and must converted to TBytes
  key  := StrHexToTBytes(AHexKey);
  iv   := StrHexToTBytes(AHexIv);

  /// Les dades estan en una cadena de caracters i s'ha de passar directament a un array de bytes
  /// The Data is plain text in a string and must converted to TBytes
  src := TEncoding.UTF8.GetBytes(Data);

  cipher := TDCP_rijndael.Create(nil);
  try
    cipher.CipherMode := cmCBC;
    slen := Length(src);

    /// Ull No s'ha de fer cap padding del text rebut!!!
    /// Attention, the pading is not necessary!!!
{
    // Add padding.
    // Resize the Value array to make it a multiple of the block length.
    // If it's already an exact multiple then add a full block of padding.
    slen := Length(src);
    bsize := (cipher.BlockSize div 8);
    pad := bsize - (slen mod bsize);
    Inc(slen, pad);
    SetLength(src, slen);
    for index := pad downto 1 do
    begin
      src[slen - index] := pad;
    end;
}
    SetLength(dest, slen);
    cipher.Init(key[0], 256, @iv[0]); // DCP uses key size in BITS not BYTES
    cipher.Encrypt(src[0], dest[0], slen);

    /// El resultat no s'ha de codificar en base 64, es un binary que només s'ha de passar a Hexadecimal
    ///  The result does'nt must be converted to based 64, is a binary that must be puttd into a string.
//    b64 := Base64EncodeBytes(dest);
//    result := TEncoding.Default.GetString(b64);
    result := TEncoding.Default.GetString(dest);
  finally
    cipher.Free;
  end;
end;

Now i must adapt the DecryptData function.

JosepMaria
  • 99
  • 1
  • 10