diff -uNr a/smg_comms/manifest b/smg_comms/manifest --- a/smg_comms/manifest 7d5acfd1981b93ad649daab47b2ec552e09ac46ad0329914b6c5503c092c899a9804c9a506b4c22fb8c930e2a3acedcd55470f9f4cba5c4c7993c7903f5722f4 +++ b/smg_comms/manifest 84f1562e913676358d1bf1a9e6013f92bd61c79e2215eba0b19959f7166cfdc8a0a73e1e6139b9a467ad060a0f2d243b788986aff361167ffc7db5cdeb1fb15e @@ -1,2 +1,3 @@ 532398 smg_comms_genesis diana_coman The first seed of an implementation of S.MG's communication protocol for Eulora: definitions for basic types, methods to/from network format, basic client/server test running locally on the same machine. 546000 smg_comms_raw_types diana_coman Part of layer 0 - raw types for the updated version of the protocol containing only two types of packets: 1470 octets RSA packet and 1472 octets Serpent packet. +546152 smg_comms_packing_serpent diana_coman Packing/Unpacking Serpent messages <-> Serpent packets. Includes Serpent implementation. diff -uNr a/smg_comms/src/packing.adb b/smg_comms/src/packing.adb --- a/smg_comms/src/packing.adb false +++ b/smg_comms/src/packing.adb 9650f68c8bfba99299b059e943008ce5c682b3991e60ea7ee51c22f23373b56a9c1bd1c6459f5d7f8a5553244a4656c357035cf54caecac4cbcab25041b2c011 @@ -0,0 +1,77 @@ + -- Packing/unpacking for Eulora's communication protocol: + -- Serpent Message to/from Serpent Packet + -- RSA Message to/from RSA Packet + -- S.MG, 2018 + +package body Packing is + + -- Packing a Serpent message into Serpent package, using the given key + function Pack( Msg : in Raw_Types.Serpent_Msg; + K : in Serpent.Key ) + return Raw_Types.Serpent_Pkt is + + -- single Serpent blocks containing plain / encrypted data + Plain : Serpent.Block; + Encr : Serpent.Block; + + -- Serpent Key Schedule - needed for direct encr/decr calls + KS : Serpent.Key_Schedule; + + -- final resulting Serpent package + Pkt : Raw_Types.Serpent_Pkt := (others => 0); + begin + -- prepare the Serpent key schedule based on given key + Serpent.Prepare_Key( K, KS ); + + -- encrypt message block by block and copy result in packet + for I in 1 .. S_Blocks loop + -- get current block to encrypt + Plain := Msg( Msg'First + (I-1) * Block_Len .. + Msg'First + I * Block_Len - 1 ); + -- encrypt with Serpent + Serpent.Encrypt( KS, Plain, Encr ); + -- copy result to output packet + Pkt( Pkt'First + (I-1) * Block_Len .. + Pkt'First + I * Block_Len - 1 ) + := Encr; + end loop; + + -- return result + return Pkt; + end Pack; + + -- Unpacking a Serpent packet into contained message, using the given key + function Unpack( Pkt : in Raw_Types.Serpent_Pkt; + K : in Serpent.Key) + return Raw_Types.Serpent_Msg is + -- single Serpent blocks containing plain / encrypted data + Plain : Serpent.Block; + Encr : Serpent.Block; + + -- Serpent Key Schedule - needed for direct encr/decr calls + KS : Serpent.Key_Schedule; + + -- the message extracted from the given packet + Msg : Raw_Types.Serpent_Msg := (others => 0); + begin + -- prepare the Serpent key for use + Serpent.Prepare_Key( K, KS ); + + -- decrypt the Serpent packet block by block + for I in 1 .. S_Blocks loop + -- get current block from input and decrypt + Encr := Pkt( Pkt'First + (I-1) * Block_Len .. + Pkt'First + I * Block_Len - 1 ); + Serpent.Decrypt( KS, Encr, Plain ); + + -- copy result to its correct position in final output + Msg( Msg'First + (I-1) * Block_Len .. + Msg'First + I * Block_Len - 1 ) + := Plain; + end loop; + + -- return the result - the message content of given package + return Msg; + end Unpack; + +end Packing; diff -uNr a/smg_comms/src/packing.ads b/smg_comms/src/packing.ads --- a/smg_comms/src/packing.ads false +++ b/smg_comms/src/packing.ads ad406f2a69515e600b7b4986232eb5ad88c0a058f3cdb24981044389a88a5a30c92f198b5431f59d38149ab99e8c893fe6657a7d940f51ea4b28ed0d113c46d0 @@ -0,0 +1,31 @@ + -- Packing/unpacking for Eulora's communication protocol: + -- Serpent Message to/from Serpent Packet + -- RSA Message to/from RSA Packet + -- S.MG, 2018 + +with Raw_Types; +with Serpent; + +package Packing is + -- no side effects or internal state + Pragma Pure(Packing); + + -- Packing a Serpent message into Serpent package, using the given key + function Pack( Msg : in Raw_Types.Serpent_Msg; + K : in Serpent.Key ) + return Raw_Types.Serpent_Pkt; + + -- Unpacking a Serpent packet into contained message, using the given key + function Unpack( Pkt : in Raw_Types.Serpent_Pkt; + K : in Serpent.Key) + return Raw_Types.Serpent_Msg; + + -- internals of this package, NOT for outside use +private + -- length of 1 Serpent block + Block_Len: constant Natural := Serpent.Block'Length; + + -- number of Serpent blocks in one single Serpent message/packet + S_Blocks : constant Natural := Raw_Types.SERPENT_OCTETS / Block_Len; + +end Packing; diff -uNr a/smg_comms/src/raw_types.ads b/smg_comms/src/raw_types.ads --- a/smg_comms/src/raw_types.ads be61934d440dad950d4f63ea9a1bb941a7994c832adb4748a1e24083887853fdd52fdf024d940740a9d3b65759aad66a05f42b0365624b0affa0e12418e2fe8d +++ b/smg_comms/src/raw_types.ads 8b32dfa8a36c4cb27171b299d329919b9cd3677de408d9474768641cf8fc1a4f60c236e6aa3005aa50b9379bbb78a06b214b38345e2d6255452e46f529afdb71 @@ -9,13 +9,14 @@ with Ada.Unchecked_Conversion; package Raw_Types is + -- no side effects or internal state + Pragma Pure(Raw_Types); -- constants from SMG.COMMS standard specification -- size of a serpent-encrypted packet and message, in octets -- note that this corresponds to 1472/16 = 92 Serpent blocks - -- NB: lengths are the same but the distinction makes the code clearer - SERPENT_PKT_OCTETS : constant Positive := 1472; - SERPENT_MSG_OCTETS : constant Positive := SERPENT_PKT_OCTETS; + -- NB: lengths are the same! + SERPENT_OCTETS : constant Positive := 1472; -- size of a RSA-encrypted packet and message in octets and bits RSA_PKT_OCTETS : constant Positive := 1470; @@ -38,8 +39,8 @@ -- Serpent packets and contained raw messages -- NB: length is the same but the distinction makes the code clearer - subtype Serpent_Pkt is Octets( 1 .. SERPENT_PKT_OCTETS ); - subtype Serpent_Msg is Octets( 1 .. SERPENT_MSG_OCTETS ); + subtype Serpent_Pkt is Octets( 1 .. SERPENT_OCTETS ); + subtype Serpent_Msg is Octets( 1 .. SERPENT_OCTETS ); -- blind, unchecked casts ( memcpy style ) function Cast is new Ada.Unchecked_Conversion( Integer_8 , Octets_1 ); diff -uNr a/smg_comms/src/serpent.adb b/smg_comms/src/serpent.adb --- a/smg_comms/src/serpent.adb false +++ b/smg_comms/src/serpent.adb 41093717fe246dac63fa4cb79464f1ff6ccca51c885a40405c1eed02dc7a6b2c23d368b1d971c13028c12c80e9d237cd74b0d7f60969a6fe803ced628034d0ab @@ -0,0 +1,624 @@ + ------------------------------------------------------------------------------ + -- + -- Serpent Blockcipher + -- + -- Copyright (c) 1998 Markus G. Kuhn . All rights reserved. + -- + -- Modified by S.MG, 2018 + -- + ------------------------------------------------------------------------------ + -- + -- This implementation is optimized for best execution time by use of + -- function inlining and loop unrolling. It is not intended to be used in + -- applications (such as smartcards) where machine code size matters. Best + -- compiled with highest optimization level activated and all run-time + -- checks supressed. + -- + ------------------------------------------------------------------------------ + +with System, Ada.Unchecked_Conversion; +use System; + +package body Serpent is + + pragma Optimize( Time ); + + -- Auxiliary functions for byte array to word array conversion with + -- Bigendian/Littleendian handling. + -- + -- The convention followed here is that the input byte array + -- + -- 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + -- + -- is converted into the register values + -- + -- X0 = 03020100, X1 = 07060504, X2 = 0b0a0908, X3 = 0f0e0d0c + + subtype Bytes_4 is Bytes (0 .. 3); + function Cast is new Ada.Unchecked_Conversion (Bytes_4, Unsigned_32); + function Cast is new Ada.Unchecked_Conversion (Unsigned_32, Bytes_4); + + function Bytes_To_Word (X : Bytes_4) return Unsigned_32 is + begin + if Default_Bit_Order = Low_Order_First then + -- we have a Littleendian processor + return Cast(X); + else + -- word sex change + return Cast((X(3), X(2), X(1), X(0))); + end if; + end Bytes_To_Word; + + function Word_To_Bytes (X : Unsigned_32) return Bytes_4 is + begin + if Default_Bit_Order = Low_Order_First then + -- we have a Littleendian processor + return Cast(X); + else + -- word sex change + return (Cast(X)(3), Cast(X)(2), Cast(X)(1), Cast(X)(0)); + end if; + end Word_To_Bytes; + + pragma Inline(Bytes_To_Word, Word_To_Bytes); + -- inline functions for the Encryption and Decryption procedures + + -- Sbox function + procedure S (R : Integer; X0, X1, X2, X3 : in out Unsigned_32) is + T01, T02, T03, T04, T05, T06, T07, T08, T09, + T10, T11, T12, T13, T14, T15, T16, T17, T18 : Unsigned_32; + W, X, Y, Z : Unsigned_32; + begin + if R = 0 then + -- S0: 3 8 15 1 10 6 5 11 14 13 4 2 7 0 9 12 + -- depth = 5,7,4,2, Total gates=18 + T01 := X1 xor X2; + T02 := X0 or X3; + T03 := X0 xor X1; + Z := T02 xor T01; + T05 := X2 or z; + T06 := X0 xor X3; + T07 := X1 or X2; + T08 := X3 and T05; + T09 := T03 and T07; + Y := T09 xor T08; + T11 := T09 and y; + T12 := X2 xor X3; + T13 := T07 xor T11; + T14 := X1 and T06; + T15 := T06 xor T13; + W := not T15; + T17 := W xor T14; + X := T12 xor T17; + elsif R = 1 then + -- S1: 15 12 2 7 9 0 5 10 1 11 14 8 6 13 3 4 + -- depth = 10,7,3,5, Total gates=18 + T01 := X0 or X3; + T02 := X2 xor X3; + T03 := not X1; + T04 := X0 xor X2; + T05 := X0 or T03; + T06 := X3 and T04; + T07 := T01 and T02; + T08 := X1 or T06; + Y := T02 xor T05; + T10 := T07 xor T08; + T11 := T01 xor T10; + T12 := Y xor T11; + T13 := X1 and X3; + Z := not T10; + X := T13 xor T12; + T16 := T10 or x; + T17 := T05 and T16; + W := X2 xor T17; + elsif R = 2 then + -- S2: 8 6 7 9 3 12 10 15 13 1 14 4 0 11 5 2 + -- depth = 3,8,11,7, Total gates=16 + T01 := X0 or X2; + T02 := X0 xor X1; + T03 := X3 xor T01; + W := T02 xor T03; + T05 := X2 xor w; + T06 := X1 xor T05; + T07 := X1 or T05; + T08 := T01 and T06; + T09 := T03 xor T07; + T10 := T02 or T09; + X := T10 xor T08; + T12 := X0 or X3; + T13 := T09 xor x; + T14 := X1 xor T13; + Z := not T09; + Y := T12 xor T14; + elsif R = 3 then + -- S3: 0 15 11 8 12 9 6 3 13 1 2 4 10 7 5 14 + -- depth = 8,3,5,5, Total gates=18 + T01 := X0 xor X2; + T02 := X0 or X3; + T03 := X0 and X3; + T04 := T01 and T02; + T05 := X1 or T03; + T06 := X0 and X1; + T07 := X3 xor T04; + T08 := X2 or T06; + T09 := X1 xor T07; + T10 := X3 and T05; + T11 := T02 xor T10; + Z := T08 xor T09; + T13 := X3 or z; + T14 := X0 or T07; + T15 := X1 and T13; + Y := T08 xor T11; + W := T14 xor T15; + X := T05 xor T04; + elsif R = 4 then + -- S4: 1 15 8 3 12 0 11 6 2 5 4 10 9 14 7 13 + -- depth = 6,7,5,3, Total gates=19 + T01 := X0 or X1; + T02 := X1 or X2; + T03 := X0 xor T02; + T04 := X1 xor X3; + T05 := X3 or T03; + T06 := X3 and T01; + Z := T03 xor T06; + T08 := Z and T04; + T09 := T04 and T05; + T10 := X2 xor T06; + T11 := X1 and X2; + T12 := T04 xor T08; + T13 := T11 or T03; + T14 := T10 xor T09; + T15 := X0 and T05; + T16 := T11 or T12; + Y := T13 xor T08; + X := T15 xor T16; + W := not T14; + elsif R = 5 then + -- S5: 15 5 2 11 4 10 9 12 0 3 14 8 13 6 7 1 + -- depth = 4,6,8,6, Total gates=17 + T01 := X1 xor X3; + T02 := X1 or X3; + T03 := X0 and T01; + T04 := X2 xor T02; + T05 := T03 xor T04; + W := not T05; + T07 := X0 xor T01; + T08 := X3 or w; + T09 := X1 or T05; + T10 := X3 xor T08; + T11 := X1 or T07; + T12 := T03 or w; + T13 := T07 or T10; + T14 := T01 xor T11; + Y := T09 xor T13; + X := T07 xor T08; + Z := T12 xor T14; + elsif R = 6 then + -- S6: 7 2 12 5 8 4 6 11 14 9 1 15 13 3 10 0 + -- depth = 8,3,6,3, Total gates=19 + T01 := X0 and X3; + T02 := X1 xor X2; + T03 := X0 xor X3; + T04 := T01 xor T02; + T05 := X1 or X2; + X := not T04; + T07 := T03 and T05; + T08 := X1 and x; + T09 := X0 or X2; + T10 := T07 xor T08; + T11 := X1 or X3; + T12 := X2 xor T11; + T13 := T09 xor T10; + Y := not T13; + T15 := X and T03; + Z := T12 xor T07; + T17 := X0 xor X1; + T18 := Y xor T15; + W := T17 xor T18; + elsif R = 7 then + -- S7: 1 13 15 0 14 8 2 11 7 4 12 10 9 3 5 6 + -- depth = 10,7,10,4, Total gates=19 + T01 := X0 and X2; + T02 := not X3; + T03 := X0 and T02; + T04 := X1 or T01; + T05 := X0 and X1; + T06 := X2 xor T04; + Z := T03 xor T06; + T08 := X2 or z; + T09 := X3 or T05; + T10 := X0 xor T08; + T11 := T04 and z; + X := T09 xor T10; + T13 := X1 xor x; + T14 := T01 xor x; + T15 := X2 xor T05; + T16 := T11 or T13; + T17 := T02 or T14; + W := T15 xor T17; + Y := X0 xor T16; + end if; + X0 := W; + X1 := X; + X2 := Y; + X3 := Z; + end S; + + + -- Inverse Sbox function + + procedure SI (R : Integer; X0, X1, X2, X3 : in out Unsigned_32) is + T01, T02, T03, T04, T05, T06, T07, T08, T09, + T10, T11, T12, T13, T14, T15, T16, T17, T18 : Unsigned_32; + W, X, Y, Z : Unsigned_32; + begin + if R = 0 then + -- InvS0: 13 3 11 0 10 6 5 12 1 14 4 7 15 9 8 2 + -- depth = 8,4,3,6, Total gates=19 + T01 := X2 xor X3; + T02 := X0 or X1; + T03 := X1 or X2; + T04 := X2 and T01; + T05 := T02 xor T01; + T06 := X0 or T04; + Y := not T05; + T08 := X1 xor X3; + T09 := T03 and T08; + T10 := X3 or y; + X := T09 xor T06; + T12 := X0 or T05; + T13 := X xor T12; + T14 := T03 xor T10; + T15 := X0 xor X2; + Z := T14 xor T13; + T17 := T05 and T13; + T18 := T14 or T17; + W := T15 xor T18; + elsif R = 1 then + -- InvS1: 5 8 2 14 15 6 12 3 11 4 7 9 1 13 10 0 + -- depth = 7,4,5,3, Total gates=18 + T01 := X0 xor X1; + T02 := X1 or X3; + T03 := X0 and X2; + T04 := X2 xor T02; + T05 := X0 or T04; + T06 := T01 and T05; + T07 := X3 or T03; + T08 := X1 xor T06; + T09 := T07 xor T06; + T10 := T04 or T03; + T11 := X3 and T08; + Y := not T09; + X := T10 xor T11; + T14 := X0 or y; + T15 := T06 xor x; + Z := T01 xor T04; + T17 := X2 xor T15; + W := T14 xor T17; + elsif R = 2 then + -- InvS2: 12 9 15 4 11 14 1 2 0 3 6 13 5 8 10 7 + -- depth = 3,6,8,3, Total gates=18 + T01 := X0 xor X3; + T02 := X2 xor X3; + T03 := X0 and X2; + T04 := X1 or T02; + W := T01 xor T04; + T06 := X0 or X2; + T07 := X3 or w; + T08 := not X3; + T09 := X1 and T06; + T10 := T08 or T03; + T11 := X1 and T07; + T12 := T06 and T02; + Z := T09 xor T10; + X := T12 xor T11; + T15 := X2 and z; + T16 := W xor x; + T17 := T10 xor T15; + Y := T16 xor T17; + elsif R = 3 then + -- InvS3: 0 9 10 7 11 14 6 13 3 5 12 2 4 8 15 1 + -- depth = 3,6,4,4, Total gates=17 + T01 := X2 or X3; + T02 := X0 or X3; + T03 := X2 xor T02; + T04 := X1 xor T02; + T05 := X0 xor X3; + T06 := T04 and T03; + T07 := X1 and T01; + Y := T05 xor T06; + T09 := X0 xor T03; + W := T07 xor T03; + T11 := W or T05; + T12 := T09 and T11; + T13 := X0 and y; + T14 := T01 xor T05; + X := X1 xor T12; + T16 := X1 or T13; + Z := T14 xor T16; + elsif R = 4 then + -- InvS4: 5 0 8 3 10 9 7 14 2 12 11 6 4 15 13 1 + -- depth = 6,4,7,3, Total gates=17 + T01 := X1 or X3; + T02 := X2 or X3; + T03 := X0 and T01; + T04 := X1 xor T02; + T05 := X2 xor X3; + T06 := not T03; + T07 := X0 and T04; + X := T05 xor T07; + T09 := X or T06; + T10 := X0 xor T07; + T11 := T01 xor T09; + T12 := X3 xor T04; + T13 := X2 or T10; + Z := T03 xor T12; + T15 := X0 xor T04; + Y := T11 xor T13; + W := T15 xor T09; + elsif R = 5 then + -- InvS5: 8 15 2 9 4 1 13 14 11 6 5 3 7 12 10 0 + -- depth = 4,6,9,7, Total gates=17 + T01 := X0 and X3; + T02 := X2 xor T01; + T03 := X0 xor X3; + T04 := X1 and T02; + T05 := X0 and X2; + W := T03 xor T04; + T07 := X0 and w; + T08 := T01 xor w; + T09 := X1 or T05; + T10 := not X1; + X := T08 xor T09; + T12 := T10 or T07; + T13 := W or x; + Z := T02 xor T12; + T15 := T02 xor T13; + T16 := X1 xor X3; + Y := T16 xor T15; + elsif R = 6 then + -- InvS6: 15 10 1 13 5 3 6 0 4 9 14 7 2 12 8 11 + -- depth = 5,3,8,6, Total gates=19 + T01 := X0 xor X2; + T02 := not X2; + T03 := X1 and T01; + T04 := X1 or T02; + T05 := X3 or T03; + T06 := X1 xor X3; + T07 := X0 and T04; + T08 := X0 or T02; + T09 := T07 xor T05; + X := T06 xor T08; + W := not T09; + T12 := X1 and w; + T13 := T01 and T05; + T14 := T01 xor T12; + T15 := T07 xor T13; + T16 := X3 or T02; + T17 := X0 xor x; + Z := T17 xor T15; + Y := T16 xor T14; + elsif R = 7 then + -- InvS7: 3 0 6 13 9 14 15 8 5 12 11 7 10 1 4 2 + -- depth := 9,7,3,3, Total gates:=18 + T01 := X0 and X1; + T02 := X0 or X1; + T03 := X2 or T01; + T04 := X3 and T02; + Z := T03 xor T04; + T06 := X1 xor T04; + T07 := X3 xor z; + T08 := not T07; + T09 := T06 or T08; + T10 := X1 xor X3; + T11 := X0 or X3; + X := X0 xor T09; + T13 := X2 xor T06; + T14 := X2 and T11; + T15 := X3 or x; + T16 := T01 or T10; + W := T13 xor T15; + Y := T14 xor T16; + end if; + X0 := W; + X1 := X; + X2 := Y; + X3 := Z; + end SI; + + + -- Linear Transform + + procedure Tr (X0, X1, X2, X3 : in out Unsigned_32) is + begin + X0 := Rotate_Left(X0, 13); + X2 := Rotate_Left(X2, 3); + X1 := X1 xor X0 xor X2; + X3 := X3 xor X2 xor Shift_Left(X0, 3); + X1 := Rotate_Left(X1, 1); + X3 := Rotate_Left(X3, 7); + X0 := X0 xor X1 xor X3; + X2 := X2 xor X3 xor Shift_Left(X1, 7); + X0 := Rotate_Left(X0, 5); + X2 := Rotate_Left(X2, 22); + end Tr; + + + -- Inverse Linear Transform + + procedure TrI (X0, X1, X2, X3 : in out Unsigned_32) is + begin + X2 := Rotate_Right(X2, 22); + X0 := Rotate_Right(X0, 5); + X2 := X2 xor X3 xor Shift_Left(X1, 7); + X0 := X0 xor X1 xor X3; + X3 := Rotate_Right(X3, 7); + X1 := Rotate_Right(X1, 1); + X3 := X3 xor X2 xor Shift_Left(X0, 3); + X1 := X1 xor X0 xor X2; + X2 := Rotate_Right(X2, 3); + X0 := Rotate_Right(X0, 13); + end TrI; + + + procedure Keying (W : Key_Schedule; + R : Integer; + X0, X1, X2, X3 : in out Unsigned_32) is + begin + X0 := X0 xor W(4*R); + X1 := X1 xor W(4*R+1); + X2 := X2 xor W(4*R+2); + X3 := X3 xor W(4*R+3); + end Keying; + + + pragma Inline(S, SI, Tr, TrI, Keying); + + + procedure Prepare_Key (K : in Key; W : out Key_Schedule) is + begin + for I in 0..7 loop + W(-8+I) := Bytes_To_Word(K(4*I .. 4*I+3)); + end loop; + for I in 0..131 loop + W(I) := Rotate_Left(W(I-8) xor W(I-5) xor W(I-3) xor W(I-1) xor + 16#9e3779b9# xor Unsigned_32(I), 11); + end loop; + S(3, W( 0), W( 1), W( 2), W( 3)); + S(2, W( 4), W( 5), W( 6), W( 7)); + S(1, W( 8), W( 9), W( 10), W( 11)); + S(0, W( 12), W( 13), W( 14), W( 15)); + S(7, W( 16), W( 17), W( 18), W( 19)); + S(6, W( 20), W( 21), W( 22), W( 23)); + S(5, W( 24), W( 25), W( 26), W( 27)); + S(4, W( 28), W( 29), W( 30), W( 31)); + S(3, W( 32), W( 33), W( 34), W( 35)); + S(2, W( 36), W( 37), W( 38), W( 39)); + S(1, W( 40), W( 41), W( 42), W( 43)); + S(0, W( 44), W( 45), W( 46), W( 47)); + S(7, W( 48), W( 49), W( 50), W( 51)); + S(6, W( 52), W( 53), W( 54), W( 55)); + S(5, W( 56), W( 57), W( 58), W( 59)); + S(4, W( 60), W( 61), W( 62), W( 63)); + S(3, W( 64), W( 65), W( 66), W( 67)); + S(2, W( 68), W( 69), W( 70), W( 71)); + S(1, W( 72), W( 73), W( 74), W( 75)); + S(0, W( 76), W( 77), W( 78), W( 79)); + S(7, W( 80), W( 81), W( 82), W( 83)); + S(6, W( 84), W( 85), W( 86), W( 87)); + S(5, W( 88), W( 89), W( 90), W( 91)); + S(4, W( 92), W( 93), W( 94), W( 95)); + S(3, W( 96), W( 97), W( 98), W( 99)); + S(2, W(100), W(101), W(102), W(103)); + S(1, W(104), W(105), W(106), W(107)); + S(0, W(108), W(109), W(110), W(111)); + S(7, W(112), W(113), W(114), W(115)); + S(6, W(116), W(117), W(118), W(119)); + S(5, W(120), W(121), W(122), W(123)); + S(4, W(124), W(125), W(126), W(127)); + S(3, W(128), W(129), W(130), W(131)); + end Prepare_Key; + + + procedure Encrypt (W : in Key_Schedule; Plaintext : in Block; + Ciphertext : out Block) is + X0, X1, X2, X3 : Unsigned_32; + begin + X0 := Bytes_To_Word(Plaintext( 0 .. 3)); + X1 := Bytes_To_Word(Plaintext( 4 .. 7)); + X2 := Bytes_To_Word(Plaintext( 8 .. 11)); + X3 := Bytes_To_Word(Plaintext(12 .. 15)); + + Keying(W, 0, X0, X1, X2, X3); S(0, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 1, X0, X1, X2, X3); S(1, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 2, X0, X1, X2, X3); S(2, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 3, X0, X1, X2, X3); S(3, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 4, X0, X1, X2, X3); S(4, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 5, X0, X1, X2, X3); S(5, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 6, X0, X1, X2, X3); S(6, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 7, X0, X1, X2, X3); S(7, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 8, X0, X1, X2, X3); S(0, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 9, X0, X1, X2, X3); S(1, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 10, X0, X1, X2, X3); S(2, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 11, X0, X1, X2, X3); S(3, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 12, X0, X1, X2, X3); S(4, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 13, X0, X1, X2, X3); S(5, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 14, X0, X1, X2, X3); S(6, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 15, X0, X1, X2, X3); S(7, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 16, X0, X1, X2, X3); S(0, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 17, X0, X1, X2, X3); S(1, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 18, X0, X1, X2, X3); S(2, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 19, X0, X1, X2, X3); S(3, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 20, X0, X1, X2, X3); S(4, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 21, X0, X1, X2, X3); S(5, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 22, X0, X1, X2, X3); S(6, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 23, X0, X1, X2, X3); S(7, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 24, X0, X1, X2, X3); S(0, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 25, X0, X1, X2, X3); S(1, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 26, X0, X1, X2, X3); S(2, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 27, X0, X1, X2, X3); S(3, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 28, X0, X1, X2, X3); S(4, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 29, X0, X1, X2, X3); S(5, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 30, X0, X1, X2, X3); S(6, X0, X1, X2, X3); Tr(X0, X1, X2, X3); + Keying(W, 31, X0, X1, X2, X3); + S(7, X0, X1, X2, X3); + Keying(W, 32, X0, X1, X2, X3); + + Ciphertext( 0 .. 3) := Word_To_Bytes(X0); + Ciphertext( 4 .. 7) := Word_To_Bytes(X1); + Ciphertext( 8 .. 11) := Word_To_Bytes(X2); + Ciphertext(12 .. 15) := Word_To_Bytes(X3); + end Encrypt; + + + procedure Decrypt (W : in Key_Schedule; Ciphertext : in Block; + Plaintext : out Block) is + X0, X1, X2, X3 : Unsigned_32; + begin + X0 := Bytes_To_Word(Ciphertext( 0 .. 3)); + X1 := Bytes_To_Word(Ciphertext( 4 .. 7)); + X2 := Bytes_To_Word(Ciphertext( 8 .. 11)); + X3 := Bytes_To_Word(Ciphertext(12 .. 15)); + + Keying(W, 32, X0, X1, X2, X3); + SI(7, X0, X1, X2, X3); + Keying(W, 31, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(6, X0, X1, X2, X3); Keying(W,30, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(5, X0, X1, X2, X3); Keying(W,29, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(4, X0, X1, X2, X3); Keying(W,28, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(3, X0, X1, X2, X3); Keying(W,27, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(2, X0, X1, X2, X3); Keying(W,26, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(1, X0, X1, X2, X3); Keying(W,25, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(0, X0, X1, X2, X3); Keying(W,24, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(7, X0, X1, X2, X3); Keying(W,23, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(6, X0, X1, X2, X3); Keying(W,22, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(5, X0, X1, X2, X3); Keying(W,21, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(4, X0, X1, X2, X3); Keying(W,20, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(3, X0, X1, X2, X3); Keying(W,19, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(2, X0, X1, X2, X3); Keying(W,18, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(1, X0, X1, X2, X3); Keying(W,17, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(0, X0, X1, X2, X3); Keying(W,16, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(7, X0, X1, X2, X3); Keying(W,15, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(6, X0, X1, X2, X3); Keying(W,14, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(5, X0, X1, X2, X3); Keying(W,13, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(4, X0, X1, X2, X3); Keying(W,12, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(3, X0, X1, X2, X3); Keying(W,11, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(2, X0, X1, X2, X3); Keying(W,10, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(1, X0, X1, X2, X3); Keying(W, 9, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(0, X0, X1, X2, X3); Keying(W, 8, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(7, X0, X1, X2, X3); Keying(W, 7, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(6, X0, X1, X2, X3); Keying(W, 6, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(5, X0, X1, X2, X3); Keying(W, 5, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(4, X0, X1, X2, X3); Keying(W, 4, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(3, X0, X1, X2, X3); Keying(W, 3, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(2, X0, X1, X2, X3); Keying(W, 2, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(1, X0, X1, X2, X3); Keying(W, 1, X0, X1, X2, X3); + TrI(X0, X1, X2, X3); SI(0, X0, X1, X2, X3); Keying(W, 0, X0, X1, X2, X3); + + Plaintext( 0 .. 3) := Word_To_Bytes(X0); + Plaintext( 4 .. 7) := Word_To_Bytes(X1); + Plaintext( 8 .. 11) := Word_To_Bytes(X2); + Plaintext(12 .. 15) := Word_To_Bytes(X3); + end Decrypt; + +end Serpent; diff -uNr a/smg_comms/src/serpent.ads b/smg_comms/src/serpent.ads --- a/smg_comms/src/serpent.ads false +++ b/smg_comms/src/serpent.ads 3dc03a39e5faf220021e2ad7a0c6e1e59b98cfd2f3b3d81aad065632268bb091077ee74ba4e3138edd4594bf562acaa68d6e5a150e56f5e4c3eff992f1702981 @@ -0,0 +1,44 @@ +------------------------------------------------------------------------------- +-- S.MG, 2018; +-- +-- Serpent Blockcipher +-- +-- Copyright (c) 1998 Markus G. Kuhn . All rights reserved. +-- +-- +------------------------------------------------------------------------------- +-- +-- This is the Ada95 reference implementation of the Serpent cipher +-- submitted by Ross Anderson, Eli Biham and Lars Knudson in June 1998 to +-- the NIST Advanced Encryption Standard (AES) contest. Please note that +-- this is a revised algorithm that is not identical to the old version +-- presented at the 1998 Fast Software Encryption Workshop. +-- +-- +-- Compiled with GNAT 3.10p under Linux, this implementation encrypts and +-- decrypts with 20.8 Mbit/s on a 300 MHz Pentium II. +-- +------------------------------------------------------------------------------- + +with Interfaces; use Interfaces; +with Raw_Types; + +package Serpent is + + pragma Pure(Serpent); + + subtype Bytes is Raw_Types.Octets; + type Words is array (Integer range <>) of Unsigned_32; + subtype Block is Bytes (0 .. 15); + subtype Key is Bytes (0 .. 31); + subtype Key_Schedule is Words (-8 .. 131); + + procedure Prepare_Key (K : in Key; W : out Key_Schedule); + + procedure Encrypt (W : in Key_Schedule; Plaintext : in Block; + Ciphertext : out Block); + + procedure Decrypt (W : in Key_Schedule; Ciphertext : in Block; + Plaintext : out Block); + +end Serpent; diff -uNr a/smg_comms/tests/obj/README b/smg_comms/tests/obj/README --- a/smg_comms/tests/obj/README false +++ b/smg_comms/tests/obj/README 50f9b127e6ae2019779520d8998bea7f559496b1847c7c66b6ce6a6f3fc20db67d45f1fbf7a9318c86ebba0694db73de168f409d8328a751f3104c1474a83a0d @@ -0,0 +1 @@ +obj diff -uNr a/smg_comms/tests/test_comms.gpr b/smg_comms/tests/test_comms.gpr --- a/smg_comms/tests/test_comms.gpr false +++ b/smg_comms/tests/test_comms.gpr f12ca7f8f9755ad77b5ef30ad9ee5c3ca83d1d24ffa5807f669005a3ce8f3ba37321e313e76c5d6141af32c716a61cca94e5a668291f46c2633a8a447b7758a9 @@ -0,0 +1,52 @@ + -- S.MG, 2018 + -- basic tests for the prototype implementation of S.MG communication protocol + -- http://trilema.com/2018/euloras-communication-protocol-restated/ + +with "../smg_comms.gpr"; + +project Test_comms is + + type Mode_Type is ("debug", "release"); + Mode : Mode_Type := external ("mode", "release"); + + for Languages use ("Ada"); + + for Source_Dirs use ("."); + for Ignore_Source_Sub_Dirs use (".svn", ".git", "@*"); + + for Object_Dir use "obj"; + for Exec_Dir use "."; + + for Main use ("testall.adb"); + + package Compiler is + + case Mode is + when "debug" => + for Switches ("Ada") + use ("-g"); + when "release" => + for Switches ("Ada") + use ("-O2", "-fdump-scos", "-gnata", "-fstack-check", + "-gnatyd", "-gnatym", + "-fdata-sections", "-ffunction-sections", "-gnatwr", "-gnatw.d", + "-gnatec=" & SMG_Comms'Project_Dir & "restrict.adc"); + end case; + end Compiler; + + package Builder is + for Executable ("test_comms.adb") use "test_comms"; + end Builder; + + package Binder is + case Mode is + when "debug" => + for Switches ("Ada") + use (); + when "release" => + for Switches ("Ada") + use ("-static"); + end case; + end Binder; + +end Test_comms; diff -uNr a/smg_comms/tests/test_packing.adb b/smg_comms/tests/test_packing.adb --- a/smg_comms/tests/test_packing.adb false +++ b/smg_comms/tests/test_packing.adb 27bbb5c117f46558f9f220e460e66c340d340e1d5315ec372b6c7765d709b22e56277a21712643cbcf8db468752f5a22a7e9d832150a4b32b1c343b69ed24b20 @@ -0,0 +1,63 @@ +-- Tests for SMG_Comms.Packing +-- S.MG, 2018 + +with Packing; use Packing; +with Raw_Types; use Raw_Types; +with Serpent; use Serpent; + +with Interfaces; use Interfaces; +with Ada.Text_IO; use Ada.Text_IO; + +package body Test_Packing is + + procedure Print(Data: in Raw_Types.Octets; Msg: in String) is + begin + Put_Line(Msg); + for I of Data loop + Put(Unsigned_8'Image(I)); + end loop; + New_Line; + end Print; + + procedure Test_Pack_Unpack is + InMsg : Serpent_Msg := (others => 0); + OutMsg : Serpent_Msg := (others => 0); + + InPkt : Serpent_Pkt := (others => 0); + OutPkt : Serpent_Pkt := (others => 0); + + K : Key := (others => 0); + KS : Key_Schedule; + Plain : Block := (others => 0); + Encr : Block := (others => 0); + Len : constant Natural := + Raw_Types.SERPENT_OCTETS / Serpent.Block'Length; + begin + for I in 1 .. 128 loop + OutPkt := Pack(InMsg, K); + if OutPkt = InMsg then + raise Test_Error; + end if; + + OutMsg := Unpack(OutPkt, K); + if OutMsg /= InMsg then + raise Test_Error; + end if; + + -- check result of pack + Prepare_Key(K, KS); + for J in 1 .. Len loop + Plain := InMsg((J-1)*Block'Length + 1 .. J*Block'Length); + Serpent.Encrypt(KS, Plain, Encr); + if Encr /= OutPkt((J-1)*Block'Length + 1 .. J*Block'Length) then + raise Test_Error; + end if; + end loop; + + -- iterate, re-packing as "message" the previous package + InMsg := OutPkt; + end loop; + + end Test_Pack_Unpack; + +end Test_Packing; diff -uNr a/smg_comms/tests/test_packing.ads b/smg_comms/tests/test_packing.ads --- a/smg_comms/tests/test_packing.ads false +++ b/smg_comms/tests/test_packing.ads 2ffca1d2b5811d3ec15095f73bc55207e4de623978585c4d4e408cf881a7ca6a5e6d4bb9ef3ccd6888f74377cdefd085c96314559a916200999bee45ed61a6ae @@ -0,0 +1,13 @@ +-- Tests for SMG_Comms.Packing +-- S.MG, 2018 + +with Raw_Types; + +package Test_Packing is + Test_Error : exception; -- raised if a test failed + + -- utility method for printing an array of octets + procedure Print(Data: in Raw_Types.Octets; Msg: in String); + + procedure Test_Pack_Unpack; +end Test_Packing; diff -uNr a/smg_comms/tests/test_serpent.adb b/smg_comms/tests/test_serpent.adb --- a/smg_comms/tests/test_serpent.adb false +++ b/smg_comms/tests/test_serpent.adb 5391b6bddacb52e015b16f67b366754d20fba03a96b1d036a44f0d71b85122c3f5a0a15123bc4e353669418b7038161f2f820c36c12b6b5d0ddabd3a8ac6ba07 @@ -0,0 +1,31 @@ +-- S.MG, 2018 + +with Raw_Types; use Raw_Types; +with Serpent; use Serpent; + +package body Test_Serpent is + + procedure Selftest is + K : Key := (others => 0); + P : Block := (others => 0); + P2, C : Block; + W : Key_Schedule; + begin + for I in 1 .. 128 loop + Prepare_Key(K, W); + Encrypt(W, P, C); + Decrypt(W, C, P2); + if (P2 /= P) then + raise Implementation_Error; + end if; + P := K( 0 .. 15); + K( 0 .. 15) := K(16 .. 31); + K(16 .. 31) := C; + end loop; + if C /= (16#A2#, 16#46#, 16#AB#, 16#69#, 16#0A#, 16#E6#, 16#8D#, 16#FB#, + 16#02#, 16#04#, 16#CB#, 16#E2#, 16#8E#, 16#D8#, 16#EB#, 16#7A#) + then + raise Implementation_Error; + end if; + end Selftest; +end Test_Serpent; diff -uNr a/smg_comms/tests/test_serpent.ads b/smg_comms/tests/test_serpent.ads --- a/smg_comms/tests/test_serpent.ads false +++ b/smg_comms/tests/test_serpent.ads eab1b7a936b15973ff60966c0ee60bf8166c246e7534be8df0ef3429ca233a631eead75f67032c3cf11cf46215804df4b05c6d11d5dd4ea33b466fa065d9ff34 @@ -0,0 +1,8 @@ +--S.MG, 2018 + +package Test_Serpent is + Implementation_Error : exception; -- raised if Selftest failed + + procedure Selftest; + +end Test_Serpent; diff -uNr a/smg_comms/tests/testall.adb b/smg_comms/tests/testall.adb --- a/smg_comms/tests/testall.adb false +++ b/smg_comms/tests/testall.adb d2f582ffa3714e9756ad5a412ea1cacba2bbd0b4e9bba295217333ae4fc9b7b21afed99a5db413a3800e77dc407a500265de7140466342a9992403a351a1b68d @@ -0,0 +1,10 @@ +-- S.MG, 2018 + +with Test_Serpent; +with Test_Packing; + +procedure testall is +begin + Test_Serpent.Selftest; + Test_Packing.Test_Pack_Unpack; +end testall;