3

I need to encrypt an 10-byte string in Delphi using 3DES.

It must get the same result than this PHP code:

function encrypt_3DES($message, $key){
$bytes = array(0,0,0,0,0,0,0,0);
$iv = implode(array_map("chr", $bytes)); 

$ciphertext = mcrypt_encrypt(MCRYPT_3DES, $key, $message, MCRYPT_MODE_CBC, $iv); 
return $ciphertext;

I have been trying to code it using DCPCrypt and LockBox 3. I have finally discarded DCPCrypt because it hasn't been update lately and I'm not sure if it works correctly with Delphi 10.1 Berlin, so I have focused in LockBox 3, but I haven't been able to get the encryption right.

The encryption key is a 24bytes key (which I have its base64 representation). I can't find how to create such key using the TSymetricKey class of LockBox to pass it to an Codec.Init method. So I put it on an AnsiString and set it on the Password property (although the documentations says that there is a utf8Password but I can't find it).

Then there is a method called EncryptAnsiString, but again it expects strings (utf16 on Delphi 10.1 Berlin) instead of AnsiStrings (although the documentation says the contrary), so I'm not surprised that the result doesn't match what I'm looking for (the same value encrypted on that PHP snippet).

This is my Delphi Code :

  function Encrypt(Data: AnsiString; LocalKey: AnsiString): AnsiString;
  var 
    BinaryLocalKey: TBytes;
    strLocalKey, strTripleDes: AnsiString;
  begin
    BinaryLocalKey := DecodeBase64(LocalKey);
    setString(strLocalKey, PAnsiChar(@BinaryLocalKey[0]), Length(BinaryLocalKey));

    Codec1.Rest;
    Codec1.Password := strLocalKey;
    Codec1.EncryptAnsiString(Data, strTripleDES);
    Codec1.Reset;

    Result := strTripleDes;
  end;

But this Code not only doesn't get the same result as the PHP code, but at every call it returns a different result for the same input.

NOTE: Codec1 is a component linked to a TCryptographicLibrary component, and with the propertis ChainMode set to CBC* and Cipher set to 3DES (Keying option 1)

Does somebody know how to properly get this 3DES encryption ?.

Thank you.

Marc Guillot
  • 6,090
  • 1
  • 15
  • 42
  • 2
    Why are you working with text rather than bytes? – David Heffernan Aug 09 '16 at 10:50
  • I can't see how to set the Key/Password using bytes. But yes, I should be able to do the encryption using bytes instead of strings. I will give it a try, thank you. – Marc Guillot Aug 09 '16 at 10:55
  • I'm quite confident that the problem should be setting the Password/Key, and I can't see how to set them as binary. Once the key set, I should be able to decrypt in memory, but is fairly complex (you need to initiate and finalize the decryption and get the result through an Stream), looks much overkill to encrypt a 10-byte string using a 24-byte key, as I just need to do. – Marc Guillot Aug 09 '16 at 11:21
  • 3DES should not be used for new work. – zaph Aug 09 '16 at 12:06
  • Since the TripleDES block size is 64 bits (8 bytes) and you want to encrypt ten bytes you have to do some padding. And I see no selection of CBC in Delphi (btw what is CBC*?) and no IV. – gammatester Aug 09 '16 at 12:09
  • Very interesting, gammatester, I didn't know that the block size is 8 bytes, that must be the reason that I get a different result each time, it must be encoding the 6 following bytes. CBC* is supposed to be CBC (I don't know why they add a *), and the IV management is supposed to be automatic http://lockbox.seanbdurkin.id.au/HomePage. – Marc Guillot Aug 10 '16 at 10:11
  • Although I dont know PHP, I would guess from the code that the IV is 8 zero bytes, so automatic IV may not work. – gammatester Aug 10 '16 at 11:45
  • @MarcGuillot did you manage to solve this? I'm facing a similar issue, the EncryptAnsiString that accepts a UnicodeString is pretty weird. In the latest version 3.7 they just conditionally left it out if UNICODE is defined. Great fix. I bet you ended up using EncryptMemory()? – drakorg Jul 20 '17 at 05:44
  • No, sorry Eduardo. We finally solved it on the client side, with Javascript. – Marc Guillot Jul 20 '17 at 06:12

1 Answers1

1

A random IV is generated for each message. The low 8 bytes of the IV are a nonce and the high bytes are zero. These low 8 bytes are prepended to the output.

If you want to send the IV via a side channel, then strip the first 8 bytes out of the nominal ciphertext.

If you want to control the IV, then use version 3.7.0 (https://github.com/SeanBDurkin/tplockbox). You will need to set the advanced options and implement the OnGetIV method.

The asterisk (*) rendered in the property editors for cipher selection and chain mode selection, mean that this selection is a recommended one.

Sean B. Durkin
  • 12,659
  • 1
  • 36
  • 65