{$apptype console} PROGRAM RosettaIsaac; USES SysUtils; // TASK globals VAR msg : STRING = 'a Top Secret secret'; VAR key : STRING = 'this is my secret key'; VAR xctx: STRING = ''; // XOR ciphertext VAR mctx: STRING = ''; // MOD ciphertext // ISAAC globals // external results VAR randrsl: ARRAY[0..256] OF CARDINAL; VAR randcnt: cardinal; // internal state VAR mm: ARRAY[0..256] OF CARDINAL; VAR aa: CARDINAL=0; bb: CARDINAL=0; cc: CARDINAL=0; PROCEDURE Isaac; VAR i,x,y: CARDINAL; BEGIN cc := cc + 1; // cc just gets incremented once per 256 results bb := bb + cc; // then combined with bb FOR i := 0 TO 255 DO BEGIN x := mm[i]; CASE (i mod 4) OF 0: aa := aa xor (aa shl 13); 1: aa := aa xor (aa shr 6); 2: aa := aa xor (aa shl 2); 3: aa := aa xor (aa shr 16); END; aa := mm[(i+128) mod 256] + aa; y := mm[(x shr 2) mod 256] + aa + bb; mm[i] := y; bb := mm[(y shr 10) mod 256] + x; randrsl[i]:= bb; END; // this reset was not in original readable.c! randcnt:=0; // prepare to use the first set of results END; {Isaac} // if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. PROCEDURE mix(VAR a,b,c,d,e,f,g,h: CARDINAL); 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; {mix} PROCEDURE iRandInit(flag: BOOLEAN); VAR i,a,b,c,d,e,f,g,h: CARDINAL; BEGIN aa:=0; bb:=0; cc:=0; a:=$9e3779b9; // the golden ratio b:=a; c:=a; d:=a; e:=a; f:=a; g:=a; h:=a; FOR i := 0 TO 3 DO // scramble it mix(a,b,c,d,e,f,g,h); i:=0; REPEAT // fill in mm[] with messy stuff IF flag THEN BEGIN // use all the information in the seed a:=a+randrsl[i ]; b:=b+randrsl[i+1]; c:=c+randrsl[i+2]; d:=d+randrsl[i+3]; e:=e+randrsl[i+4]; f:=f+randrsl[i+5]; g:=g+randrsl[i+6]; h:=h+randrsl[i+7]; END; mix(a,b,c,d,e,f,g,h); mm[i ]:=a; mm[i+1]:=b; mm[i+2]:=c; mm[i+3]:=d; mm[i+4]:=e; mm[i+5]:=f; mm[i+6]:=g; mm[i+7]:=h; i:=i+8; UNTIL i>255; IF (flag) THEN BEGIN // do a second pass to make all of the seed affect all of mm i:=0; REPEAT a:=a+mm[i ]; b:=b+mm[i+1]; c:=c+mm[i+2]; d:=d+mm[i+3]; e:=e+mm[i+4]; f:=f+mm[i+5]; g:=g+mm[i+6]; h:=h+mm[i+7]; mix(a,b,c,d,e,f,g,h); mm[i ]:=a; mm[i+1]:=b; mm[i+2]:=c; mm[i+3]:=d; mm[i+4]:=e; mm[i+5]:=f; mm[i+6]:=g; mm[i+7]:=h; i:=i+8; UNTIL i>255; END; isaac(); // fill in the first set of results randcnt:=0; // prepare to use the first set of results END; {randinit} { Seed ISAAC with a given string. The string can be any size. The first 256 values will be used.} PROCEDURE iSeed(seed: STRING; flag: BOOLEAN); VAR i,m: CARDINAL; BEGIN FOR i:= 0 TO 255 DO mm[i]:=0; m := Length(seed)-1; FOR i:= 0 TO 255 DO BEGIN // in case seed has less than 256 elements IF i>m THEN randrsl[i]:=0 // Pascal strings are 1-based ELSE randrsl[i]:=ord(seed[i+1]); END; // initialize ISAAC with seed iRandInit(flag); END; {iSeed} { Get a random 32-bit value 0..MAXINT } FUNCTION iRandom : Cardinal; BEGIN result := randrsl[randcnt]; inc(randcnt); IF (randcnt >255) THEN BEGIN Isaac(); randcnt := 0; END; END; {iRandom} { Get a random character in printable ASCII range } FUNCTION iRandA: BYTE; BEGIN result := iRandom mod 95 + 32; END; { convert an ASCII string to a hexadecimal string } FUNCTION ascii2hex(s: STRING): STRING; VAR i,l: CARDINAL; BEGIN result := ''; l := Length(s); FOR i := 1 TO l DO result := result + IntToHex(ord(s[i]),2); END; { XOR encrypt on random stream. Output: string of hex chars } FUNCTION Vernam(msg: STRING): STRING; VAR i: CARDINAL; BEGIN result := ''; FOR i := 1 to length(msg) DO result := result + chr(iRandA xor ord(msg[i])); result := ascii2hex(result); END; { Get position of the letter in chosen alphabet } FUNCTION letternum(letter, start: CHAR): byte; BEGIN result := (ord(letter)-ord(start)); END; { Caesar-shift a character places: Generalized Vigenere } FUNCTION Caesar(ch: CHAR; shift, modulo: INTEGER; start: CHAR): CHAR; VAR n: INTEGER; BEGIN n := letternum(ch,start) + shift; n := n MOD modulo; result := chr(ord(start)+n); END; { Vigenere mod 95 encryption. Output: string of hex chars } FUNCTION Vigenere(msg: STRING): STRING; VAR i: CARDINAL; BEGIN result := ''; FOR i := 1 to length(msg) DO result := result + Caesar(msg[i],iRandA,95,' '); result := ascii2hex(result); END; BEGIN // 1) seed ISAAC with the key iSeed(key,true); // 2) Vernam XOR encryption xctx := Vernam(msg); // 3) MOD encryption mctx := Vigenere(msg); // program output Writeln('Message: ',msg); Writeln('Key : ',key); Writeln('XOR : ',xctx); Writeln('MOD : ',mctx); END.