[2838] in cryptography@c2.net mail archive

home help back first fref pref prev next nref lref last post

SKIPJACK Implementation

daemon@ATHENA.MIT.EDU (Markus Kuhn)
Wed Jun 24 18:19:25 1998

To: cypherpunks@cyberpass.com, cryptography@c2.net
In-reply-to: Your message of "Wed, 24 Jun 1998 09:25:27 MST."
             <413AC08141DBD011A58000A0C924A6D52C357C@MVS2> 
Date: Wed, 24 Jun 1998 21:31:44 +0000
From: Markus Kuhn <Markus.Kuhn@cl.cam.ac.uk>

This is a multipart MIME message.

--==_Exmh_-15046075950
Content-Type: text/plain; charset=us-ascii

For anyone who wants to play around with NSA's recently declassified
SKIPJACK blockcipher, an example implementation follows below.

It is also downloadable from

  http://www.cl.cam.ac.uk/~mgk25/download/skipjack.tar.gz

Markus

-- 
Markus G. Kuhn, Security Group, Computer Lab, Cambridge University, UK
email: mkuhn at acm.org,  home page: <http://www.cl.cam.ac.uk/~mgk25/>


--==_Exmh_-15046075950
Content-Type: text/plain ; name="skipjack.ads"; charset=us-ascii
Content-Description: skipjack.ads
Content-Disposition: attachment; filename="skipjack.ads"

-------------------------------------------------------------------------------
--
-- SKIPJACK Blockcipher
--
-- Markus G. Kuhn <mkuhn@acm.org>
--
-- $Id: skipjack.ads,v 1.2 1998-06-24 20:43:30+00 mgk25 Rel $
--
-------------------------------------------------------------------------------
--
-- This is an Ada 95 implementation of the SKIPJACK blockcipher algorithm
-- as specified in version 2.0 of NSA's SKIPJACK specification dated
-- 1998-05-29 <http://csrc.nist.gov/encryption/skipjack-kea.htm>.
--
-------------------------------------------------------------------------------

with Interfaces; use Interfaces;

package Skipjack is

   pragma Pure(Skipjack);

   type    Bytes is array (Natural range <>) of Unsigned_8;
   subtype Block is Bytes (0 .. 7);

   -- To conform to the NSA specification, cryptovariable Key should be of
   -- type Bytes (0 .. 9), which is 80 bits long. Other key lengths work as
   -- well here, but if Key'Length /= 10 is used, be aware that this will
   -- not be a conforming SKIPJACK implementation.

   procedure Encrypt (Key : in Bytes; Plaintext  :  in Block;
				      Ciphertext : out Block);

   procedure Decrypt (Key : in Bytes; Ciphertext :  in Block;
				      Plaintext  : out Block);

   procedure Selftest;

   Implementation_Error : exception;  -- raised if Selftest failed

end Skipjack;

--==_Exmh_-15046075950
Content-Type: text/plain ; name="skipjack.adb"; charset=us-ascii
Content-Description: skipjack.adb
Content-Disposition: attachment; filename="skipjack.adb"

-------------------------------------------------------------------------------
--
-- SKIPJACK Blockcipher
--
-- Markus G. Kuhn <mkuhn@acm.org>
--
-- $Id: skipjack.adb,v 1.2 1998-06-24 20:43:30+00 mgk25 Rel $
--
-------------------------------------------------------------------------------

with Interfaces; use Interfaces;

