The ISAAC cipher: Difference between revisions
Content added Content deleted
(→{{header|Pascal}}: [0 .. 255] instead of [0..256]; unnecessary variables removed) |
(→{{header|Pascal}}: Spaces and indenting according to coding guidelines. The logic remained unchanged.) |
||
Line 3,024: | Line 3,024: | ||
<lang Pascal> |
<lang Pascal> |
||
PROGRAM RosettaIsaac; |
PROGRAM RosettaIsaac; |
||
USES |
USES |
||
StrUtils; |
|||
TYPE |
|||
iMode = (iEncrypt, iDecrypt); |
|||
TYPE iMode = (iEncrypt,iDecrypt); |
|||
// TASK globals |
// TASK globals |
||
VAR |
|||
VAR msg : STRING = 'a Top Secret secret'; |
|||
msg : String = 'a Top Secret secret'; |
|||
key : String = 'this is my secret key'; |
|||
xctx: String = ''; // XOR ciphertext |
|||
mctx: String = ''; // MOD ciphertext |
|||
xptx: String = ''; // XOR decryption (plaintext) |
|||
mptx: String = ''; // MOD decryption (plaintext) |
|||
// ISAAC globals |
// ISAAC globals |
||
VAR |
|||
// external results |
|||
// external results |
|||
VAR randrsl: ARRAY[0 .. 255] OF CARDINAL; |
|||
randrsl: ARRAY[0 .. 255] OF Cardinal; |
|||
randcnt: CARDINAL; |
|||
randcnt: Cardinal; |
|||
// internal state |
|||
VAR mm: ARRAY[0 .. 255] OF CARDINAL; |
|||
aa: CARDINAL = 0; bb: CARDINAL = 0; cc: CARDINAL = 0; |
|||
// internal state |
|||
mm: ARRAY[0 .. 255] OF Cardinal; |
|||
aa: Cardinal = 0; |
|||
bb: Cardinal = 0; |
|||
cc: Cardinal = 0; |
|||
PROCEDURE Isaac; |
PROCEDURE Isaac; |
||
VAR |
|||
VAR i,x,y: CARDINAL; |
|||
i, x, y: Cardinal; |
|||
BEGIN |
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]; |
|||
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; |
|||
END; |
|||
aa := mm[(i+128) mod 256] + aa; |
|||
aa := mm[(i + 128) MOD 256] + aa; |
|||
mm[ |
y := mm[(x SHR 2) MOD 256] + aa + bb; |
||
mm[i] := y; |
|||
bb := mm[(y SHR 10) MOD 256] + x; |
|||
randrsl[i]:= bb; |
|||
randrsl[i] := bb; |
|||
END; |
|||
END; |
|||
// this reset was not in the original readable.c |
|||
randcnt := 0; // prepare to use the first set of results |
|||
END; |
END; // Isaac |
||
PROCEDURE Mix(VAR a, b, c, d, e, f, g, h: Cardinal); |
|||
// 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 |
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; |
END; // Mix |
||
PROCEDURE iRandInit(flag: |
PROCEDURE iRandInit(flag: Boolean); |
||
VAR |
|||
VAR i,a,b,c,d,e,f,g,h: CARDINAL; |
|||
i, a, b, c, d, e, f, g, h: Cardinal; |
|||
BEGIN |
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; |
|||
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 |
|||
IF flag THEN BEGIN // use all the information in the seed |
|||
BEGIN // use all the information in the seed |
|||
a+=randrsl[i ]; b+=randrsl[i+1]; c+=randrsl[i+2]; d+=randrsl[i+3]; |
|||
a += randrsl[i ]; b += randrsl[i + 1]; |
|||
c += randrsl[i + 2]; d += randrsl[i + 3]; |
|||
e += randrsl[i + 4]; f += randrsl[i + 5]; |
|||
g += randrsl[i + 6]; h += randrsl[i + 7]; |
|||
END; |
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 ] := 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; |
mm[i + 4] := e; mm[i + 5] := f; mm[i + 6] := g; mm[i + 7] := h; |
||
i += 8; |
|||
UNTIL i > 255; |
|||
IF flag THEN |
|||
BEGIN |
|||
// do a second pass to make all of the seed affect all of mm |
|||
// do a second pass to make all of the seed affect all of mm |
|||
i:=0; |
|||
i := 0; |
|||
REPEAT |
|||
a+=mm[i ]; b+=mm[i+1]; c+=mm[i+2]; d+=mm[i+3]; |
|||
a += mm[i ]; b += mm[i + 1]; c += mm[i + 2]; d += mm[i + 3]; |
|||
e += mm[i + 4]; f += mm[i + 5]; g += mm[i + 6]; h += mm[i + 7]; |
|||
mix(a,b,c,d,e,f,g,h); |
|||
Mix(a, b, c, d, e, f, g, h); |
|||
mm[i |
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+=8; |
|||
i += 8; |
|||
UNTIL i > 255; |
|||
END; |
|||
isaac(); // fill in the first set of results |
|||
Isaac(); // fill in the first set of results |
|||
randcnt := 0; // prepare to use the first set of results |
|||
END; {randinit} |
|||
END; // iRandInit |
|||
// Seed ISAAC with a given string. |
|||
// The string can be any size. The first 256 values will be used. |
|||
{ Seed ISAAC with a given string. |
|||
PROCEDURE iSeed(seed: String; flag: Boolean); |
|||
The string can be any size. The first 256 values will be used.} |
|||
VAR |
|||
PROCEDURE iSeed(seed: STRING; flag: BOOLEAN); |
|||
i, m: Cardinal; |
|||
BEGIN |
BEGIN |
||
FOR i := 0 TO 255 DO |
|||
mm[i] := 0; |
|||
m := Length(seed)-1; |
|||
m := Length(seed) - 1; |
|||
FOR i:= 0 TO 255 DO BEGIN |
|||
FOR i := 0 TO 255 DO |
|||
// in case seed has less than 256 elements |
|||
BEGIN |
|||
IF i>m THEN randrsl[i]:=0 |
|||
// in case seed has less than 256 elements |
|||
// Pascal strings are 1-based |
|||
IF i > m THEN |
|||
ELSE randrsl[i]:=ord(seed[i+1]); |
|||
randrsl[i] := 0 |
|||
END; |
|||
// Pascal strings are 1-based |
|||
// initialize ISAAC with seed |
|||
ELSE |
|||
iRandInit(flag); |
|||
randrsl[i] := Ord(seed[i + 1]); |
|||
END; {iSeed} |
|||
END; |
|||
// initialize ISAAC with seed |
|||
iRandInit(flag); |
|||
END; // iSeed |
|||
// Get a random 32-bit value 0..MAXINT |
|||
FUNCTION iRandom |
FUNCTION iRandom: Cardinal; |
||
BEGIN |
BEGIN |
||
iRandom := randrsl[randcnt]; |
|||
inc(randcnt); |
|||
IF (randcnt > 255) THEN |
|||
BEGIN |
|||
Isaac(); |
|||
Isaac; |
|||
randcnt := 0; |
|||
randcnt := 0; |
|||
END; |
|||
END; |
END; |
||
END; // iRandom |
|||
// Get a random character in printable ASCII range |
|||
FUNCTION iRandA: Byte; |
|||
{ Get a random character in printable ASCII range } |
|||
FUNCTION iRandA: BYTE; |
|||
BEGIN |
BEGIN |
||
iRandA := iRandom MOD 95 + 32; |
|||
END; |
END; |
||
// Convert an ASCII string to a hexadecimal string |
|||
FUNCTION Ascii2Hex(s: String): String; |
|||
VAR |
|||
i: Cardinal; |
|||
BEGIN |
|||
Ascii2Hex := ''; |
|||
FOR i := 1 TO Length(s) DO |
|||
Ascii2Hex += Dec2Numb(Ord(s[i]), 2, 16); |
|||
END; // Ascii2Hex |
|||
// XOR encrypt on random stream. Output: ASCII string |
|||
FUNCTION |
FUNCTION Vernam(msg: String): String; |
||
VAR |
|||
VAR i: CARDINAL; |
|||
i: Cardinal; |
|||
BEGIN |
|||
BEGIN |
|||
ascii2hex := ''; |
|||
Vernam := ''; |
|||
FOR i := 1 TO Length(s) DO |
|||
FOR i := 1 to Length(msg) DO |
|||
ascii2hex += Dec2Numb(ord(s[i]),2,16); |
|||
Vernam += Chr(iRandA XOR Ord(msg[i])); |
|||
END; |
|||
END; // Vernam |
|||
// Get position of the letter in chosen alphabet |
|||
FUNCTION LetterNum(letter, start: Char): Byte; |
|||
BEGIN |
|||
LetterNum := (Ord(letter) - Ord(start)); |
|||
END; // LetterNum |
|||
// Caesar-shift a character <shift> places: Generalized Vigenere |
|||
{ XOR encrypt on random stream. Output: ASCII string } |
|||
FUNCTION Caesar(m: iMode; ch: Char; shift, modulo: Integer; start: Char): Char; |
|||
FUNCTION Vernam(msg: STRING): STRING; |
|||
VAR |
|||
VAR i: CARDINAL; |
|||
n: Integer; |
|||
BEGIN |
|||
BEGIN |
|||
Vernam := ''; |
|||
IF m = iDecrypt THEN |
|||
FOR i := 1 to length(msg) DO |
|||
shift := -shift; |
|||
Vernam += chr(iRandA xor ord(msg[i])); |
|||
n := LetterNum(ch, start) + shift; |
|||
END; |
|||
n := n MOD modulo; |
|||
IF n < 0 THEN |
|||
n += modulo; |
|||
{ Get position of the letter in chosen alphabet } |
|||
Caesar := Chr(Ord(start) + n); |
|||
FUNCTION letternum(letter, start: CHAR): byte; |
|||
END; // Caesar |
|||
BEGIN |
|||
letternum := (ord(letter)-ord(start)); |
|||
END; |
|||
{ Caesar-shift a character <shift> places: Generalized Vigenere } |
|||
FUNCTION Caesar(m: iMode; ch: CHAR; shift, modulo: INTEGER; start: CHAR): CHAR; |
|||
VAR n: INTEGER; |
|||
BEGIN |
|||
IF m = iDecrypt THEN shift := -shift; |
|||
n := letternum(ch,start) + shift; |
|||
n := n MOD modulo; |
|||
IF n<0 THEN n += modulo; |
|||
Caesar := chr(ord(start)+n); |
|||
END; |
|||
{ Vigenere mod 95 encryption & decryption. Output: ASCII string } |
|||
FUNCTION Vigenere(msg: STRING; m: iMode): STRING; |
|||
VAR i: CARDINAL; |
|||
BEGIN |
|||
Vigenere := ''; |
|||
FOR i := 1 to length(msg) DO |
|||
Vigenere += Caesar(m,msg[i],iRandA,95,' '); |
|||
END; |
|||
// Vigenere MOD 95 encryption & decryption. Output: ASCII string |
|||
FUNCTION Vigenere(msg: String; m: iMode): String; |
|||
VAR |
|||
i: Cardinal; |
|||
BEGIN |
|||
Vigenere := ''; |
|||
FOR i := 1 to Length(msg) DO |
|||
Vigenere += Caesar(m, msg[i], iRandA, 95, ' '); |
|||
END; // Vigenere |
|||
BEGIN |
BEGIN |
||
// 1) seed ISAAC with the key |
|||
iSeed(key, true); |
|||
// 2) Encryption |
|||
// a) XOR (Vernam) |
|||
xctx := Vernam(msg); |
|||
// b) MOD (Vigenere) |
|||
mctx := Vigenere(msg, iEncrypt); |
|||
// 3) Decryption |
|||
iSeed(key, true); |
|||
// a) XOR (Vernam) |
|||
xptx := Vernam(xctx); |
|||
// b) MOD (Vigenere) |
|||
mptx := Vigenere(mctx, iDecrypt); |
|||
// program output |
|||
Writeln('Message: ', msg); |
|||
Writeln('Key : ', key); |
|||
Writeln('XOR : ', Ascii2Hex(xctx)); |
|||
Writeln('MOD : ', Ascii2Hex(mctx)); |
|||
Writeln('XOR dcr: ', xptx); |
|||
Writeln('MOD dcr: ', mptx); |
|||
END. |
END. |
||
</lang> |
</lang> |