1

How do you detect decryption failure? I have the following test code:

procedure TForm1.Button1Click(Sender: TObject);
var 
 plainms, cipherms: TMemoryStream;
 tempstr: string;

begin
  plainms := TMemoryStream.Create;
  cipherms := TMemoryStream.Create;
  try
    cipherms.LoadFromFile('rwcx.ini');
    Codec1.Password := '122rkdkdk';  
    try
     Codec1.DecryptStream(plainms, cipherms);
    except on E: Exception do
      showmessage(e.Message);
    end;
    plainms.Position := 0;
    SetLength(tempstr, plainms.Size * 2);
    BinToHex(plainms.Memory, PChar(tempstr), plainms.Size);
    showmessage(tempstr);
  finally
    plainms.Free;
    cipherms.Free;
  end;
end;

The file "rwcx.ini" is just a plain text file that does not contain encrypted data. I am using AES 256 with CBC and version 3.5 of Lockbox installed with "GetIt." I expected the plainms memory stream to be empty or an exception to be raised as decryption is guaranteed to fail. Instead I get garbage in plainms and no exception.

How do you detect decryption has failed? I must be able to detect bad passwords or corrupted input data. What am I missing?

Mike
  • 153
  • 3
  • 11

1 Answers1

2

Encryption is just a transform, in itself it has no concept of correct decryption.

One method is to create HMAC of the encrypted data and prepend that to the encrypted data and on decryption HMAC the encrypted data and compare the HMACs. Be careful to use a HMAC compare function that takes the same amount of time for matching and non-matching values.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • I was hoping that wasn't the case. Somewhere on the library's web pages I read "makes detecting decryption failures easy" or something to that affect. I thought that meant an HMAC was built in. I also read a reply by the author on his forums regarding RSA that stated "wrap the decryption in a try/except block to detect wrong key" I guess this only works for RSA and not AES. I will implement my own HMAC as you suggest. Thanks for the quick reply. – Mike Feb 13 '16 at 02:56
  • Note: Sometimes developers think that checking for valid parity is a solution but it is not totally correct and returning a padding failure to the cient allows a malicious client to obtain the encrypted data without the key, see padding oracle attack. Also AED GCM has authentication built-in but support is still low. – zaph Feb 13 '16 at 03:05
  • Take a look at the [RNCryptor format](https://github.com/RNCryptor/RNCryptor-Spec/blob/master/RNCryptor-Spec-v3.md), it is a good scheme. – zaph Feb 13 '16 at 03:08
  • Very good reading. I would not have thought to put any data in the clear as RNCryptor format suggests. I SHA hashed the plaintext and then encrypted the 32 byte hash + the plaintext. Since the decryption unit decrypts regardless of what I send it, I then verify I have at least 33 bytes of decrypted data. If so, I hash everything after the first 32 bytes and see if the first 32 bytes match the hash of the remainder of the data. This seemed to work without exposing what I'm doing. Thanks for the link! – Mike Feb 13 '16 at 04:13