I am trying to implement a simple text file encryption technique and I am using the following code to do so. The code is not written by me, I just googled and got it. The encryption technique seems to be pretty simple, concise and easy to implement. I see that it has only one function that can do the encryption and the decryption on the fly. Just pass the key it will do the trick. However, I just wanted to know, is it possible for me to check if the key is passed by the user is correct or not. Currently it will just encrypt / decrypt the text file based on the passed key. But there is no mechanism to check if we are decrypting with correct key or not. Whatever the key we pass, it will get decrypted, but it will not be readable. Any idea how to tackle this problem..?
procedure TEnDeCrypt.EnDecryptFile(pathin, pathout: string; Chave: Word);
var
InMS, OutMS: TMemoryStream;
cnt: Integer;
C: byte;
begin
InMS := TMemoryStream.Create;
OutMS := TMemoryStream.Create;
try
InMS.LoadFromFile(pathin);
InMS.Position := 0;
for cnt := 0 to InMS.Size - 1 DO
begin
InMS.Read(C, 1);
C := (C xor not (ord(chave shr cnt)));
OutMS.Write(C, 1);
end;
OutMS.SaveToFile(pathout);
finally
InMS.Free;
OutMS.Free;
end;
end;
Generate a checksum on the plain text using a hashing algorithm and store it at the beginning of the encrypted file.
You can verify the key by hashing the decrypted text and ensure that the checksum matches.
If you use a strong hashing algorithm such as SHA256 to generate the checksum, it will be difficult for the user to automate a brute force attack because it will be computationally expensive.
To ensure that the file is intact, you may also wish to store a checksum on the encrypted file and store it in the file header as well. Otherwise, there will be no way to differentiate an invalid password from a truncated file.
I typically use the Blowfish encryption algorithm, which is available for Delphi from multiple sources. Blowfish has no known weaknesses and is fairly compact and fast.
If you are aware of the kind of content your file will have (whether it is a binary file / text file etc), then you can sample the text and see if there are any non-ASCII or characters that are not expected in the file after decryption.
Another thing you can do is to add a watermark text at the end of the file. After decryption, you can check if your watermark is containing data that is outside the expected data-type (if you are expecting only characters and you see a non-char data in it, then there is possibly an issue). This though is not fool-proof, just a sort of a buffer for you.
That said, I will ask you this question - what is the intent behind this? The key the user is passing is to encrypt; so if the user is passing an invalid key, then they get invalid output. Why do you need to steer the user towards the right key? And if there is some business use-case for something like that, then you also need to understand that this is going to make your encryption very easy to break. I will suggest that you pick up a standard encryption algorithm and use that to encrypt your file.
The correct way to do what you are asking for is to Encrypt-then-Authenticate the data. There is some relevant discussion here: Should we MAC-then-encrypt or encrypt-then-MAC?
The conventional way is to first use a standard cipher in a standard mode, such as AES in CBC mode, and then calculate a HMAC (such as HMAC-SHA256) over the cipher text. There are also some cipher modes, such as CCM, EAX, GCM, that will perform both encryption and authentication.
Do not use a hash instead of a HMAC for this.
The key you use for encryption must be independent from the key you use for authentication. You could e.g. generate both randomly, but absolutely not using the System.Random function. If you are deploying to Vista SP2 or later, you could use CryptGenRandom from the Windows API, but otherwise you should use a cryptographic library with support for cryptographic random number generation.
If you use password based encryption, use a PBKDF2 implementation for deriving the encryption key and authentication key. There are four common ways to ensure the two keys are independent:
- Use two separate Salt values;
- Use a single salt but concatenate it with separate "labels", e.g. the strings 'E' and 'A' respectively,
- Generate a twice as long derived key and use one half as encryption key and the other half as authentication key, or
- Let the derived key be a "key encryption key" you use for encrypting randomly generated encryption keys and authentication keys.