package body Skipjack is

   pragma Optimize(Time);

   F : constant array (Unsigned_8) of Unsigned_8 :=
     (16#A3#, 16#D7#, 16#09#, 16#83#, 16#F8#, 16#48#, 16#F6#, 16#F4#,
      16#B3#, 16#21#, 16#15#, 16#78#, 16#99#, 16#B1#, 16#AF#, 16#F9#,
      16#E7#, 16#2D#, 16#4D#, 16#8A#, 16#CE#, 16#4C#, 16#CA#, 16#2E#,
      16#52#, 16#95#, 16#D9#, 16#1E#, 16#4E#, 16#38#, 16#44#, 16#28#,
      16#0A#, 16#DF#, 16#02#, 16#A0#, 16#17#, 16#F1#, 16#60#, 16#68#,
      16#12#, 16#B7#, 16#7A#, 16#C3#, 16#E9#, 16#FA#, 16#3D#, 16#53#,
      16#96#, 16#84#, 16#6B#, 16#BA#, 16#F2#, 16#63#, 16#9A#, 16#19#,
      16#7C#, 16#AE#, 16#E5#, 16#F5#, 16#F7#, 16#16#, 16#6A#, 16#A2#,
      16#39#, 16#B6#, 16#7B#, 16#0F#, 16#C1#, 16#93#, 16#81#, 16#1B#,
      16#EE#, 16#B4#, 16#1A#, 16#EA#, 16#D0#, 16#91#, 16#2F#, 16#B8#,
      16#55#, 16#B9#, 16#DA#, 16#85#, 16#3F#, 16#41#, 16#BF#, 16#E0#,
      16#5A#, 16#58#, 16#80#, 16#5F#, 16#66#, 16#0B#, 16#D8#, 16#90#,
      16#35#, 16#D5#, 16#C0#, 16#A7#, 16#33#, 16#06#, 16#65#, 16#69#,
      16#45#, 16#00#, 16#94#, 16#56#, 16#6D#, 16#98#, 16#9B#, 16#76#,
      16#97#, 16#FC#, 16#B2#, 16#C2#, 16#B0#, 16#FE#, 16#DB#, 16#20#,
      16#E1#, 16#EB#, 16#D6#, 16#E4#, 16#DD#, 16#47#, 16#4A#, 16#1D#,
      16#42#, 16#ED#, 16#9E#, 16#6E#, 16#49#, 16#3C#, 16#CD#, 16#43#,
      16#27#, 16#D2#, 16#07#, 16#D4#, 16#DE#, 16#C7#, 16#67#, 16#18#,
      16#89#, 16#CB#, 16#30#, 16#1F#, 16#8D#, 16#C6#, 16#8F#, 16#AA#,
      16#C8#, 16#74#, 16#DC#, 16#C9#, 16#5D#, 16#5C#, 16#31#, 16#A4#,
      16#70#, 16#88#, 16#61#, 16#2C#, 16#9F#, 16#0D#, 16#2B#, 16#87#,
      16#50#, 16#82#, 16#54#, 16#64#, 16#26#, 16#7D#, 16#03#, 16#40#,
      16#34#, 16#4B#, 16#1C#, 16#73#, 16#D1#, 16#C4#, 16#FD#, 16#3B#,
      16#CC#, 16#FB#, 16#7F#, 16#AB#, 16#E6#, 16#3E#, 16#5B#, 16#A5#,
      16#AD#, 16#04#, 16#23#, 16#9C#, 16#14#, 16#51#, 16#22#, 16#F0#,
      16#29#, 16#79#, 16#71#, 16#7E#, 16#FF#, 16#8C#, 16#0E#, 16#E2#,
      16#0C#, 16#EF#, 16#BC#, 16#72#, 16#75#, 16#6F#, 16#37#, 16#A1#,
      16#EC#, 16#D3#, 16#8E#, 16#62#, 16#8B#, 16#86#, 16#10#, 16#E8#,
      16#08#, 16#77#, 16#11#, 16#BE#, 16#92#, 16#4F#, 16#24#, 16#C5#,
      16#32#, 16#36#, 16#9D#, 16#CF#, 16#F3#, 16#A6#, 16#BB#, 16#AC#,
      16#5E#, 16#6C#, 16#A9#, 16#13#, 16#57#, 16#25#, 16#B5#, 16#E3#,
      16#BD#, 16#A8#, 16#3A#, 16#01#, 16#05#, 16#59#, 16#2A#, 16#46#);


   procedure G(Key       :        Bytes;
	       I         : in out Natural;
	       High, Low : in out Unsigned_8) is
   begin
      High := High xor F(Low  xor Key(I));
      if I < Key'Last then I := I + 1; else I := Key'First; end if;
      Low  := Low  xor F(High xor Key(I));
      if I < Key'Last then I := I + 1; else I := Key'First; end if;
      High := High xor F(Low  xor Key(I));
      if I < Key'Last then I := I + 1; else I := Key'First; end if;
      Low  := Low  xor F(High xor Key(I));
      if I < Key'Last then I := I + 1; else I := Key'First; end if;
   end G;


   procedure G_Inverse(Key       :        Bytes;
		       I         : in out Natural;
		       High, Low : in out Unsigned_8) is
   begin
      Low  := Low  xor F(High xor Key(I));
      if I > Key'First then I := I - 1; else I := Key'Last; end if;
      High := High xor F(Low  xor Key(I));
      if I > Key'First then I := I - 1; else I := Key'Last; end if;
      Low  := Low  xor F(High xor Key(I));
      if I > Key'First then I := I - 1; else I := Key'Last; end if;
      High := High xor F(Low  xor Key(I));
      if I > Key'First then I := I - 1; else I := Key'Last; end if;
   end G_Inverse;


   pragma Inline(G, G_Inverse);


   procedure Encrypt (Key : in Bytes; Plaintext  :  in Block;
				      Ciphertext : out Block) is
      I       : Natural    := Key'First;
      Counter : Unsigned_8 := 0;
      Temp    : Bytes(0 .. 1);
   begin
      Ciphertext := Plaintext;
      while Counter < 32 loop
	 while Counter mod 16 /= 8 loop
	    Counter := Counter + 1;
	    Temp := Ciphertext(6 .. 7);
	    Ciphertext(2 .. 7) := Ciphertext(0 .. 5);
	    G(Key, I, Ciphertext(2), Ciphertext(3));
	    Ciphertext(0) := Temp(0) xor Ciphertext(2);
	    Ciphertext(1) := Temp(1) xor Ciphertext(3) xor Counter;
	 end loop;
	 while Counter mod 16 /= 0 loop
	    Counter := Counter + 1;
	    Temp := Ciphertext(6 .. 7);
	    Ciphertext(2 .. 7) := Ciphertext(0 .. 5);
	    Ciphertext(4) := Ciphertext(4) xor Ciphertext(0);
	    Ciphertext(5) := Ciphertext(5) xor Ciphertext(1) xor Counter;
	    G(Key, I, Ciphertext(2), Ciphertext(3));
	    Ciphertext(0 .. 1) := Temp;
	 end loop;
      end loop;
   end Encrypt;
   

   procedure Decrypt (Key : in Bytes; Ciphertext :  in Block;
				      Plaintext  : out Block) is
      I       : Natural    := Key'First + (4 * 4 * 8 - 1) mod Key'Length;
      Counter : Unsigned_8 := 4 * 8;
      Temp    : Bytes(0 .. 1);
   begin
      Plaintext := Ciphertext;
      while Counter > 0 loop
	 while Counter mod 16 /= 8 loop
	    Temp := Plaintext(0 .. 1);
	    Plaintext(0 .. 5) := Plaintext(2 .. 7);
	    G_Inverse(Key, I, Plaintext(0), Plaintext(1));
	    Plaintext(2) := Plaintext(2) xor Plaintext(0);
	    Plaintext(3) := Plaintext(3) xor Plaintext(1) xor Counter;
	    Plaintext(6 .. 7) := Temp;
	    Counter := Counter - 1;
	 end loop;
	 while Counter mod 16 /= 0 loop
	    Temp(0) := Plaintext(0) xor Plaintext(2);
	    Temp(1) := Plaintext(1) xor Plaintext(3) xor Counter;
	    Plaintext(0 .. 5) := Plaintext(2 .. 7);
	    G_Inverse(Key, I, Plaintext(0), Plaintext(1));
	    Plaintext(6 .. 7) := Temp;
	    Counter := Counter - 1;
	 end loop;
      end loop;
   end Decrypt;
   
   
   procedure Selftest is
      K     : constant Bytes := (16#00#, 16#99#, 16#88#, 16#77#, 16#66#,
				 16#55#, 16#44#, 16#33#, 16#22#, 16#11#);
      P     : constant Block := (16#33#, 16#22#, 16#11#, 16#00#,
				 16#DD#, 16#CC#, 16#BB#, 16#AA#);
      C, P2 : Block;
   begin
      Encrypt(K, P, C);
      Decrypt(K, C, P2);
      if C /= (16#25#, 16#87#, 16#CA#, 16#E2#, 16#7A#, 16#12#, 16#D3#, 16#00#)
	or P2 /= P then
         raise Implementation_Error;
      end if;
   end Selftest;
   
end Skipjack;

--==_Exmh_-15046075950--


home help back first fref pref prev next nref lref last post