1------------------------------------------------------------------------------
2--                                                                          --
3--                         GNAT LIBRARY COMPONENTS                          --
4--                                                                          --
5--                   G N A T . S E C U R E _ H A S H E S                    --
6--                                                                          --
7--                                 S p e c                                  --
8--                                                                          --
9--          Copyright (C) 2009-2018, Free Software Foundation, Inc.         --
10--                                                                          --
11-- GNAT is free software;  you can  redistribute it  and/or modify it under --
12-- terms of the  GNU General Public License as published  by the Free Soft- --
13-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
14-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
17--                                                                          --
18-- As a special exception under Section 7 of GPL version 3, you are granted --
19-- additional permissions described in the GCC Runtime Library Exception,   --
20-- version 3.1, as published by the Free Software Foundation.               --
21--                                                                          --
22-- You should have received a copy of the GNU General Public License and    --
23-- a copy of the GCC Runtime Library Exception along with this program;     --
24-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
25-- <http://www.gnu.org/licenses/>.                                          --
26--                                                                          --
27-- GNAT was originally developed  by the GNAT team at  New York University. --
28-- Extensive contributions were provided by Ada Core Technologies Inc.      --
29--                                                                          --
30------------------------------------------------------------------------------
31
32--  This package provides common supporting code for a family of secure
33--  hash functions (including MD5 and the FIPS PUB 180-3 functions SHA-1,
34--  SHA-224, SHA-256, SHA-384 and SHA-512).
35
36--  This is an internal unit and should be not used directly in applications.
37--  Use GNAT.MD5 and GNAT.SHA* instead.
38
39with Ada.Streams; use Ada.Streams;
40
41with Interfaces;
42
43with System;
44
45package GNAT.Secure_Hashes is
46
47   type Buffer_Type is new String;
48   for Buffer_Type'Alignment use 8;
49   --  Secure hash functions use a string buffer that is also accessed as an
50   --  array of words, which may require up to 64 bit alignment.
51
52   --  The function-independent part of processing state: A buffer of data
53   --  being accumulated until a complete block is ready for hashing.
54
55   type Message_State (Block_Length : Natural) is record
56      Last : Natural := 0;
57      --  Index of last used element in Buffer
58
59      Length : Interfaces.Unsigned_64 := 0;
60      --  Total length of processed data
61
62      Buffer : Buffer_Type (1 .. Block_Length);
63      --  Data buffer
64   end record;
65
66   --  The function-specific part of processing state:
67
68   --  Each hash function maintains an internal state as an array of words,
69   --  which is ultimately converted to a stream representation with the
70   --  appropriate bit order.
71
72   generic
73      type Word is mod <>;
74      --  Either 32 or 64 bits
75
76      with procedure Swap (X : System.Address);
77      --  Byte swapping function for a Word at X
78
79      Hash_Bit_Order : System.Bit_Order;
80      --  Bit order of the produced hash
81
82   package Hash_Function_State is
83
84      type State is array (Natural range <>) of Word;
85      --  Used to store a hash function's internal state
86
87      procedure To_Hash
88        (H      : State;
89         H_Bits : out Stream_Element_Array);
90      --  Convert H to stream representation with the given bit order. If
91      --  H_Bits is smaller than the internal hash state, then the state
92      --  is truncated.
93
94   end Hash_Function_State;
95
96   --  Generic hashing framework: The user interface for each implemented
97   --  secure hash function is an instance of this generic package.
98
99   generic
100      Block_Words : Natural;
101      --  Number of words in each block
102
103      State_Words : Natural;
104      --  Number of words in internal state
105
106      Hash_Words : Natural;
107      --  Number of words in the final hash (must be no greater than
108      --  State_Words).
109
110      Hash_Bit_Order : System.Bit_Order;
111      --  Bit order used for conversion between bit representation and word
112      --  representation.
113
114      with package Hash_State is new Hash_Function_State (<>);
115      --  Hash function state package
116
117      Initial_State : Hash_State.State;
118      --  Initial value of the hash function state
119
120      with procedure Transform
121        (H : in out Hash_State.State;
122         M : in out Message_State);
123      --  Transformation function updating H by processing a complete data
124      --  block from M.
125
126   package H is
127
128      --  The visible part of H is the interface to secure hashing functions
129      --  that is exposed to user applications, and is intended to remain
130      --  a stable interface.
131
132      pragma Assert (Hash_Words <= State_Words);
133
134      type Context is private;
135      --  The internal processing state of the hashing function
136
137      function "=" (L, R : Context) return Boolean is abstract;
138      --  Context is the internal, implementation defined intermediate state
139      --  in a hash computation, and no specific semantics can be expected on
140      --  equality of context values. Only equality of final hash values (as
141      --  returned by the [Wide_]Digest functions below) is meaningful.
142
143      Initial_Context : constant Context;
144      --  Initial value of a Context object. May be used to reinitialize
145      --  a Context value by simple assignment of this value to the object.
146
147      function HMAC_Initial_Context (Key : String) return Context;
148      --  Initial Context for HMAC computation with the given Key
149
150      procedure Update      (C : in out Context; Input : String);
151      procedure Wide_Update (C : in out Context; Input : Wide_String);
152      procedure Update
153        (C     : in out Context;
154         Input : Stream_Element_Array);
155      --  Update C to process the given input. Successive calls to Update are
156      --  equivalent to a single call with the concatenation of the inputs. For
157      --  the Wide_String version, each Wide_Character is processed low order
158      --  byte first.
159
160      Word_Length : constant Natural := Hash_State.Word'Size / 8;
161      Hash_Length : constant Natural := Hash_Words * Word_Length;
162
163      subtype Binary_Message_Digest is
164        Stream_Element_Array (1 .. Stream_Element_Offset (Hash_Length));
165      --  The fixed-length byte array returned by Digest, providing
166      --  the hash in binary representation.
167
168      function Digest (C : Context) return Binary_Message_Digest;
169      --  Return hash or HMAC for the data accumulated with C
170
171      function Digest      (S : String)      return Binary_Message_Digest;
172      function Wide_Digest (W : Wide_String) return Binary_Message_Digest;
173      function Digest
174        (A : Stream_Element_Array)           return Binary_Message_Digest;
175      --  These functions are equivalent to the corresponding Update (or
176      --  Wide_Update) on a default initialized Context, followed by Digest
177      --  on the resulting Context.
178
179      subtype Message_Digest is String (1 .. 2 * Hash_Length);
180      --  The fixed-length string returned by Digest, providing the hash in
181      --  hexadecimal representation.
182
183      function Digest (C : Context) return Message_Digest;
184      --  Return hash or HMAC for the data accumulated with C in hexadecimal
185      --  representation.
186
187      function Digest      (S : String)               return Message_Digest;
188      function Wide_Digest (W : Wide_String)          return Message_Digest;
189      function Digest      (A : Stream_Element_Array) return Message_Digest;
190      --  These functions are equivalent to the corresponding Update (or
191      --  Wide_Update) on a default initialized Context, followed by Digest
192      --  on the resulting Context.
193
194      type Hash_Stream (C : access Context) is
195        new Root_Stream_Type with private;
196      --  Stream wrapper converting Write calls to Update calls on C.
197      --  Arbitrary data structures can thus be conveniently hashed using
198      --  their stream attributes.
199
200   private
201
202      Block_Length : constant Natural := Block_Words * Word_Length;
203      --  Length in bytes of a data block
204
205      subtype Key_Length is
206        Stream_Element_Offset range 0 .. Stream_Element_Offset (Block_Length);
207
208      --  KL is 0 for a normal hash context, > 0 for HMAC
209
210      type Context (KL : Key_Length := 0) is record
211         H_State : Hash_State.State (0 .. State_Words - 1) := Initial_State;
212         --  Function-specific state
213
214         M_State : Message_State (Block_Length);
215         --  Function-independent state (block buffer)
216
217         Key : Stream_Element_Array (1 .. KL);
218         --  HMAC key
219      end record;
220
221      Initial_Context : constant Context (KL => 0) := (others => <>);
222      --  Initial values are provided by default initialization of Context
223
224      type Hash_Stream (C : access Context) is
225        new Root_Stream_Type with null record;
226
227      procedure Read
228        (Stream : in out Hash_Stream;
229         Item   : out Stream_Element_Array;
230         Last   : out Stream_Element_Offset);
231      --  Raise Program_Error: hash streams are write-only
232
233      procedure Write
234         (Stream : in out Hash_Stream;
235          Item   : Stream_Element_Array);
236      --  Call Update
237
238   end H;
239
240end GNAT.Secure_Hashes;
241