PDA

View Full Version : ISAAC Cipher



Echo_
08-18-2012, 09:14 PM
The ISAAC Cipher is a fast random number generator. Jagex used it to break AutoRune back in the day by encrypting packet opcodes sent between the client and the server.

http://en.wikipedia.org/wiki/ISAAC_(cipher)

I based the Simba version off of this:
https://svn.assembla.com/svn/runesource/trunk/RuneSource/src/ISAACCipher.java

NOTE: commenting out signed will produce all positive integers, currently it's set to generate both negatives and positives.

{$define signed}

const
RATIO = $9e3779b9;
SIZE_LOG = 8;
SIZE = 1 shl SIZE_LOG;
MASK = (SIZE - 1) shl 2;

type
TCipher = record
Count: Integer;
Results: array[0..255] of {$ifdef signed}Integer{$else}Cardinal{$endif};
Memory: array[0..255] of {$ifdef signed}Integer{$else}Cardinal{$endif};
A, B, C: {$ifdef signed}Integer{$else}Cardinal{$endif};
end;

procedure Isaac(var Cipher: TCipher);
var
I, J, X, Y: Integer;
begin
Inc(Cipher.C);
Cipher.B := Cipher.B + Cipher.C;
J := SIZE div 2;
while I < SIZE div 2 do
begin
X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shl 13);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);

X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shr 6);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);

X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shl 2);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);

X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shr 16);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);
end;

J := 0;
while J < SIZE div 2 do
begin
X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shl 13);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);

X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shr 6);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);

X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shl 2);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);

X := Cipher.Memory[I];
Cipher.A := Cipher.A xor (Cipher.A shr 16);
Cipher.A := Cipher.A + Cipher.Memory[J];
Inc(J);
{$ifdef lape}
Cipher.Memory[I] := Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Results[I] := Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
{$else}
Y := Cipher.Memory[(X and MASK) shr 2] + Cipher.A + Cipher.B;
Cipher.Memory[I] := Y;
Cipher.B := Cipher.Memory[((Y shr SIZE_LOG) and MASK) shr 2] + X;
Cipher.Results[I] := Cipher.B;
{$endif}
Inc(I);
end;
end;

procedure Init(var Cipher: TCipher; Flag: Boolean);
var
I: Integer;
A, B, C, D, E, F, G, H: {$ifdef signed}Integer{$else}Cardinal{$endif};
begin
{$ifdef lape}
A := B := C := D := E := F := G := H := RATIO;
{$else}
A := RATIO;
B := RATIO;
C := RATIO;
D := RATIO;
E := RATIO;
F := RATIO;
G := RATIO;
H := RATIO;
{$endif}
for I := 0 to 3 do
begin
A := A xor (B shl 11);
D := D + A;
B := B + C;
B := B xor (C shr 2);
E := E + B;
C := C + D;
C := C xor (D shl 8);
F := F + C;
D := D + E;
D := D xor (E shr 16);
G := G + D;
E := E + F;
E := E xor (F shl 10);
H := H + E;
F := F + G;
F := F xor (G shr 4);
A := A + F;
G := G + H;
G := G xor (H shl 8);
B := B + G;
H := H + A;
H := H xor (A shr 9);
C := C + H;
A := A + B;
end;

I := 0;
while I < SIZE do
begin
if Flag then
begin
A := A + Cipher.Results[I];
B := B + Cipher.Results[I + 1];
C := C + Cipher.Results[I + 2];
D := D + Cipher.Results[I + 3];
E := E + Cipher.Results[I + 4];
F := F + Cipher.Results[I + 5];
G := G + Cipher.Results[I + 6];
H := H + Cipher.Results[I + 7];
end;

A := A xor (B shl 11);
D := D + A;
B := B + C;
B := B xor (C shr 2);
E := E + B;
C := C + D;
C := C xor (D shl 8);
F := F + C;
D := D + E;
D := D xor (E shr 16);
G := G + D;
E := E + F;
E := E xor (F shl 10);
H := H + E;
F := F + G;
F := F xor (G shr 4);
A := A + F;
G := G + H;
G := G xor (H shl 8);
B := B + G;
H := H + A;
H := H xor (A shr 9);
C := C + H;
A := A + B;

Cipher.Memory[I] := A;
Cipher.Memory[I + 1] := B;
Cipher.Memory[I + 2] := C;
Cipher.Memory[I + 3] := D;
Cipher.Memory[I + 4] := E;
Cipher.Memory[I + 5] := F;
Cipher.Memory[I + 6] := G;
Cipher.Memory[I + 7] := H;
IncEx(I, 8);
end;

if Flag then
begin
I := 0;
while I < SIZE do
begin
A := A + Cipher.Memory[I];
B := B + Cipher.Memory[I + 1];
C := C + Cipher.Memory[I + 2];
D := D + Cipher.Memory[I + 3];
E := E + Cipher.Memory[I + 4];
F := F + Cipher.Memory[I + 5];
G := G + Cipher.Memory[I + 6];
H := H + Cipher.Memory[I + 7];

A := A xor (B shl 11);
D := D + A;
B := B + C;
B := B xor (C shr 2);
E := E + B;
C := C + D;
C := C xor (D shl 8);
F := F + C;
D := D + E;
D := D xor (E shr 16);
G := G + D;
E := E + F;
E := E xor (F shl 10);
H := H + E;
F := F + G;
F := F xor (G shr 4);
A := A + F;
G := G + H;
G := G xor (H shl 8);
B := B + G;
H := H + A;
H := H xor (A shr 9);
C := C + H;
A := A + B;

Cipher.Memory[I] := A;
Cipher.Memory[I + 1] := B;
Cipher.Memory[I + 2] := C;
Cipher.Memory[I + 3] := D;
Cipher.Memory[I + 4] := E;
Cipher.Memory[I + 5] := F;
Cipher.Memory[I + 6] := G;
Cipher.Memory[I + 7] := H;
IncEx(I, 8);
end;
end;

Isaac(Cipher);
Cipher.Count := SIZE;
end;

function GetNextValue(var Cipher: TCipher): {$ifdef signed}Integer{$else}Cardinal{$endif};
begin
if Cipher.Count = 0 then
begin
Isaac(Cipher);
Cipher.Count := SIZE - 1;
end;
Dec(Cipher.Count);
Result := Cipher.Results[Cipher.Count];
end;

{$ifdef lape}
function Cipher: TCipher; overload;
{$else}
function EmptyCipher: TCipher;
{$endif}
begin
Init(Result, False);
end;

function Cipher(Seed: array of {$ifdef signed}Integer{$else}Cardinal{$endif}): TCipher;{$ifdef lape} overload;{$endif}
var
I: Integer;
begin
for I := 0 to SIZE - 1 do
Result.Results[I] := Seed[I];
Init(Result, True);
end;

var
I, Start, Finish: Integer;
C: TCipher;
begin
Start := GetSystemTime;
ClearDebug;
C := {$ifdef lape}Cipher{$else}EmptyCipher{$endif};
for I := 0 to 255 do
WriteLn(GetNextValue(C));
Finish := GetSystemTime;
WriteLn(#13#10' * Took ' + IntToStr(Finish - Start) + ' ms');
end.

I just wrote this because I was bored :p Maybe it will be of use to someone someday.