Since the size of the code isn't excessive, messages tend to disappear quickly from attachments and I take this matter quite seriously, I post the code here too.

Please note that the code is neither pretty nor optimized. But it works, and in this case that's fatal.

---

Here is a small demonstration of how to perform a trivial known plain
text differential attack against EZCrypt. You need approximately 8 bytes
of consequtive known plain text to narrow down the number of possible
keys to below 100. It will just take a couple of seconds to run this
attack. Increasing the amount of known plain text will further reduce
the number of possible keys with practically no time penalty.




unit Unit1;

interface

uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
   Dialogs, StdCtrls;

type
   EightByte = array [0..7] of Byte;
   ThreeWord = array [0..2] of Word;
   Guess = packed record
     L: Byte;
     J: Byte;
     K: Word;
     R: Word;
   end;

   TForm1 = class(TForm)
     Button1: TButton;
     Memo1: TMemo;
     Button2: TButton;
     Button3: TButton;
     procedure Button1Click(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure Button2Click(Sender: TObject);
   private
     PT: EightByte; // Plain text
     KS: EightByte; // Key stream, i.e. CT xor PT
     RealKey: ThreeWord;
     Guesses: array of Guess;
     GuessCount: Integer;
   public
     { Public declarations }
   end;

var
   Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var
   W: Word;
   I: Integer;
begin
   RealKey[0] := Random(65535) + 1;
   RealKey[1] := Random(65535) + 1;
   RealKey[2] := Random(65535) + 1;

   W := RealKey[2];
   for I := 0 to 7 do begin
     PT[I] := Random(256);
     KS[I] := W shr 8;
     W := Byte(PT[I] + W)*RealKey[0] + RealKey[1];
   end;
   SetLength(Guesses,0);
   GuessCount := 0;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   Randomize;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
   I, J, K, L: Integer;
   P1, P2, W, R: Word;
   D1, D: Byte;
begin
   D1 := Byte(KS[2] - KS[1]);
   for I := -256 to 255 do begin
     for K := 1 to 65535 do begin
       W := I*K;
       D := W shr 8;
       if (D = D1) or (D = Byte(D1-1)) or (D = Byte(D1+1)) then begin
         for L := 0 to 255 do begin
           J := Byte(I - PT[1] + L + PT[0]);
           P1 := Byte(L + PT[0])*K;
           P2 := Byte(J + PT[1])*K;
           R := Word(Word(KS[1] shl 8) + J - P1);
           W := Word(P2 + R);
           if (W shr 8) = KS[2] then begin
             W := Byte(W + PT[2])*K + R;
             if (W shr 8) = KS[3] then begin
               W := Byte(W + PT[3])*K + R;
               if (W shr 8) = KS[4] then begin
                 W := Byte(W + PT[4])*K + R;
                 if (W shr 8) = KS[5] then begin
                   W := Byte(W + PT[5])*K + R;
                   if (W shr 8) = KS[6] then begin
                     W := Byte(W + PT[6])*K + R;
                     if (W shr 8) = KS[7] then begin
                       if Length(Guesses) = GuessCount then
                         SetLength(Guesses,GuessCount + 256);
                       Guesses[GuessCount].J := J;
                       Guesses[GuessCount].L := L;
                       Guesses[GuessCount].K := K;
                       Guesses[GuessCount].R := R;
                       Inc(GuessCount);
                     end;
                   end;
                 end;
               end;
             end;
           end;
         end;
       end;
     end;
   end;
   for I := 0 to GuessCount - 1 do
     if (Guesses[I].K = RealKey[0]) and
        (Guesses[I].R = RealKey[1]) then
       Memo1.Lines.Add('Hit');
   Memo1.Lines.Add(IntToStr(GuessCount));
end;

end.


-- 
Henrick Hellström,
StreamSec http://www.streamsec.com
Need to security enhance your Delphi application? Don't settle for anything less than StrSecII:
http://www.streamsec.com/download_strsec50.asp

 

I like the EZCrypt unit.  Do you have an example of how to use it in a
program for us newbies?
Thanks,
Jim (jmiller55@hotmail.com)

On Sat, 27 Apr 2002 10:13:47 GMT, Ben Hochstrasser
<tictactux123^H^H^H@surfeu.ch> wrote:


>Here's a simple yet effective encryption function (seen at borlands' eons ago, turned into a unit and
>made faster...)
>
>unit EZCrypt;
>
>{modeled by Ben Hochstrasser(bhoc@surfeu.ch) after some code snippet from borland)
>
>interface
>
>uses Windows, Classes;
>
>type
>  TWordTriple = Array[0..2] of Word;
>
>function FileEncrypt(InFile, OutFile: String; Key: TWordTriple): boolean;
>function FileDecrypt(InFile, OutFile: String; Key: TWordTriple): boolean;
>function TextEncrypt(const s: string; Key: TWordTriple): string;
>function TextDecrypt(const s: string; Key: TWordTriple): string;
>function MemoryEncrypt(Src: Pointer; SrcSize: Cardinal; Target: Pointer; TargetSize: Cardinal; Key: TWordTriple): boolean;
>function MemoryDecrypt(Src: Pointer; SrcSize: Cardinal; Target: Pointer; TargetSize: Cardinal; Key: TWordTriple): boolean;
>
>implementation
>
>function MemoryEncrypt(Src: Pointer; SrcSize: Cardinal; Target: Pointer; TargetSize: Cardinal; Key: TWordTriple): boolean;
>var
>  pIn, pOut: ^byte;
>  i : Cardinal;
>begin
>  if SrcSize = TargetSize then
>  begin
>    pIn := Src;
>    pOut := Target;
>    for i := 1 to SrcSize do
>    begin
>      pOut^ := pIn^ xor (Key[2] shr 8);
>      Key[2] := Byte(pIn^ + Key[2]) * Key[0] + Key[1];
>      inc(pIn);
>      inc(pOut);
>    end;
>    Result := True;
>  end else
>    Result := False;
>end;
>
>function MemoryDecrypt(Src: Pointer; SrcSize: Cardinal; Target: Pointer; TargetSize: Cardinal; Key: TWordTriple): boolean;
>var
>  pIn, pOut: ^byte;
>  i : Cardinal;
>begin
>  if SrcSize = TargetSize then
>  begin
>    pIn := Src;
>    pOut := Target;
>    for i := 1 to SrcSize do
>    begin
>      pOut^ := pIn^ xor (Key[2] shr 8);
>      Key[2] := byte(pOut^ + Key[2]) * Key[0] + Key[1];
>      inc(pIn);
>      inc(pOut);
>    end;
>    Result := True;
>  end else
>    Result := False;
>end;
>
>function TextCrypt(const s: string; Key: TWordTriple; Encrypt: Boolean): string;
>var
>  bOK: Boolean;
>begin
>  SetLength(Result, Length(s));
>  if Encrypt then
>    bOK := MemoryEncrypt(PChar(s), Length(s), PChar(Result), Length(Result), Key)
>  else
>    bOK := MemoryDecrypt(PChar(s), Length(s), PChar(Result), Length(Result), Key);
>  if not bOK then Result := '';
>end;
>
>function FileCrypt(InFile, OutFile: String; Key: TWordTriple; Encrypt: Boolean): boolean;
>var
>  MIn, MOut: TMemoryStream;
>begin
>  MIn := TMemoryStream.Create;
>  MOut := TMemoryStream.Create;
>  Try
>    MIn.LoadFromFile(InFile);
>    MOut.SetSize(MIn.Size);
>    if Encrypt then
>      Result := MemoryEncrypt(MIn.Memory, MIn.Size, MOut.Memory, MOut.Size, Key)
>    else
>      Result := MemoryDecrypt(MIn.Memory, MIn.Size, MOut.Memory, MOut.Size, Key);
>    MOut.SaveToFile(OutFile);
>  finally
>    MOut.Free;
>    MIn.Free;
>  end;
>end;
>
>function TextEncrypt(const s: string; Key: TWordTriple): string;
>begin
>  Result := TextCrypt(s, Key, True);
>end;
>
>function TextDecrypt(const s: string; Key: TWordTriple): string;
>begin
>  Result := TextCrypt(s, Key, False);
>end;
>
>function FileEncrypt(InFile, OutFile: String; Key: TWordTriple): boolean;
>begin
>  Result := FileCrypt(InFile, OutFile, Key, True);
>end;
>
>function FileDecrypt(InFile, OutFile: String; Key: TWordTriple): boolean;
>begin
>  Result := FileCrypt(InFile, OutFile, Key, False);
>end;
>
>end.
>
>
>