with Ada.Text_IO; use Ada.Text_IO; with Interfaces; procedure Day_4 is type Uint32 is mod 2**32; type Uint64 is mod 2**64; type Uint128 is mod 2**128; type Byte is range 0 .. 2**8 -1; for Byte'Size use 8; package Uint128_IO is new Ada.Text_IO.Modular_IO( Uint128 ); package Uint32_IO is new Ada.Text_IO.Modular_IO( Uint32 ); type Byte_Array is array (Natural range <>) of Byte; type Uint32_Array is array (Natural range <>) of Uint32; function Hex( Num : Uint32 ) return String is Str : String( 1 .. 8 ); Tally : Uint32 := Num; Temp : Uint32; begin for I in reverse Str'Range loop Temp := Tally mod 16; case Temp is when 0 .. 9 => Str(I) := Character'Val(48 + Temp); when 10 .. 15 => Str(I) := Character'val(65 + (Temp - 10)); when others => Str(I) := 'x'; end case; Tally := Tally / 16; end loop; return Str; end Hex; function Pad( Key : String ) return Byte_Array is Size : Natural := Key'Length; Mod_Size : Natural := Size mod 64; Pad_Size : Natural; Original : Uint64 := Uint64(Size) * 8; begin if Mod_Size <= 55 then Pad_Size := 55 - Mod_Size; else Pad_Size := (63 - Mod_Size) + 56; end if; declare B : Byte_Array( 0 .. Pad_Size + Size + 8); begin for I in Key'Range loop B(I-1) := Byte(Character'Pos(Key(I))); end loop; B(Key'Last) := 16#80#; for I in 1 .. Pad_Size loop B(Key'Last + I) := 0; end loop; for I in 0 .. 7 loop B(B'Last - (7-I)) := Byte((Original / 2**(8*I)) and 16#FF#); end loop; return B; end; end Pad; function MD5( Key : String ) return Uint128 is S : Uint32_Array( 0 .. 63 ) := ( 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 ); K : Uint32_Array( 0 .. 63 ) := ( 16#d76aa478#, 16#e8c7b756#, 16#242070db#, 16#c1bdceee#, 16#f57c0faf#, 16#4787c62a#, 16#a8304613#, 16#fd469501#, 16#698098d8#, 16#8b44f7af#, 16#ffff5bb1#, 16#895cd7be#, 16#6b901122#, 16#fd987193#, 16#a679438e#, 16#49b40821#, 16#f61e2562#, 16#c040b340#, 16#265e5a51#, 16#e9b6c7aa#, 16#d62f105d#, 16#02441453#, 16#d8a1e681#, 16#e7d3fbc8#, 16#21e1cde6#, 16#c33707d6#, 16#f4d50d87#, 16#455a14ed#, 16#a9e3e905#, 16#fcefa3f8#, 16#676f02d9#, 16#8d2a4c8a#, 16#fffa3942#, 16#8771f681#, 16#6d9d6122#, 16#fde5380c#, 16#a4beea44#, 16#4bdecfa9#, 16#f6bb4b60#, 16#bebfbc70#, 16#289b7ec6#, 16#eaa127fa#, 16#d4ef3085#, 16#04881d05#, 16#d9d4d039#, 16#e6db99e5#, 16#1fa27cf8#, 16#c4ac5665#, 16#f4292244#, 16#432aff97#, 16#ab9423a7#, 16#fc93a039#, 16#655b59c3#, 16#8f0ccc92#, 16#ffeff47d#, 16#85845dd1#, 16#6fa87e4f#, 16#fe2ce6e0#, 16#a3014314#, 16#4e0811a1#, 16#f7537e82#, 16#bd3af235#, 16#2ad7d2bb#, 16#eb86d391# ); A0 : Uint32 := 16#67452301#; B0 : Uint32 := 16#efcdab89#; C0 : Uint32 := 16#98badcfe#; D0 : Uint32 := 16#10325476#; Data : Byte_Array := Pad(Key); Output : Uint128 := 0; begin for I in 0 .. (Data'Length / 64) - 1 loop declare M : Uint32_Array( 0 .. 15 ); A : Uint32 := A0; B : Uint32 := B0; C : Uint32 := C0; D : Uint32 := D0; F : Uint32; G : Uint32; begin for J in 0 .. 15 loop declare Index : Integer := (I*64) + (J*4); begin M(J) := Uint32(Data(Index)); M(J) := @ + Uint32(Data(Index + 1)) * 2**8; M(J) := @ + Uint32(Data(Index + 2)) * 2**16; M(J) := @ + Uint32(Data(Index + 3)) * 2**24; end; end loop; for J in 0 .. 63 loop if J >= 0 and J <= 15 then F := (B and C) or ((not B) and D); G := Uint32(J); elsif J >= 16 and J <= 31 then F := (D and B) or ((not D) and C); G := (5*Uint32(J) + 1) mod 16; elsif J >= 32 and J <= 47 then F := B xor C xor D; G := (3*Uint32(J) + 5) mod 16; else F := C xor (B or (not D)); G := (7*Uint32(J)) mod 16; end if; F := F + A + K(J) + M(Integer(G)); A := D; D := C; C := B; B := B + Uint32( Interfaces.Rotate_Left( Interfaces.Unsigned_32(F), Natural(S(J)))); end loop; A0 := @ + A; B0 := @ + B; C0 := @ + C; D0 := @ + D; end; end loop; declare Output_Arr : Uint32_Array := [A0, B0, C0, D0]; begin for I in 0 .. 3 loop declare Nibble : Uint32 := Output_Arr(I); begin for J in 0 .. 3 loop Output := (@ * 2**8) + Uint128(Nibble mod 2**8); Nibble := @ / 2**8; end loop; end; end loop; end; return Output; end MD5; Base_Key : String := "yzbqklnj"; Index : Positive := 1; MD5_Hash : Uint128; begin Uint128_IO.Put(MD5("a"), Base => 16); New_Line; loop declare Num : String := Index'Image; begin Put_Line("Testing: " & Base_Key & Num(Num'First + 1 .. Num'Last)); MD5_Hash := MD5(Base_Key & Num( Num'First + 1 .. Num'Last)); Uint128_IO.Put(MD5_Hash, Base => 16); New_Line; end; exit when (MD5_Hash and 16#FFFFFF00000000000000000000000000#) = 0; Index := @ + 1; end loop; Put_Line("Key is" & Index'Image); end Day_4;