[2838] in cryptography@c2.net mail archive
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--