cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ctx_hsha2.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib HMAC-SHA2 Hash Routines *
4 * Copyright Peter Gutmann 2004-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "context.h"
11  #include "sha2.h"
12 #else
13  #include "crypt.h"
14  #include "context/context.h"
15  #include "crypt/sha2.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_SHA2
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  sha2_ctx macState, initialMacState;
26  } MAC_STATE;
27 
28 #define MAC_STATE_SIZE sizeof( MAC_STATE )
29 
30 #ifndef SHA384_DIGEST_SIZE
31  /* These may not be defined on non 64-bit systems */
32  #define SHA384_DIGEST_SIZE 48
33  #define SHA512_DIGEST_SIZE 64
34  #define sha2_begin( size, ctx ) sha256_begin( ( ctx )->uu->ctx256 )
35  #define sha2_hash( data, len, ctx ) sha256_hash( data, len, ( ctx )->uu->ctx256 )
36  #define sha2_end( hash, ctx ) sha256_end( hash, ( ctx )->uu->ctx256 )
37 #endif /* SHA384_DIGEST_SIZE */
38 
39 /****************************************************************************
40 * *
41 * HMAC-SHA2 Self-test Routines *
42 * *
43 ****************************************************************************/
44 
45 #ifndef CONFIG_NO_SELFTEST
46 
47 /* Test the HMAC-SHA2 output against the test vectors given in RFC 4231 */
48 
49 static const struct {
50  const char FAR_BSS *key; /* HMAC key */
51  const int keyLength; /* Length of key */
52  const char FAR_BSS *data; /* Data to hash */
53  const int length; /* Length of data */
54  const BYTE digest[ SHA256_DIGEST_SIZE ]; /* Digest of data */
55  } FAR_BSS hmacValues[] = {
56  { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
57  "\x0B\x0B\x0B\x0B", 20,
58  "Hi There", 8,
59  { 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53,
60  0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B,
61  0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7,
62  0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 } },
63  { "Jefe", 4,
64  "what do ya want for nothing?", 28,
65  { 0x5B, 0xDC, 0xC1, 0x46, 0xBF, 0x60, 0x75, 0x4E,
66  0x6A, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xC7,
67  0x5A, 0x00, 0x3F, 0x08, 0x9D, 0x27, 0x39, 0x83,
68  0x9D, 0xEC, 0x58, 0xB9, 0x64, 0xEC, 0x38, 0x43 } },
69  { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
70  "\xAA\xAA\xAA\xAA", 20,
71  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
72  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
73  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
74  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
75  "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD", 50,
76  { 0x77, 0x3E, 0xA9, 0x1E, 0x36, 0x80, 0x0E, 0x46,
77  0x85, 0x4D, 0xB8, 0xEB, 0xD0, 0x91, 0x81, 0xA7,
78  0x29, 0x59, 0x09, 0x8B, 0x3E, 0xF8, 0xC1, 0x22,
79  0xD9, 0x63, 0x55, 0x14, 0xCE, 0xD5, 0x65, 0xFE } },
80  { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
81  "\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
82  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
83  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
84  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
85  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
86  "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD", 50,
87  { 0x82, 0x55, 0x8A, 0x38, 0x9A, 0x44, 0x3C, 0x0E,
88  0xA4, 0xCC, 0x81, 0x98, 0x99, 0xF2, 0x08, 0x3A,
89  0x85, 0xF0, 0xFA, 0xA3, 0xE5, 0x78, 0xF8, 0x07,
90  0x7A, 0x2E, 0x3F, 0xF4, 0x67, 0x29, 0x66, 0x5B } },
91 #if 0 /* Should be truncated to 128 bits - we don't do truncation */
92  { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
93  "\x0C\x0C\x0C\x0C", 20,
94  "Test With Truncation", 20,
95  { 0xA3, 0xB6, 0x16, 0x74, 0x73, 0x10, 0x0E, 0xE0,
96  0x6E, 0x0C, 0x79, 0x6C, 0x29, 0x55, 0x55, 0x2B } },
97 #endif /* 0 */
98  { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
99  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
100  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
101  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
102  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
103  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
104  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
105  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
106  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
107  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
108  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
109  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
110  "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
111  "\xAA", 131,
112  "Test Using Larger Than Block-Size Key - Hash Key First", 54,
113  { 0x60, 0xE4, 0x31, 0x59, 0x1E, 0xE0, 0xB6, 0x7F,
114  0x0D, 0x8A, 0x26, 0xAA, 0xCB, 0xF5, 0xB7, 0x7F,
115  0x8E, 0x0B, 0xC6, 0x21, 0x37, 0x28, 0xC5, 0x14,
116  0x05, 0x46, 0x04, 0x0F, 0x0E, 0xE3, 0x7F, 0x54 } },
117 
118  { "", 0, NULL, 0, { 0 } }
119  };
120 
121 static int selfTest( void )
122  {
123  const CAPABILITY_INFO *capabilityInfo = getHmacSHA2Capability();
124  BYTE macState[ MAC_STATE_SIZE + 8 ];
125  int i, status;
126 
127  /* Test HMAC-SHA2 against the test vectors given in RFC 4231 */
128  for( i = 0; hmacValues[ i ].data != NULL; i++ )
129  {
130  status = testMAC( capabilityInfo, macState, hmacValues[ i ].key,
131  hmacValues[ i ].keyLength, hmacValues[ i ].data,
132  hmacValues[ i ].length, hmacValues[ i ].digest );
133  if( cryptStatusError( status ) )
134  return( status );
135  }
136 
137  return( CRYPT_OK );
138  }
139 #else
140  #define selfTest NULL
141 #endif /* !CONFIG_NO_SELFTEST */
142 
143 /****************************************************************************
144 * *
145 * Control Routines *
146 * *
147 ****************************************************************************/
148 
149 /* Return context subtype-specific information */
150 
152 static int getInfo( IN_ENUM( CAPABILITY_INFO ) const CAPABILITY_INFO_TYPE type,
154  OUT void *data,
155  IN_INT_Z const int length )
156  {
157  assert( contextInfoPtr == NULL || \
158  isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
159  assert( ( length == 0 && isWritePtr( data, sizeof( int ) ) ) || \
160  ( length > 0 && isWritePtr( data, length ) ) );
161 
163 
164  if( type == CAPABILITY_INFO_STATESIZE )
165  {
166  int *valuePtr = ( int * ) data;
167 
168  *valuePtr = MAC_STATE_SIZE;
169 
170  return( CRYPT_OK );
171  }
172 
173  return( getDefaultInfo( type, contextInfoPtr, data, length ) );
174  }
175 
176 /****************************************************************************
177 * *
178 * HMAC-SHA2 Hash Routines *
179 * *
180 ****************************************************************************/
181 
182 /* Hash data using HMAC-SHA2 */
183 
184 static int hash( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
185  {
186  MAC_INFO *macInfo = contextInfoPtr->ctxMAC;
187  sha2_ctx *shaInfo = &( ( MAC_STATE * ) macInfo->macInfo )->macState;
188 
189  /* If the hash state was reset to allow another round of MAC'ing, copy
190  the initial MAC state over into the current MAC state */
191  if( !( contextInfoPtr->flags & CONTEXT_FLAG_HASH_INITED ) )
192  {
193  MAC_STATE *macState = macInfo->macInfo;
194 
195  memcpy( &macState->macState, &macState->initialMacState,
196  sizeof( sha2_ctx ) );
197  }
198 
199  if( noBytes > 0 )
200  sha2_hash( buffer, noBytes, shaInfo );
201  else
202  {
203  const int digestSize = contextInfoPtr->capabilityInfo->blockSize;
204  BYTE hashBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
205  BYTE digestBuffer[ CRYPT_MAX_HASHSIZE + 8 ];
206  int i;
207 
208  /* Complete the inner hash and extract the digest */
209  sha2_end( digestBuffer, shaInfo );
210 
211  /* Perform the of the outer hash using the zero-padded key XOR'd
212  with the opad value followed by the digest from the inner hash */
213  memset( hashBuffer, HMAC_OPAD, SHA256_BLOCK_SIZE );
214  memcpy( hashBuffer, macInfo->userKey,
215  macInfo->userKeyLength );
216  for( i = 0; i < macInfo->userKeyLength; i++ )
217  hashBuffer[ i ] ^= HMAC_OPAD;
218  sha2_begin( digestSize, shaInfo );
219  sha2_hash( hashBuffer, SHA256_BLOCK_SIZE, shaInfo );
220  memset( hashBuffer, 0, SHA256_BLOCK_SIZE );
221  sha2_hash( digestBuffer, digestSize, shaInfo );
222  memset( digestBuffer, 0, digestSize );
223  sha2_end( macInfo->mac, shaInfo );
224  }
225 
226  return( CRYPT_OK );
227  }
228 
229 /****************************************************************************
230 * *
231 * HMAC-SHA2 Key Management Routines *
232 * *
233 ****************************************************************************/
234 
235 /* Set up an HMAC-SHA2 key */
236 
237 static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
238  const int keyLength )
239  {
240  MAC_INFO *macInfo = contextInfoPtr->ctxMAC;
241  sha2_ctx *shaInfo = &( ( MAC_STATE * ) macInfo->macInfo )->macState;
242  BYTE hashBuffer[ SHA256_BLOCK_SIZE + 8 ];
243  const int digestSize = contextInfoPtr->capabilityInfo->blockSize;
244  int i;
245 
246  sha2_begin( digestSize, shaInfo );
247 
248  /* If the key size is larger than tha SHA2 data size, reduce it to the
249  SHA2 hash size before processing it (yuck. You're required to do this
250  though) */
251  if( keyLength > SHA256_BLOCK_SIZE )
252  {
253  /* Hash the user key down to the hash size (sha2_begin() has already
254  been called when the context was created) and use the hashed form
255  of the key */
256  sha2_hash( ( void * ) key, keyLength, shaInfo );
257  sha2_end( macInfo->userKey, shaInfo );
258  macInfo->userKeyLength = digestSize;
259 
260  /* Reset the SHA2 state */
261  sha2_begin( digestSize, shaInfo );
262  }
263  else
264  {
265  /* Copy the key to internal storage */
266  if( macInfo->userKey != key )
267  memcpy( macInfo->userKey, key, keyLength );
268  macInfo->userKeyLength = keyLength;
269  }
270 
271  /* Perform the start of the inner hash using the zero-padded key XOR'd
272  with the ipad value */
273  memset( hashBuffer, HMAC_IPAD, SHA256_BLOCK_SIZE );
274  memcpy( hashBuffer, macInfo->userKey,
275  macInfo->userKeyLength );
276  for( i = 0; i < macInfo->userKeyLength; i++ )
277  hashBuffer[ i ] ^= HMAC_IPAD;
278  sha2_hash( hashBuffer, SHA256_BLOCK_SIZE, shaInfo );
279  memset( hashBuffer, 0, SHA256_BLOCK_SIZE );
280  contextInfoPtr->flags |= CONTEXT_FLAG_HASH_INITED;
281 
282  /* Save a copy of the initial state in case it's needed later */
283  memcpy( &( ( MAC_STATE * ) macInfo->macInfo )->initialMacState, shaInfo,
284  sizeof( sha2_ctx ) );
285 
286  return( CRYPT_OK );
287  }
288 
289 /* Initialise algorithm parameters */
290 
292 static int initParams( INOUT CONTEXT_INFO *contextInfoPtr,
293  IN_ENUM( KEYPARAM ) const KEYPARAM_TYPE paramType,
294  IN_OPT const void *data,
295  IN_INT const int dataLength )
296  {
297  assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
298 
299  REQUIRES( contextInfoPtr->type == CONTEXT_MAC );
300  REQUIRES( paramType > KEYPARAM_NONE && paramType < KEYPARAM_LAST );
301 
302  /* SHA-2 has a variable-length output, selectable by setting the
303  blocksize attribute */
304  if( paramType == KEYPARAM_BLOCKSIZE )
305  {
306 #ifdef USE_SHA2_EXT
307  #ifdef CONFIG_SUITEB
308  static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
309  CRYPT_ALGO_SHA2, bitsToBytes( 384 ), "HMAC-SHA384", 11,
311  selfTest, getInfo, NULL, NULL, initKey, NULL, hash, hash
312  };
313  #else
314  static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
315  CRYPT_ALGO_SHA2, bitsToBytes( 512 ), "HMAC-SHA512", 11,
317  selfTest, getInfo, NULL, NULL, initKey, NULL, hash, hash
318  };
319  #endif /* CONFIG_SUITEB */
320 #endif /* USE_SHA2_EXT */
321 
322  /* The default SHA-2 variant is SHA-256, so an attempt to set this
323  size is a no-op */
324  if( dataLength == SHA256_DIGEST_SIZE )
325  return( CRYPT_OK );
326 
327 #ifdef USE_SHA2_EXT
328  /* Switch to the appropriate variant of SHA-2. Note that the
329  initParamsFunction pointer for this version is NULL rather than
330  pointing to this function, so once the output size has been set
331  it can't be changed again */
332  #ifdef CONFIG_SUITEB
333  if( dataLength != SHA384_DIGEST_SIZE )
334  return( CRYPT_ARGERROR_NUM1 );
335  contextInfoPtr->capabilityInfo = &capabilityInfo;
336  #else
337  if( dataLength != SHA512_DIGEST_SIZE )
338  return( CRYPT_ARGERROR_NUM1 );
339  contextInfoPtr->capabilityInfo = &capabilityInfo;
340  #endif /* CONFIG_SUITEB */
341 
342  return( CRYPT_OK );
343 #else
344  return( CRYPT_ARGERROR_NUM1 );
345 #endif /* USE_SHA2_EXT */
346  }
347 
348  /* Pass the call on down to the global parameter-handling function */
349  return( initGenericParams( contextInfoPtr, paramType, data,
350  dataLength ) );
351  }
352 
353 /****************************************************************************
354 * *
355 * Capability Access Routines *
356 * *
357 ****************************************************************************/
358 
359 static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
360  CRYPT_ALGO_HMAC_SHA2, bitsToBytes( 256 ), "HMAC-SHA2", 9,
362  selfTest, getInfo, NULL, initParams, initKey, NULL, hash, hash
363  };
364 
366  {
367  return( &capabilityInfo );
368  }
369 
370 #endif /* USE_SHA2 */