-- S.MG, 2018 -- Testing of Serpent implementation using Nessie-format test vectors with SMG_Serpent; use SMG_Serpent; with Ada.Text_IO; use Ada.Text_IO; with Ada.Command_Line; use Ada.Command_Line; -- set exit status on fail with Interfaces; use Interfaces; -- unsigned_8 package body Test_Serpent is Test_Fail : exception; -- raised if a test fails procedure test_from_file (filename: String) is file : FILE_TYPE; keylen : constant := 256; blocklen : constant := 128; octets : constant := 16; K : Key; P, P2 : Block; --plain text C, C2 : Block; --cipher (encrypted) text times100 : Block; --value after 100 iterations times1k : Block; --value after 1000 iterations W : Key_Schedule; Test_No : Positive := 1; begin begin open(file, In_File, filename); exception when others => Put_Line(Standard_Error, "Can not open the file '" & filename & "'. Does it exist?"); Set_Exit_Status(Failure); return; end; loop declare Line1 : String := Get_Line(file); Line2 : String := Line1; key1, key2 : String( 1..octets*2 ); len : Natural := 0; begin --check if this is test data of any known kind if index( Line1, "key=", 1 ) > 0 then Line2 := Get_Line( file ); key1 := Tail( Line1, octets*2 ); key2 := Tail( Line2, octets*2 ); for jj in 1..octets loop K(jj-1) := Unsigned_8'Value("16#" & key1( ( jj - 1 ) * 2 + 1 .. jj * 2 ) & "#"); K( jj + octets - 1 ) := Unsigned_8'Value("16#" & key2( ( jj - 1 ) * 2 + 1 .. jj * 2 ) & "#"); end loop; elsif index( Line1, "plain=", 1 ) > 0 then key1 := Tail( Line1, octets * 2 ); for jj in 1..octets loop P(jj-1) := Unsigned_8'Value("16#" & key1( ( jj - 1 ) * 2 + 1 .. jj * 2 ) & "#"); end loop; elsif index( Line1, "cipher=", 1 ) > 0 then key1 := Tail( Line1, octets * 2 ); for jj in 1..octets loop C(jj-1) := Unsigned_8'Value("16#" & key1( ( jj - 1 ) * 2 + 1 .. jj * 2) & "#"); end loop; elsif index( Line1, "100 times=", 1 ) > 0 then key1 := Tail( Line1, octets * 2 ); for jj in 1..octets loop times100(jj-1) := Unsigned_8'Value("16#" & key1( ( jj - 1 ) * 2 + 1 .. jj * 2 ) & "#"); end loop; elsif index( Line1, "1000 times=", 1 ) > 0 then key1 := Tail( Line1, octets * 2 ); for jj in 1..octets loop times1k(jj-1) := Unsigned_8'value("16#" & key1( ( jj - 1 ) * 2 + 1 .. jj * 2 ) & "#"); end loop; --at this stage we should have ALL needed, so run test Put("-----Test " & Positive'Image(Test_No) & ": encryption..."); Prepare_Key(K, W); Encrypt(W, P, C2); if C2 /= C then raise Test_Fail; else Put_Line("Passed-----"); end if; Put("-----Test " & Positive'Image(Test_No) & ": decryption..."); Decrypt(W, C2, P2); if P /= P2 then raise Test_Fail; else Put_Line("Passed-----"); end if; Put("-----Test " & Positive'Image(Test_No) & ": 100 iterations..."); for jj in 1 .. 100 loop Encrypt(W, P, C2); Decrypt(W, C2, P2); if (P2 /= P) then raise Test_Fail; end if; P := C2; end loop; Put_Line("Passed-----"); Put("-----Test " & Positive'Image(Test_No) & ": 1000 iterations..."); for jj in 1 .. 900 loop Encrypt(W, P, C2); Decrypt(W, C2, P2); if (P2 /= P) then raise Test_Fail; end if; P := C2; end loop; Put_Line("Passed-----"); Test_No := Test_No + 1; end if; exit when End_Of_File(file); end; end loop; Close(file); end test_from_file; procedure test_one is K: Key; P, P2: Block; C: Block; W: Key_Schedule; begin K := (16#80#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#); P := (16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#); SMG_Serpent.Prepare_Key(K, W); Encrypt(W, P, C); if C /= (16#A2#, 16#23#, 16#AA#, 16#12#, 16#88#, 16#46#, 16#3C#, 16#0E#, 16#2B#, 16#E3#, 16#8E#, 16#BD#, 16#82#, 16#56#, 16#16#, 16#C0#) then raise Test_Fail; end if; for I in 1 .. 100 loop Encrypt(W, P, C); Decrypt(W, C, P2); if (P2 /= P) then raise Test_Fail; end if; P := C; end loop; if C /= (16#73#, 16#9E#, 16#01#, 16#48#, 16#97#, 16#1F#, 16#D9#, 16#75#, 16#B5#, 16#85#, 16#EA#, 16#FD#, 16#BD#, 16#65#, 16#9E#, 16#2C#) then raise Test_Fail; end if; for I in 1 .. 900 loop Encrypt(W, P, C); Decrypt(W, C, P2); if (P2 /= P) then raise Test_Fail; end if; P := C; end loop; if C /= (16#BE#, 16#FD#, 16#00#, 16#E0#, 16#D6#, 16#E2#, 16#7E#, 16#56#, 16#95#, 16#1D#, 16#C6#, 16#61#, 16#44#, 16#40#, 16#D2#, 16#86#) then raise Test_Fail; else Put_Line("PASSED: test single case."); end if; end test_one; end Test_Serpent;