Search code examples
delphiencryptionaesdelphi-7

Delphi Aes Decrypt function


I have this Python decryption function which I am trying to convert to Delphi.

It uses AES CFB mode:

def aes_decrypt(data,key,iv):
    ctx = AES.new(key, AES.MODE_CFB, iv=iv, segment_size=128)
    decrypted = ctx.decrypt(data)
    return decrypted

I am using Dcpcrypt in Delphi 7. // key is Md5 hash (this key/IV is just example not exact)

const
  Key = 'c143vvssaaea933f04e956a3ff5vb562'; 
  iv = 'r4022f4577726207fy0etf4fate2gd44';
    
function aes_decrypt(Data: TBytes; key,iv: string): TBytes;
var
  Cipher: TDCP_rijndael;
  InStrm, OutStrm: TMemoryStream;
begin
  InStrm := TMemoryStream.Create;
  OutStrm := TMemoryStream.Create;
  InStrm.Write(Data[0], Length(Data));
  Cipher := TDCP_rijndael.Create(nil);
  Cipher.BlockSize:=128;
  Cipher.CipherMode:=cmCFB8bit;
  Cipher.Init(Key, 128, @IV);
  Cipher.DecryptStream(InStrm, OutStrm, OutStrm.Size);
  SetLength(Result, Integer(OutStrm.size));
  OutStrm.Seek(0, 0);
  OutStrm.Read(Result[0], Length(Result));
  OutStrm.SaveToFile('decbuf.bin');
  InStrm.Free;
  OutStrm.Free;
  Cipher.Free;
end;

I am getting incorrect output with the Delphi code; the Python function is returning the expected output.

The segment_size

segment_size (integer) – (Only MODE_CFB).The number of bits the plaintext and ciphertext are segmented in. It must be a multiple of 8. If not specified, it will be assumed to be 8.

does this apply in Delphi Dcpcrypt ?


Solution

  • I don't know Python and can only assume OP is importing PyCrypto, but the manual's first example shows and explains what I suspected:

    key = b'Sixteen byte key'
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    

    Both key and iv are in bytes, not a string. It even literally says "Sixteen byte key", not "32 character hash string". And the b right before the literal is not there for fun either. But in your Pascal code you're handing over text, which surprisingly is double the size of 16 byte, and also (almost) only makes use of hexadecimal digits. But you should provide full bytes instead of their hexadecimal representation. The correct code would be:

    const
      // v, s, r, t and g are invalid digits, of course
      Key= #$c1#$43#$vv#$ss#$aa#$ea#$93#$3f#$04#$e9#$56#$a3#$ff#$5v#$b5#$62;
      iv= #$r4#$02#$2f#$45#$77#$72#$62#$07#$fy#$0e#$tf#$4f#$at#$e2#$gd#$44;
    
    // Last parameter is optional, just like you wanted it. Credits: fpiette
    function aes_decrypt( Data: TBytes; key, iv: String; segment_size: Integer= 128 ): TBytes;
    

    You have to find out the rest yourself. The comments been given to you barely made you progress. DCPcrypt (just like any software/library) exists in different versions, which differ in details - since nobody knows which one you are using nobody can halfway pinpoint a potential mistake you make. Same goes for PyCrypto. If you would have offered right away

    • an uncensored correct key,
    • an uncensored correct initialization vector,
    • the encrypted data, and
    • the correctly decrypted data

    then it would be much simpler. Otherwise you might wait forever until someone shows up who can execute both ends (Python X and Delphi 7). Consider changing your question drastically and provide more details.