-- HMAC - Provide a comprehensive generic HMAC package that suffices for the SHA family and similar. -- Copyright (C) 2023 Prince Trippy . -- This program is free software: you can redistribute it and/or modify it under the terms of the -- GNU Affero General Public License version 3 as published by the Free Software Foundation. -- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without -- even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU Affero General Public License for more details. -- You should have received a copy of the GNU Affero General Public License along with this program. -- If not, see . package HMAC is function "xor" (Left, Right : in Unit_Block) return Unit_Block is Result : Unit_Block; begin for I in Unit_Block'Range loop Result(I) := Left(I) xor Right(I); end loop; return Result; end "xor"; function Prepare_Key (Key : in Unit_Array) return Prepared_Key is Derived_Key : Unit_Block := (others => 0); begin if Key'Length > Unit_Block'Length then declare D : Unit_Array := To_Unit(Hash(Key)); begin -- However unreasonable, I won't assume the digest to be shorter than the unit block. for I in Positive range 1 .. Natural'Min(D'Length, Unit_Block'Length) loop Derived_Key(Derived_Key'First + Integer'Pred(I)) := D(D'First + Integer'Pred(I)); end loop; end; else Derived_Key(Unit_Block'First .. Unit_Block'First + Integer'Pred(Key'Length)) := Key; end if; return (Outer_Status => Hash(Initial_Status_Constant, Outer_Pad xor Derived_Key), Inner_Status => Hash(Initial_Status_Constant, Inner_Pad xor Derived_Key)); end Prepare_Key; function HMAC (Key : in Prepared_Key; Data : in Unit_Array) return Digest_Type is Input_Length : Length_Type := Length_Type'Mod(Data'Length); Block_Length : Length_Type := Length_Type'Mod(Unit_Block'Length); Inner_Length : Natural := Natural(Input_Length + Block_Length); Inner_Digest : Unit_Array := To_Unit(Hash(Key.Inner_Status, Data, Inner_Length)); Outer_Length : Natural := Natural(Length_Type'Mod(Inner_Digest'Length) + Block_Length); begin return Hash(Key.Outer_Status, Inner_Digest, Outer_Length); end HMAC; end HMAC; .