Here is a working version using streams for the encrypted data. The only code that has changed is the Encrypt and Decrypt methods.
xtea.pas
Code:
unit xtea;
interface
uses
SysUtils, Classes;
type
PKey128 = ^TKey128;
TKey128 = array [0..3] of longword;
PBlock64 = ^TBlock64;
TBlock64 = array [0..1] of longword;
TXTea = class(TObject)
private
FKey: TKey128;
FInitialized: Boolean;
public
property Initialized: boolean read FInitialized default false;
procedure Burn;
procedure InitKey(const Key: string);
procedure Encrypt(const Input: string; Stream: TStream);
function Decrypt(Stream: TStream; Count: Integer): string;
destructor Destroy; override;
constructor Create;
end;
implementation
const
DELTA = $9e3779b9;
XTEA_BLANK: TBlock64 = (0,0);
XTEA_BURN: TKey128 =(0,0,0,0);
destructor TXTea.Destroy;
begin
Burn;
inherited;
end;
constructor TXTea.Create;
begin
inherited;
Burn;
end;
procedure TXTea.Burn;
begin
FKey := XTEA_BURN;
FInitialized := False;
end;
procedure TXTea.InitKey(const Key: string);
var L: integer;
begin
if Length(Key) <= SizeOf(FKey) then
L := Length(Key)
else
L := SizeOf(FKey);
Move(Key[1],FKey[0],L);
FInitialized := True;
end;
procedure TXTea.Encrypt(const Input: string; Stream: TStream);
var i,l: integer;
v: TBlock64;
procedure CipherXTea(v: PBlock64; key: PKey128);
var sum: longword;
i: integer;
begin
Sum:= 0;
for i:= 0 to 31 do
begin
Inc(v[0], ((v[1] shl 4 xor v[1] shr 5) + v[1]) xor (Sum + Key[Sum and 3]));
Inc(Sum, Delta);
Inc(v[1], ((v[0] shl 4 xor v[0] shr 5) + v[0]) xor (Sum + Key[Sum shr 11 and 3]));
end;
end;
begin
if not Initialized then
raise Exception.Create('Error: You must define a password.');
l := (Length(Input) + 1 + (SizeOf(v) - 1)) and (not (SizeOf(v) - 1));
i := 1;
while i < l do
try
v := XTEA_BLANK;
if l - (i - 1) < SizeOf(v) then
Move(Input[i], v, l - (i - 1))
else
Move(Input[i], v, SizeOf(v));
CipherXTea(@v, @FKey);
Stream.Write(v, SizeOf(v));
Inc(i, SizeOf(v));
except
raise;
end;
end;
function TXTea.Decrypt(Stream: TStream; Count: Integer): string;
var i: integer;
v: TBlock64;
procedure DecipherXTea(v: PBlock64; Key: PKey128);
var
i: Integer;
Sum: Longword;
begin
Sum:= $C6EF3720;
for i:= 0 to 31 do
begin
Dec(v[1], ((v[0] shl 4 xor v[0] shr 5) + v[0]) xor (Sum + Key[Sum shr 11 and 3]));
Dec(Sum, Delta);
Dec(v[0], ((v[1] shl 4 xor v[1] shr 5) + v[1]) xor (Sum + Key[Sum and 3]));
end;
end;
begin
if not Initialized then
raise Exception.Create('Error: You must define a password.');
SetLength(Result, Count);
i := 1;
while i < Count do
try
v := XTEA_BLANK;
Stream.Read(v, SizeOf(v));
DecipherXTea(@v, @FKey);
Move(v, Result[i], SizeOf(v));
Inc(i, SizeOf(v));
except
raise;
end;
end;
end.
Sample app
Code:
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, xtea;
type
TForm4 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
Button1: TButton;
Button2: TButton;
procedure Button2Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
FXTea: TXTea;
FStream: TMemoryStream;
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.FormCreate(Sender: TObject);
begin
FXTea := TXTea.Create;
FXTea.InitKey('0123456789abcdef');
FStream := TMemoryStream.Create;
end;
procedure TForm4.FormDestroy(Sender: TObject);
begin
FStream.Free;
FXTea.Free;
end;
procedure TForm4.Button1Click(Sender: TObject);
var
Input: String;
begin
Input := Memo1.Lines.Text;
(* Set the size and position of the stream outside the method so that
we could append to an existing stream if we wanted to. *)
(* Add one to allow for the NUL terminator on the string *)
FStream.SetSize(Length(Input) + 1);
FStream.Position := 0;
FXTea.Encrypt(Input, FStream);
end;
procedure TForm4.Button2Click(Sender: TObject);
begin
(* This sample assumes that the stream contains only the encrypted data,
but it could be part of a much larger stream. *)
FStream.Position := 0;
Memo2.Lines.Text := FXTea.Decrypt(FStream, FStream.Size);
end;
end.
Press Button1 to encrypt the text in Memo1 into a TMemoryStream. Press Button2 to decrypt the stream into Memo2.
Bookmarks