cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ctx_hmd5.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib HMAC-MD5 Hash Routines *
4 * Copyright Peter Gutmann 1997-2005 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "context.h"
11  #include "md5.h"
12 #else
13  #include "crypt.h"
14  #include "context/context.h"
15  #include "crypt/md5.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_MD5
19 
20 /* A structure to hold the initial and current MAC state info. Rather than
21  redoing the key processing each time when we're calculating multiple MACs
22  with the same key, we just copy the initial state into the current state */
23 
24 typedef struct {
25  MD5_CTX macState, initialMacState;
26  } MAC_STATE;
27 
28 #define MAC_STATE_SIZE sizeof( MAC_STATE )
29 
30 /****************************************************************************
31 * *
32 * HMAC-MD5 Self-test Routines *
33 * *
34 ****************************************************************************/
35 
36 #ifndef CONFIG_NO_SELFTEST
37 
38 /* Test the HMAC-MD5 output against the test vectors given in RFC 2104 and
39  RFC ???? */
40 
41 static const struct {
42  const char FAR_BSS *key; /* HMAC key */
43  const int keyLength; /* Length of key */
44  const char FAR_BSS *data; /* Data to hash */
45  const int length; /* Length of data */
46  const BYTE digest[ MD5_DIGEST_LENGTH ]; /* Digest of data */
47  } FAR_BSS hmacValues[] = {
48  { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B", 16,
49  "Hi There", 8,
50  { 0x92, 0x94, 0x72, 0x7A, 0x36, 0x38, 0xBB, 0x1C,
51  0x13, 0xF4, 0x8E, 0xF8, 0x15, 0x8B, 0xFC, 0x9D } },
52  { "Jefe", 4,
53  "what do ya want for nothing?", 28,
54  { 0x75, 0x0C, 0x78, 0x3E, 0x6A, 0xB0, 0xB5, 0x03,
55  0xEA, 0xA8, 0x6E, 0x31, 0x0A, 0x5D, 0xB7, 0x38 } },
56  { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 16,
57  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
58  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
59  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
60  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
61  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 50,
62  { 0x56, 0xBE, 0x34, 0x52, 0x1D, 0x14, 0x4C, 0x88,
63  0xDB, 0xB8, 0xC7, 0x33, 0xF0, 0xE8, 0xB3, 0xF6 } },
64  { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
65  "\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
66  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
67  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
68  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
69  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
70  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD", 50,
71  { 0x69, 0x7E, 0xAF, 0x0A, 0xCA, 0x3A, 0x3A, 0xEA,
72  0x3A, 0x75, 0x16, 0x47, 0x46, 0xFF, 0xAA, 0x79 } },
73 #if 0 /* Should be trunc.to 96 bits - we don't do truncation */
74  { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C", 16,
75  "Test With Truncation", 20,
76  { 0x56, 0x46, 0x1E, 0xF2, 0x34, 0x2E, 0xDC, 0x00,
77  0xF9, 0xBA, 0xB9, 0x95, 0x69, 0x0E, 0xFD, 0x4C } },
78 #endif /* 0 */
79  { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
80  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
81  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
82  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
83  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
84  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
85  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
86  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 80,
87  "Test Using Larger Than Block-Size Key - Hash Key First", 54,
88  { 0x6B, 0x1A, 0xB7, 0xFE, 0x4B, 0xD7, 0xBF, 0x8F,
89  0x0B, 0x62, 0xE6, 0xCE, 0x61, 0xB9, 0xD0, 0xCD } },
90  { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
91  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
92  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
93  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
94  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
95  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
96  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
97  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 80,
98  "Test Using Larger Than Block-Size Key and Larger Than One "
99  "Block-Size Data", 73,
100  { 0x6F, 0x63, 0x0F, 0xAD, 0x67, 0xCD, 0xA0, 0xEE,
101  0x1F, 0xB1, 0xF5, 0x62, 0xDB, 0x3A, 0xA5, 0x3E } },
102  { "", 0, NULL, 0, { 0 } }
103  };
104 
105 static int selfTest( void )
106  {
107  const CAPABILITY_INFO *capabilityInfo = getHmacMD5Capability();
108  BYTE macState[ MAC_STATE_SIZE + 8 ];
109  int i, status;
110 
111  /* Test HMAC-MD5 against the test vectors given in RFC 2104 */
112  for( i = 0; hmacValues[ i ].data != NULL; i++ )
113  {
114  status = testMAC( capabilityInfo, macState, hmacValues[ i ].key,
115  hmacValues[ i ].keyLength, hmacValues[ i ].data,
116  hmacValues[ i ].length, hmacValues[ i ].digest );
117  if( cryptStatusError( status ) )
118  return( status );
119  }
120 
121  return( CRYPT_OK );
122  }
123 #else
124  #define selfTest NULL
125 #endif /* !CONFIG_NO_SELFTEST */
126 
127 /****************************************************************************
128 * *
129 * Control Routines *
130 * *
131 ****************************************************************************/
132 
133 /* Return context subtype-specific information */
134 
136 static int getInfo( IN_ENUM( CAPABILITY_INFO ) const CAPABILITY_INFO_TYPE type,
138  OUT void *data,
139  IN_INT_Z const int length )
140  {
141  assert( contextInfoPtr == NULL || \
142  isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
143  assert( ( length == 0 && isWritePtr( data, sizeof( int ) ) ) || \
144  ( length > 0 && isWritePtr( data, length ) ) );
145 
147 
148  if( type == CAPABILITY_INFO_STATESIZE )
149  {
150  int *valuePtr = ( int * ) data;
151 
152  *valuePtr = MAC_STATE_SIZE;
153 
154  return( CRYPT_OK );
155  }
156 
157  return( getDefaultInfo( type, contextInfoPtr, data, length ) );
158  }
159 
160 /****************************************************************************
161 * *
162 * HMAC-MD5 Hash Routines *
163 * *
164 ****************************************************************************/
165 
166 /* Hash data using HMAC-MD5 */
167 
168 static int hash( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
169  {
170  MAC_INFO *macInfo = contextInfoPtr->ctxMAC;
171  MD5_CTX *md5Info = &( ( MAC_STATE * ) macInfo->macInfo )->macState;
172 
173  /* If the hash state was reset to allow another round of MAC'ing, copy
174  the initial MAC state over into the current MAC state */
175  if( !( contextInfoPtr->flags & CONTEXT_FLAG_HASH_INITED ) )
176  {
177  MAC_STATE *macState = macInfo->macInfo;
178 
179  memcpy( &macState->macState, &macState->initialMacState,
180  sizeof( MD5_CTX ) );
181  }
182 
183  if( noBytes > 0 )
184  MD5_Update( md5Info, buffer, noBytes );
185  else
186  {
187  BYTE hashBuffer[ MD5_CBLOCK + 8 ], digestBuffer[ MD5_CBLOCK + 8 ];
188  int i;
189 
190  /* Complete the inner hash and extract the digest */
191  MD5_Final( digestBuffer, md5Info );
192 
193  /* Perform the of the outer hash using the zero-padded key XOR'd
194  with the opad value followed by the digest from the inner hash */
195  memset( hashBuffer, HMAC_OPAD, MD5_CBLOCK );
196  memcpy( hashBuffer, macInfo->userKey,
197  macInfo->userKeyLength );
198  for( i = 0; i < macInfo->userKeyLength; i++ )
199  hashBuffer[ i ] ^= HMAC_OPAD;
200  MD5_Init( md5Info );
201  MD5_Update( md5Info, hashBuffer, MD5_CBLOCK );
202  memset( hashBuffer, 0, MD5_CBLOCK );
203  MD5_Update( md5Info, digestBuffer, MD5_DIGEST_LENGTH );
204  memset( digestBuffer, 0, MD5_DIGEST_LENGTH );
205  MD5_Final( macInfo->mac, md5Info );
206  }
207 
208  return( CRYPT_OK );
209  }
210 
211 /****************************************************************************
212 * *
213 * HMAC-MD5 Key Management Routines *
214 * *
215 ****************************************************************************/
216 
217 /* Set up an HMAC-MD5 key */
218 
219 static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
220  const int keyLength )
221  {
222  MAC_INFO *macInfo = contextInfoPtr->ctxMAC;
223  MD5_CTX *md5Info = &( ( MAC_STATE * ) macInfo->macInfo )->macState;
224  BYTE hashBuffer[ MD5_CBLOCK + 8 ];
225  int i;
226 
227  MD5_Init( md5Info );
228 
229  /* If the key size is larger than the MD5 data size, reduce it to the MD5
230  hash size before processing it (yuck. You're required to do this
231  though) */
232  if( keyLength > MD5_CBLOCK )
233  {
234  /* Hash the user key down to the hash size (MD5_Init() has already
235  been called when the context was created) and use the hashed form
236  of the key */
237  MD5_Update( md5Info, ( BYTE * ) key, keyLength );
238  MD5_Final( macInfo->userKey, md5Info );
239  macInfo->userKeyLength = MD5_DIGEST_LENGTH;
240 
241  /* Reset the MD5 state */
242  MD5_Init( md5Info );
243  }
244  else
245  {
246  /* Copy the key to internal storage */
247  if( macInfo->userKey != key )
248  memcpy( macInfo->userKey, key, keyLength );
249  macInfo->userKeyLength = keyLength;
250  }
251 
252  /* Perform the start of the inner hash using the zero-padded key XOR'd
253  with the ipad value */
254  memset( hashBuffer, HMAC_IPAD, MD5_CBLOCK );
255  memcpy( hashBuffer, macInfo->userKey,
256  macInfo->userKeyLength );
257  for( i = 0; i < macInfo->userKeyLength; i++ )
258  hashBuffer[ i ] ^= HMAC_IPAD;
259  MD5_Update( md5Info, hashBuffer, MD5_CBLOCK );
260  memset( hashBuffer, 0, MD5_CBLOCK );
261  contextInfoPtr->flags |= CONTEXT_FLAG_HASH_INITED;
262 
263  /* Save a copy of the initial state in case it's needed later */
264  memcpy( &( ( MAC_STATE * ) macInfo->macInfo )->initialMacState, md5Info,
265  sizeof( MD5_CTX ) );
266 
267  return( CRYPT_OK );
268  }
269 
270 /****************************************************************************
271 * *
272 * Capability Access Routines *
273 * *
274 ****************************************************************************/
275 
276 static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
277  CRYPT_ALGO_HMAC_MD5, bitsToBytes( 128 ), "HMAC-MD5", 8,
279  selfTest, getInfo, NULL, NULL, initKey, NULL, hash, hash
280  };
281 
283  {
284  return( &capabilityInfo );
285  }
286 
287 #endif /* USE_MD5 */