The TDCP_cipher component provides the basis of all of the encryption components in the DCPcrypt library. Stream ciphers are directly descended from this class by overriding the Encrypt and Decrypt procedures, where as block ciphers are descended from the TDCP_blockcipher class which its self is descended from the TDCP_cipher class.
type TDCP_cipher= class(TComponent) public property Initialized: boolean; class function GetId: longint; virtual; abstract; class function GetAlgorithm: string; virtual; abstract; class function GetMaxKeySize: longint; virtual; abstract; class function SelfTest: boolean; virtual; abstract; procedure Init(const Key; Size: longint; InitVector: pointer); virtual; procedure InitStr(const Key: string); procedure Burn; virtual; procedure Reset; virtual; abstract; procedure Encrypt(const Indata; var Outdata; Size: longint); virtual; abstract; procedure Decrypt(const Indata; var Outdata; Size: longint); virtual; abstract; function EncryptStream(InStream, OutStream: TStream; Size: longint): longint; function DecryptStream(InStream, OutStream: TStream; Size: longint): longint; function EncryptString(const Str: string): string; virtual; function DecryptString(const Str: string): string; virtual; constructor Create(AOwner: TComponent); override; destructor Destroy; override; published property Id: longint; property Algorithm: string; property MaxKeySize: longint; end;
This property indicates whether or not key setup has been done for the cipher. If this is set to false then either the Init or InitStr procedures need to be called before data can be encrypted or decrypted.
... if not Cipher.Initialized then { We forgot to initialize the cipher! } Cipher.InitStr('Hello World'); Cipher.Encrypt(SomeDataIn,SomeDataOut,Sizeof(SomeDataIn)); ...
This function returns the Id number of the algorithm used by the cipher, each Id number is unique within DCPcrypt and as such can be used to identify which cipher should be used to encrypt/decrypt data. A component can be directly created from the Id number of the algorithm by using the DCPcipherfromid function. As this function is a class function, it can be used without having to first create the component. For example;
Id:= TDCP_blowfish.GetId;
Will return the Id number of the Blowfish algorithm.
This function returns the name of the algorithm used by the cipher, for example the TDCP_blowfish component returns Blowfish. A component can be directly created from the algorithm name by using the DCPcipherfromname function. As this function is a class function, it can be used without having to first create the component. For example;
Name:= TDCP_blowfish.GetAlgorithm;
Will return the algorithm name of the TDCP_blowfish component.
This functions returns the maximum key size you can pass to a cipher in BITS. As this function is a class function, it can be used without having to first create the component. For example;
MaxKeySize:= TDCP_blowfish.GetMaxKeySize;
Will return the maximum key size which can be used with the TDCP_blowfish component.
This function performs a self test on the cipher implementation by encrypting test values for which the results that should be produced are known. This does not need to be called regularly, it's primary purpose is to ensure that the implementation works correctly with different compilers. As this function is a class function, it can be used without having to first create the component. For example;
Result:= TDCP_blowfish.SelfTest;
Will return the test result of the TDCP_blowfish component.
This procedure performs the cipher key setup for the algorithm. It is necessary to call this function (or InitStr) before any of the encryption or decryption routines are used. The Size parameter specifies the size of the key passed in BITS. The InitVector parameter specifies an initialization vector for the cipher of size equal to the block size of the cipher. If this parameter is NIL then an initialization vector is generated automatically from the key.
const Key: array[0..7] of byte= ($12,$34,$56,$78,$9A,$BC,$DE,$F0); var Cipher: TDCP_blowfish; begin Cipher:= TDCP_blowfish.Create(nil); Cipher.Init(Key,Sizeof(Key) * 8 { Size in bits! },nil); { Do encryption/decryption stuff } Cipher.Burn; { Erase key information } Cipher.Free; end;
For initializing the cipher with a string use InitStr instead of Init.
This procedure performs the cipher key setup for the algorithm. The key string is hashed using the SHA1 algorithm to produce a 160bit digest which is then used as the key material to initialize the cipher. Note: When using a passphrase as the key string the chances are that there isn't 160bits of entropy in it and as a result the key produced is actually far weaker than 160bits. When using this procedure to initialize the cipher, an initialization vector is produced in the same way as Init does when passed nil for the InitVector parameter.
const Key= 'Hello World!'; var Cipher: TDCP_blowfish; begin Cipher:= TDCP_blowfish.Create(nil); Cipher.InitStr(Key); { Do encryption/decryption stuff } Cipher.Burn; { Erase key information } Cipher.Free; end;
For initializing the cipher with raw data use Init instead of InitStr.
This procedure clears all sensitive key data stored within the cipher component. This should be called as soon as all encryption/decryption has been performed. After Burn has been called you must call either Init or InitStr to reinitialize the cipher before any further encryptions/decryptions can be performed.
... if Cipher.Initialized then Cipher.Burn; ...
This procedure resets the chaining information stored within the component. Depending on the cipher and the mode of encryption used it is sometimes necessary to reset the chaining information after every block of encrypts and decrypts. For example, the following will not work;
... Cipher.Reset; Str1:= Cipher.EncryptString(Edit1.Text); Str2:= Cipher.EncryptString(Edit2.Text); Str3:= Cipher.EncryptString(Edit3.Text); Cipher.Reset; { This resets the chaining information to start of Str1 } Label2.Text:= Cipher.DecryptString(Str2); { Chaining information at Str2 doesn't equal chaining information at Str1 so this fails } Label3.Text:= Cipher.DecryptString(Str3); Cipher.Reset; ...
There are two ways to solve this problem, by making the chaining information at Str1 equal to that at Str2 (by use of another reset), or by decrypting Str1 as well.
Making the chaining information at Str1 equal to that at Str2;
... Cipher.Reset; Str1:= Cipher.EncryptString(Edit1.Text); Cipher.Reset; Str2:= Cipher.EncryptString(Edit2.Text); Str3:= Cipher.EncryptString(Edit3.Text); Cipher.Reset; { This resets the chaining information to start of Str1 & Str2 } Label2.Text:= Cipher.DecryptString(Str2); { Chaining information at Str2 does equal chaining information at Str1 so this works } Label3.Text:= Cipher.DecryptString(Str3); Cipher.Reset; ...
Decrypting Str1 as well;
... Cipher.Reset; Str1:= Cipher.EncryptString(Edit1.Text); Str2:= Cipher.EncryptString(Edit2.Text); Str3:= Cipher.EncryptString(Edit3.Text); Cipher.Reset; { This resets the chaining information to start of Str1 } Label1.Text:= Cipher.DecryptString(Str1); Label2.Text:= Cipher.DecryptString(Str2); Label3.Text:= Cipher.DecryptString(Str3); Cipher.Reset; ...
The encrypt procedure encrypts a block of data of Size bytes in length and returns it in Outdata.
const Indata: array[0..7] of byte= ($01,$23,$45,$67,$89,$AB,$CD,$EF); var Data: array[0..7] of byte; Cipher: TDCP_blowfish; begin Cipher:= TDCP_blowfish.Create(nil); Cipher.InitStr('Hello World'); Cipher.Encrypt(Indata,Data,Sizeof(Indata)); { Data now contains the encrypted version of Indata } Cipher.Burn; Cipher.Free; end;
The decrypt procedure decrypts a block of data of Size bytes in length and returns it in Outdata.
const Indata: array[0..7] of byte= ($48,$A9,$69,$42,$01,$24,$FF,$F7); var Data: array[0..7] of byte; Cipher: TDCP_blowfish; begin Cipher:= TDCP_blowfish.Create(nil); Cipher.InitStr('Hello World'); Cipher.Decrypt(Indata,Data,Sizeof(Indata)); { Data now contains the decrypted version of Indata } Cipher.Burn; Cipher.Free; end;
This procedure encrypts Size bytes from the InStream to the OutStream using the Encrypt method. It returns the number of bytes encrypted.
var Source, Dest: TFileStream; Cipher: TDCP_blowfish; begin Cipher:= TDCP_blowfish.Create(nil); Source:= TFileStream.Create('ATestFile.dat',fmOpenRead); Dest:= TFileStream.Create('OutputFile.dat',fmCreate); Cipher.InitStr('Hello World'); Cipher.EncryptStream(Source,Dest,Source.Size); Cipher.Burn; Cipher.Free; Source.Free; Dest.Free; end;
This procedure decrypts Size bytes from the InStream to the OutStream using the Decrypt method. It returns the number of bytes decrypted.
var Source, Dest: TFileStream; Cipher: TDCP_blowfish; begin Cipher:= TDCP_blowfish.Create(nil); Source:= TFileStream.Create('OutputFile.dat',fmOpenRead); Dest:= TFileStream.Create('ATestFile.dat',fmCreate); Cipher.InitStr('Hello World'); Cipher.DecryptStream(Source,Dest,Source.Size); Cipher.Burn; Cipher.Free; Source.Free; Dest.Free; end;
This procedure encrypts the string passed and then Base64 encoded to ensure that there are no non-printable characters. When using a block cipher to encrypt a string the mode specified in CipherMode is used. Since it is likely that a chaining mode will be used to encrypt the string you cannot encrypt and then immediately decrypt, you must call Reset first. For example the following will not work;
... s:= Cipher.EncryptString('A nice string'); t:= Cipher.DecryptString(s); ...
To get this to work we need to use Reset.
... Cipher.Reset; s:= Cipher.EncryptString('A nice string'); Cipher.Reset; t:= Cipher.DecryptString(s); ...
This procedure decodes the Base64 encoded string and then decrypts it. When using a block cipher to decrypt a string the mode specified in CipherMode is used.