123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- MODULE CryptoTwofish; (** Twofish en/decryption *)
- (* Oberon port, based on twofish.c (vers. 1.0, Apr. 1998),
- 2002.07.22 g.f.
- *)
- IMPORT S := SYSTEM, Ciphers := CryptoCiphers, U := CryptoUtils;
- CONST
- N = 16;
- TYPE
- Block = ARRAY 4 OF SET32;
- SKey = ARRAY 4 OF SET32;
- VAR
- tab0: ARRAY 256 OF SET32;
- tab1: ARRAY 256 OF SET32;
- TYPE
- Cipher* = OBJECT (Ciphers.Cipher)
- VAR keybits: LONGINT;
- sbox: ARRAY 4 OF LONGINT;
- subkeys: ARRAY 8 + 2*N OF LONGINT;
- iv: Block;
- PROCEDURE InitKey*( CONST src: ARRAY OF CHAR; keybits: LONGINT );
- CONST step = 02020202H; bump = 01010101H;
- VAR
- i, A, B, m, nsub: LONGINT;
- k32e, k32o: ARRAY 4 OF LONGINT; (* even/odd key dwords *)
- BEGIN
- InitKey^( src, keybits ); SELF.keybits := keybits;
- FOR i := 0 TO keybits DIV 32 - 1 DO
- IF ODD( i ) THEN k32o[i DIV 2] := U.IntFromBufferLE( src, i*4 )
- ELSE k32e[i DIV 2] := U.IntFromBufferLE( src, i*4 )
- END
- END;
- m := keybits DIV 64 - 1;
- FOR i := 0 TO m DO
- (* compute S-box keys using (12,8) Reed-Solomon code over GF(256) *)
- sbox[m - i] := Encode( k32e[i], k32o[i] ); (* reverse order *)
- END;
- nsub := 8 + N*2;
- FOR i := 0 TO nsub DIV 2 - 1 DO
- (* compute round subkeys for PHT *)
- A := F32( S.VAL( SET32, i*step ), k32e, keybits ); (* A uses even key dwords *)
- B := ROT( F32( S.VAL( SET32, i*step + bump ), k32o, keybits ), 8 ); (* B uses odd key dwords *)
- subkeys[i*2] := A + B; (* combine with a PHT *)
- subkeys[i*2 + 1] := ROT( A + 2*B, 9 );
- END
- END InitKey;
- PROCEDURE SetIV*( CONST src: ARRAY OF CHAR; mode: SHORTINT );
- VAR i: INTEGER;
- BEGIN
- SetIV^( src, mode ); (* set mode *)
- FOR i := 0 TO 3 DO iv[i] := U.SetFromBufferLE( src, 4*i ) END;
- END SetIV;
- PROCEDURE Encrypt*( VAR buf: ARRAY OF CHAR; ofs, len: LONGINT );
- VAR i: LONGINT;
- BEGIN
- ASSERT( isKeyInitialized & (mode IN {Ciphers.ECB, Ciphers.CBC}) );
- ASSERT( len MOD blockSize = 0 ); (* padding must have been added *)
- i := 0;
- WHILE i < len DO EncryptBlock( buf, ofs + i ); INC( i, blockSize ); END
- END Encrypt;
- PROCEDURE Decrypt*( VAR buf: ARRAY OF CHAR; ofs, len: LONGINT );
- VAR i: LONGINT;
- BEGIN
- ASSERT( isKeyInitialized );
- ASSERT( len MOD blockSize = 0 ); (* padding must have been added *)
- i := 0;
- WHILE i < len DO DecryptBlock( buf, ofs + i ); INC( i, blockSize ); END
- END Decrypt;
- PROCEDURE EncryptBlock( VAR buf: ARRAY OF CHAR; pos: LONGINT );
- VAR x: Block; t0, t1, i, r: LONGINT; s0, s1: SET32;
- BEGIN
- (* copy in the block, add whitening *)
- FOR i := 0 TO 3 DO
- x[i] := U.SetFromBufferLE( buf, pos + i*4 ) / S.VAL( SET32, subkeys[i] );
- IF mode = Ciphers.CBC THEN x[i] := x[i] / iv[i] END
- END;
- (* main Twofish encryption loop *)
- FOR r := 0 TO N - 1 DO
- t0 := F32( x[0], sbox, keybits );
- t1 := F32( ROT( x[1], 8 ), sbox, keybits );
- x[2] := ROT( x[2] / S.VAL( SET32, t0 + t1 + subkeys[8 + 2*r] ), -1 );
- x[3] := ROT( x[3], 1 ) / S.VAL( SET32, t0 + t1*2 + subkeys[8 + 2*r + 1] );
- IF r < N - 1 THEN (* unswap, except for last round *)
- s0 := x[0]; x[0] := x[2]; x[2] := s0; s1 := x[1]; x[1] := x[3]; x[3] := s1;
- END
- END;
- (* copy out, with whitening *)
- FOR i := 0 TO 3 DO
- x[i] := x[i] / S.VAL( SET32, subkeys[4 + i] ); U.SetToBufferLE( x[i], buf, pos + i*4 );
- IF mode = Ciphers.CBC THEN iv[i] := x[i] END
- END;
- END EncryptBlock;
- PROCEDURE DecryptBlock( VAR buf: ARRAY OF CHAR; pos: LONGINT );
- VAR x0, x: Block; t0, t1, i, r: LONGINT; s0, s1: SET32;
- BEGIN
- (* copy in the block, add whitening *)
- FOR i := 0 TO 3 DO
- x0[i] := U.SetFromBufferLE( buf, pos + i*4 );
- x[i] := x0[i] / S.VAL( SET32, subkeys[4 + i] );
- END;
- (* main Twofish decryption loop *)
- FOR r := N - 1 TO 0 BY -1 DO
- t0 := F32( x[0], sbox, keybits );
- t1 := F32( ROT( x[1], 8 ), sbox, keybits );
- x[2] := ROT( x[2], 1 ); x[2] := x[2] / S.VAL( SET32, t0 + t1 + subkeys[8 + 2*r] );
- x[3] := ROT( x[3] / S.VAL( SET32, t0 + t1*2 + subkeys[8 + 2*r + 1] ), -1 );
- IF r > 0 THEN (* unswap, except for last round *)
- s0 := x[0]; x[0] := x[2]; x[2] := s0;
- s1 := x[1]; x[1] := x[3]; x[3] := s1;
- END
- END;
- (* copy out, with whitening *)
- FOR i := 0 TO 3 DO
- x[i] := x[i] / S.VAL( SET32, subkeys[i] );
- IF mode = Ciphers.CBC THEN x[i] := x[i] / iv[i]; iv[i] := x0[i] END;
- U.SetToBufferLE( x[i], buf, pos + i*4 );
- END;
- END DecryptBlock;
- PROCEDURE & Init*;
- BEGIN
- SetNameAndBlocksize( "twofish", 16 )
- END Init;
- END Cipher;
- PROCEDURE NewCipher*(): Ciphers.Cipher;
- VAR cipher: Cipher;
- BEGIN
- NEW( cipher ); RETURN cipher
- END NewCipher;
- (*-------------------------------------------------------------------------------*)
- CONST
- FDBK = 169H;
- Fdbk2 = S.VAL( SET32, FDBK DIV 2 );
- Fdbk4 = S.VAL( SET32, FDBK DIV 4 );
- Byte0 = S.VAL( SET32, 0FFH );
- S14d = S.VAL( SET32, 14DH );
- S0a6 = S.VAL( SET32, 0A6H );
- PROCEDURE m1( x: LONGINT ): SET32;
- BEGIN
- RETURN S.VAL( SET32, x )
- END m1;
- PROCEDURE mx( x: LONGINT ): SET32;
- VAR t: SET32;
- BEGIN
- t := S.VAL( SET32, x DIV 4 );
- IF ODD( x DIV 2 ) THEN t := t / Fdbk2 END;
- IF ODD( x ) THEN t := t / Fdbk4 END;
- RETURN S.VAL( SET32, x ) / t
- END mx;
- PROCEDURE my( x: LONGINT ): SET32;
- VAR t1, t2: SET32;
- BEGIN
- t1 := S.VAL( SET32, x DIV 2 ); t2 := S.VAL( SET32, x DIV 4 );
- IF ODD( x DIV 2 ) THEN t2 := t2 / Fdbk2 END;
- IF ODD( x ) THEN t1 := t1 / Fdbk2; t2 := t2 / Fdbk4 END;
- RETURN S.VAL( SET32, x ) / t1 / t2
- END my;
- PROCEDURE split( x: LONGINT; VAR v: SKey );
- BEGIN
- v[3] := S.VAL( SET32, x DIV 1000000H MOD 100H );
- v[2] := S.VAL( SET32, x DIV 10000H MOD 100H );
- v[1] := S.VAL( SET32, x DIV 100H MOD 100H );
- v[0] := S.VAL( SET32, x MOD 100H );
- END split;
- PROCEDURE -Int( x: SET32 ): LONGINT;
- BEGIN
- RETURN S.VAL( LONGINT, x )
- END Int;
- PROCEDURE F32( x: SET32; CONST k32: ARRAY OF LONGINT; keybits: LONGINT ): LONGINT;
- VAR a, b, c, d, l: LONGINT; k, k1: SKey;
- BEGIN
- (* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. *)
- (* Note that each byte goes through a different combination of S-boxes.*)
- d := Int( x ) DIV 1000000H MOD 100H;
- c := Int( x ) DIV 10000H MOD 100H;
- b := Int( x ) DIV 100H MOD 100H;
- a := Int( x ) MOD 100H;
- l := ((keybits + 63) DIV 64) MOD 4;
- IF l = 0 THEN (* 256 bits of key *)
- split( k32[3], k );
- a := Int( tab1[a] / k[0] );
- b := Int( tab0[b] / k[1] );
- c := Int( tab0[c] / k[2] );
- d := Int( tab1[d] / k[3] );
- END;
- IF l IN {0, 3} THEN (* 192 <= bits of key *)
- split( k32[2], k );
- a := Int( tab1[a] / k[0] );
- b := Int( tab1[b] / k[1] );
- c := Int( tab0[c] / k[2] );
- d := Int( tab0[d] / k[3] )
- END;
- (* 128 <= bits of key *)
- split( k32[1], k1 ); split( k32[0], k );
- a := Int( tab1[Int( tab0[Int( tab0[a] / k1[0] )] / k[0] )] );
- b := Int( tab0[Int( tab0[Int( tab1[b] / k1[1] )] / k[1] )] );
- c := Int( tab1[Int( tab1[Int( tab0[c] / k1[2] )] / k[2] )] );
- d := Int( tab0[Int( tab1[Int( tab1[d] / k1[3] )] / k[3] )] );
- (* Now perform the MDS matrix multiply *)
- RETURN Int( m1( a ) / my( b ) / mx( c ) / mx( d ) ) +
- ASH( Int( mx( a ) / my( b ) / my( c ) / m1( d ) ), 8 ) +
- ASH( Int( my( a ) / mx( b ) / m1( c ) / my( d ) ), 16 ) +
- ASH( Int( my( a ) / m1( b ) / my( c ) / mx( d ) ), 24 )
- END F32;
- (* RS_MDS_Encode *)
- PROCEDURE Encode( k0, k1: LONGINT ): LONGINT;
- VAR i, j, b: LONGINT; r, g2, g2s16, g3, g3s8, g3s24: SET32;
- BEGIN
- r := S.VAL( SET32, k1 );
- FOR i := 0 TO 1 DO
- IF i # 0 THEN r := r / S.VAL( SET32, k0 ) END;
- FOR j := 0 TO 3 DO
- b := S.VAL( LONGINT, LSH( r, -24 ) );
- g2 := S.VAL( SET32, b*2 );
- IF b > 7FH THEN g2 := (g2 / S14d) * Byte0 END;
- g2s16 := LSH( g2, 16 );
- g3 := S.VAL( SET32, b DIV 2 ) / g2;
- IF ODD( b ) THEN g3 := g3 / S0a6 END;
- g3s8 := LSH( g3, 8 );
- g3s24 := LSH( g3s8, 16 );
- r := LSH( r, 8 ) / g3s24 / g2s16 / g3s8 / S.VAL( SET32, b )
- END
- END;
- RETURN S.VAL( LONGINT, r )
- END Encode;
- PROCEDURE Init0;
- VAR
- buf: U.InitBuffer; i: LONGINT;
- BEGIN
- NEW( buf, 2048 );
- buf.Add( "0A9 067 0B3 0E8 004 0FD 0A3 076 09A 092 080 078 0E4 0DD 0D1 038 " );
- buf.Add( "00D 0C6 035 098 018 0F7 0EC 06C 043 075 037 026 0FA 013 094 048 " );
- buf.Add( "0F2 0D0 08B 030 084 054 0DF 023 019 05B 03D 059 0F3 0AE 0A2 082 " );
- buf.Add( "063 001 083 02E 0D9 051 09B 07C 0A6 0EB 0A5 0BE 016 00C 0E3 061 " );
- buf.Add( "0C0 08C 03A 0F5 073 02C 025 00B 0BB 04E 089 06B 053 06A 0B4 0F1 " );
- buf.Add( "0E1 0E6 0BD 045 0E2 0F4 0B6 066 0CC 095 003 056 0D4 01C 01E 0D7 " );
- buf.Add( "0FB 0C3 08E 0B5 0E9 0CF 0BF 0BA 0EA 077 039 0AF 033 0C9 062 071 " );
- buf.Add( "081 079 009 0AD 024 0CD 0F9 0D8 0E5 0C5 0B9 04D 044 008 086 0E7 " );
- buf.Add( "0A1 01D 0AA 0ED 006 070 0B2 0D2 041 07B 0A0 011 031 0C2 027 090 " );
- buf.Add( "020 0F6 060 0FF 096 05C 0B1 0AB 09E 09C 052 01B 05F 093 00A 0EF " );
- buf.Add( "091 085 049 0EE 02D 04F 08F 03B 047 087 06D 046 0D6 03E 069 064 " );
- buf.Add( "02A 0CE 0CB 02F 0FC 097 005 07A 0AC 07F 0D5 01A 04B 00E 0A7 05A " );
- buf.Add( "028 014 03F 029 088 03C 04C 002 0B8 0DA 0B0 017 055 01F 08A 07D " );
- buf.Add( "057 0C7 08D 074 0B7 0C4 09F 072 07E 015 022 012 058 007 099 034 " );
- buf.Add( "06E 050 0DE 068 065 0BC 0DB 0F8 0C8 0A8 02B 040 0DC 0FE 032 0A4 " );
- buf.Add( "0CA 010 021 0F0 0D3 05D 00F 000 06F 09D 036 042 04A 05E 0C1 0E0 " );
- FOR i := 0 TO 255 DO tab0[i] := buf.GetSet() END;
- buf.Init( 2048 );
- buf.Add( "075 0F3 0C6 0F4 0DB 07B 0FB 0C8 04A 0D3 0E6 06B 045 07D 0E8 04B " );
- buf.Add( "0D6 032 0D8 0FD 037 071 0F1 0E1 030 00F 0F8 01B 087 0FA 006 03F " );
- buf.Add( "05E 0BA 0AE 05B 08A 000 0BC 09D 06D 0C1 0B1 00E 080 05D 0D2 0D5 " );
- buf.Add( "0A0 084 007 014 0B5 090 02C 0A3 0B2 073 04C 054 092 074 036 051 " );
- buf.Add( "038 0B0 0BD 05A 0FC 060 062 096 06C 042 0F7 010 07C 028 027 08C " );
- buf.Add( "013 095 09C 0C7 024 046 03B 070 0CA 0E3 085 0CB 011 0D0 093 0B8 " );
- buf.Add( "0A6 083 020 0FF 09F 077 0C3 0CC 003 06F 008 0BF 040 0E7 02B 0E2 " );
- buf.Add( "079 00C 0AA 082 041 03A 0EA 0B9 0E4 09A 0A4 097 07E 0DA 07A 017 " );
- buf.Add( "066 094 0A1 01D 03D 0F0 0DE 0B3 00B 072 0A7 01C 0EF 0D1 053 03E " );
- buf.Add( "08F 033 026 05F 0EC 076 02A 049 081 088 0EE 021 0C4 01A 0EB 0D9 " );
- buf.Add( "0C5 039 099 0CD 0AD 031 08B 001 018 023 0DD 01F 04E 02D 0F9 048 " );
- buf.Add( "04F 0F2 065 08E 078 05C 058 019 08D 0E5 098 057 067 07F 005 064 " );
- buf.Add( "0AF 063 0B6 0FE 0F5 0B7 03C 0A5 0CE 0E9 068 044 0E0 04D 043 069 " );
- buf.Add( "029 02E 0AC 015 059 0A8 00A 09E 06E 047 0DF 034 035 06A 0CF 0DC " );
- buf.Add( "022 0C9 0C0 09B 089 0D4 0ED 0AB 012 0A2 00D 052 0BB 002 02F 0A9 " );
- buf.Add( "0D7 061 01E 0B4 050 004 0F6 0C2 016 025 086 056 055 009 0BE 091 " );
- FOR i := 0 TO 255 DO tab1[i] := buf.GetSet() END;
- END Init0;
- BEGIN
- Init0
- END CryptoTwofish.
|