Introduction to strong crypto programming in Borland Delphi
2001 Uri Fridman <urifrid@hushmail.com>
Download the source
code of this article!
![]() |
Some words
Historically, cryptography was used by governments throughout the ages to conceal secret messages. The need to keep "state secrets" out of reach of the general public led to the invention of several encryption methods.
In the 20th century these methods were taken one step beyond as they were automated by introducing machines such as the Enigma (broken by the allies in WWII).
With the introduction of the computer, this automated process became even easier and yet newer cryptography methods were invented.
Today computers are everywhere.
Governments have access to almost everything. System Administrators have access to most of the files in your HD. Competition has access to stolen laptops... I mean, I don't want to sound "too" paranoid but in today's world, privacy is getting more and more difficult to achieve.
But don't worry. We have Cryptography to help us.
Warranty
NO WARRANTY.
THIS ARTICLE COMES WITH NO WARRANTY, AND IS PROVIDED ON AN "AS IS" BASIS. YOU ASSUME THE ENTIRE COST OF ANY DAMAGE RESULTING FROM THE INFORMATION CONTAINED IN OR PRODUCED BY THE CONTENTS OF THIS ARTICLE. YOU ASSUME ALL RESPONSIBILITIES FOR SELECTION OF THIS ARTICLE TO ACHIEVE YOUR INTENDED RESULTS, AND FOR THE INSTALLATION OF, USE OF, AND RESULTS OBTAINED FROM IT. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, URI, HIS SUPPLIERS AND OTHERS WHO MAY DISTRIBUTE THIS ARTICLE DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, CONFORMANCE WITH DESCRIPTION, AND NON-INFRINGEMENT, WITH RESPECT TO THIS SOFTWARE PRODUCT.
IN OTHER WORDS: USE AT YOUR OWN RISK
Definitions
In crypto terminology a plain readable file is called Plaintext. The process of scrambling its contents in order to make it unreadable is called Encryption, thus we are Encrypting the file. This unreadable message is now called Ciphertext. The opposite operation, unscrambling the ciphertext, is called Decryption, thus we Decrypt the file.
These two processes use a Key to encrypt or decrypt the file. Only by knowing the correct key we should be able to decrypt a message encrypted with that key.
Warning
These definitions are all good and nice but the real world is a little different. It might look easy and fun to create Ciphers (cryptographic algorithms) but it's not.
Good crypto looks the same as bad crypto. Both output unreadable garbage. But don't be fooled. Always use public and well known ciphers, one that has been studied by professionals and has been analyzed over the years. Always try to get the source code for the ciphers. Go to the following link to learn how to differentiate a good product from a bad one:
http://www.interhack.net/people/cmcurtin/snake-oil-faq.html
I tried to be as accurate as possible when writing this article. However English is not my mother tongue and I'm not a professional cryptographer, so some mistakes can appear in the article. Please feel free to comment about them or other issues by sending an email to <urifrid@hushmail.com>.
The algorithm
I chose Twofish as the algorithm for this introduction. I did it for several reasons:
It was written by Bruce Schneier (http://www.counterpane.com), a well known cryptographer and cryptanalyst
It hasn't been broken
It's easy to use
IT'S PUBLIC. The source code can be found in several places.
It can be used in any mode: ECB, CBC, CFB 8bit, OFB, OFB counter 8bit. To know more about modes read Applied Crytography by Bruce Schneier or go to his web site: http://www.counterpane.com
In short, Twofish is:
A 128 bit block cipher. Encrypts blocks of 128 bits in size.
128, 192 or 256 bits keys. Can use several lengths of keys. In general, if a cipher has 128 bits key it would take 2^128 tries to try each and every key.
Performs 16 rounds encryption. It iterates the cipher 16 times before returning ciphertext.
The code in Delphi for this algorithm was ported from the original C implementation by David Barton (davebarton@bigfoot.com). You can download several other ciphers from his web page:
http://www.scramdisk.clara.net
I'm providing all the files that this article uses. You will find them in the archive that accompanies this article.
The code
Create a new project. Add 3 edit boxes
(Edit1, Edit2 and Edit3). Add 4 buttons
(encrypt, decrypt, hash and browse).
Also add a radiogroup and call it RadioHex, insert two radiobuttons
in there, one "Show in Hex" and the other "Show in Base64".
We are going to add the following to the uses clause:
uses SHA1, Twofish, Base64;
SHA1is the Hash. One-way hash functions are like fingerprints of the data being hashed, it takes variable-length input and produces a fixed-length output (160 bits in SHA1). The hash function ensures that, if the information is changed in any way —even by just one bit— an entirely different output value is produced. This is useful in many ways. One of them for example is to encrypt a file and then make a hash of that encrypted file. You send both the file and the hash of it. When the other end gets the file he or she can check if the file was tampered with by creating a hash of the file and comparing it with the hash sent. Of course the hash has to be sent in a secure way to be sure that it is untouched (probably using some public key encryption algorithm like RSA). We are going to use hashes to create a fingerprint of both the password entered by the user and the encrypted file.TWOFISHis the encryption algorithm.Base64is a way of coding output so it has only printable characters.
Add the following procedures to your program:
// produces a hash of a string
procedure _HashString(s: string; var Digest: TSHA1Digest);
var
Context: TSHA1Context; // record to store intermediate
// data
begin
SHA1Init(Context); // initialize the data record
SHA1Update(Context,@S[1],Length(S)); // update the data record with
// the string
SHA1Final(Context,Digest); // produce the final hash
end;
// produces a hash of a file
procedure _HashFile(filename: string; var Digest: TSHA1Digest);
var
Context: TSHA1Context; // record to store intermediate
// data
Source: file; // source file
Buffer: array[1..8192] of byte; // read buffer
Read: integer; // number of bytes read
begin
AssignFile(Source,filename);
try
Reset(Source,1);
except
MessageDlg('Unable to open source file.',mtInformation,[mbOK],0);
Exit;
end;
SHA1Init(Context); // initialize the data structure
repeat
BlockRead(Source,Buffer,Sizeof(Buffer),Read);
SHA1Update(Context,@Buffer,Read); // update the hash
until Read<> Sizeof(Buffer);
SHA1Final(Context,Digest); // produce the final hash
CloseFile(Source);
end;
These procedures will produce the One-Way Hash for files and strings.
Note that the encryption and decryption process will be like this:
get a hash of the password
initialize the key in the algorithm using the hash
make an IV (the first block to use in the chaining modes)
encrypt or decrypt
burn data (key in memory, IV, etc.) and sets the algorithm for the next task.
(Optional) get a hash of the encrypted file
In (1) we generate the hash of the user's password. This hash will be used in (2) to initialize the key. This key is NOT the password the user typed. In (3) we generate the first block of encrypted data, this block contains random data. This is done because we are using one of the chaining modes and we need and each block depends on the previous one to be encrypted. This helps to hide patters in the text like redundancy and other file headers (like the "PK" in zipped files). In (4) we perform the actual encryption/decryption and in (5) we get rid of the data place in memory (we don't want any sniffer stealing our password, right?)
So, in the OnClick procedure for the button you
called Encrypt you can
write the following (Warning, this will OVERWRITE the original file.
Unless you remember the password you won't be able to recover the data):
var
KeyData: TTwofishData; // the initialized key data
Digest: TSHA1Digest;
IV: array[0..15] of byte; // the initialization vector needed for
// chaining modes
Buffer: array[0..8191] of byte;
Source,source2: file;
i, j, n: integer;
Key: string;
NumRead, NumWritten: Integer;
begin
Key:= edit2.Text; // you wrote the password in edit2
_HashString(Key,Digest);
TwofishInit(KeyData,@Digest,Sizeof(Digest),nil); // initialize the
// key data using a hash of the key
FillChar(IV,Sizeof(IV),0); // make the IV all zeros
TwofishEncryptCBC(KeyData,@IV,@IV); // encrypt the IV to
// get a 'random' IV
Move(IV,KeyData.InitBlock,Sizeof(KeyData.InitBlock)); // move the
// IV into the keydata so can use chaining
TwofishReset(KeyData); // reset the keydata so it uses the new IV
AssignFile(Source, edit1.Text); // file to encrypt in edit1
try
Reset(Source,1);
except
TwofishBurn(KeyData); // get rid of the data in memory
MessageDlg('File cannot be opened...', mtInformation, [mbOK], 0);
Edit2.text:='00000000000000000000000000000000';
Edit2.text:='';
Exit;
end;
repeat
n:= FilePos(Source);
BlockRead(Source,Buffer,Sizeof(Buffer),i);
for j:= 1 to (i div 16) do // 16 is the blocksize of Twofish
// so process in 16 byte blocks
TwofishEncryptCBC(KeyData,@Buffer[(j-1)*Sizeof(IV)], // encrypt!
@Buffer[(j-1)*Sizeof(IV)]);
if (i mod 16)<> 0 then // encrypt the last bytes that don't
// fit in to a full block
begin
Move(KeyData.LastBlock,IV,Sizeof(IV));
TwofishEncryptCBC(KeyData,@IV,@IV); // encrypt the full block
// again (so that it is encrypted twice)
for j:= 1 to (i mod 16) do
// xor this encrypted block with the short block
Buffer[(i and not 15)+j]:= Buffer[(i and not 15)+j] xor IV[j];
end;
Seek(Source,n);
BlockWrite(Source,Buffer,i); // write out the buffer to the file
until i<> Sizeof(Buffer);
CloseFile(Source);
TwofishBurn(KeyData); // get rid of data
Edit2.text:='00000000000000000000000000000000';
Edit2.text:='';
Edit1.text:='';
MessageDlg('All done. File Encrypted with the same name as the ' +
'original.', mtInformation,[mbOK],0);
end;
Presto! We just encrypted the file in Edit1 with
the password in Edit2!
To decrypt do exactly the same, but instead of using TwofishEncryptCBC()
use:
TwofishDecryptCBC(KeyData,@Buffer[(j-1)*Sizeof(IV)],
@Buffer[(j-1)*Sizeof(IV)]);
Simple, huh?
Ok, you have your encrypted file. Some nice touch will be to generate the hash of that encrypted file and send it along with it.
To achieve this we will use the _HashFile procedure we wrote before. On
the OnClick procedure for the button you named Hash add
the following:
procedure TForm1.HashClick(Sender: TObject);
var
Digest: TSHA1Digest; // binary form of the hash
i: integer;
begin
if Edit1.Text='' then exit; // make sure we have a file to hash
_HashFile(Edit1.Text,Digest); // calculate the hash
// and store in Digest
if radiohex.ItemIndex=0 then // we want to show the
// hash in hexadecimal
begin
Edit3.Text:= '0x';
for i:= 0 to (Sizeof(Digest)-1) do
Edit3.Text:= Edit3.Text+IntToHex(Digest[i],2); // convert Digest
// to a hexadecimal string
end
else // in base64
begin
Edit3.Text:= '';
for i:= 0 to (Sizeof(Digest)-1) do
Edit3.Text:= Edit3.Text+chr(Digest[i]); // convert Digest to a
// base64
Edit3.Text:=B64Encode(Edit3.Text);
end;
end;
Now can choose to save the hash to a file and compress both the encrypted file and its hash in one single .zip archive. We can now send the zip file to a friend being sure that only him/her can decrypt it.
This is a simple application. A lot can be added to make it more secure but this is just and example, it's up to you to add your own code and remember:
"...may the source be with you."
Source Code
for SHA1, Twofish and Base64 along
with a program using them
can be found in the archive that
accompanies this article. Please be sure to read the warranty very carefully.
Thanks.
Uri, February 10, 2001. - urifrid@hushmail.com
NOTE: In case you are insterested, Uri has a freeware application that presents an explorer-like interface and allows to encrypt and decrypt files. There's also a console version available:
http://www.geocities.com/urifrid/soft.html
![]() |



