1 /* Submited by Dobes Vandermeer (dobes@smartt.com) */
6 (1) append zeros to the end of K to create a B byte string
7 (e.g., if K is of length 20 bytes and B=64, then K will be
8 appended with 44 zero bytes 0x00)
9 (2) XOR (bitwise exclusive-OR) the B byte string computed in step
10 (1) with ipad (ipad = the byte 0x36 repeated B times)
11 (3) append the stream of data 'text' to the B byte string resulting
13 (4) apply H to the stream generated in step (3)
14 (5) XOR (bitwise exclusive-OR) the B byte string computed in
15 step (1) with opad (opad = the byte 0x5C repeated B times.)
16 (6) append the H result from step (4) to the B byte string
17 resulting from step (5)
18 (7) apply H to the stream generated in step (6) and output
24 #define HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
26 int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
28 unsigned char buf[MAXBLOCKSIZE];
29 unsigned long hashsize;
33 _ARGCHK(hmac != NULL);
36 if ((err = hash_is_valid(hash)) != CRYPT_OK) {
41 return CRYPT_INVALID_KEYSIZE;
46 // (1) make sure we have a large enough key
47 hmac->hashsize = hashsize = hash_descriptor[hash].hashsize;
48 if(keylen > HMAC_BLOCKSIZE) {
49 z = (unsigned long)sizeof(hmac->key);
50 if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) {
53 if(hashsize < HMAC_BLOCKSIZE) {
54 zeromem((hmac->key) + hashsize, (size_t)(HMAC_BLOCKSIZE - hashsize));
57 memcpy(hmac->key, key, (size_t)keylen);
58 if(keylen < HMAC_BLOCKSIZE) {
59 zeromem((hmac->key) + keylen, (size_t)(HMAC_BLOCKSIZE - keylen));
63 // Create the initial vector for step (3)
64 for(i=0; i < keylen; i++) {
65 buf[i] = hmac->key[i] ^ 0x36;
68 for( ; i < HMAC_BLOCKSIZE; i++) {
72 // Pre-pend that to the hash data
73 hash_descriptor[hash].init(&hmac->md);
74 hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE);
79 int hmac_process(hmac_state *hmac, const unsigned char *buf, unsigned long len)
82 _ARGCHK(hmac != NULL);
84 if ((err = hash_is_valid(hmac->hash)) != CRYPT_OK) {
87 hash_descriptor[hmac->hash].process(&hmac->md, buf, len);
91 int hmac_done(hmac_state *hmac, unsigned char *hashOut)
93 unsigned char buf[MAXBLOCKSIZE];
94 unsigned char isha[MAXBLOCKSIZE];
95 unsigned long hashsize, i;
98 _ARGCHK(hmac != NULL);
99 _ARGCHK(hashOut != NULL);
102 if((err = hash_is_valid(hash)) != CRYPT_OK) {
106 // Get the hash of the first HMAC vector plus the data
107 hash_descriptor[hash].done(&hmac->md, isha);
109 // Create the second HMAC vector vector for step (3)
110 hashsize = hash_descriptor[hash].hashsize;
111 for(i=0; i < HMAC_BLOCKSIZE; i++) {
112 buf[i] = hmac->key[i] ^ 0x5C;
115 // Now calculate the "outer" hash for step (5), (6), and (7)
116 hash_descriptor[hash].init(&hmac->md);
117 hash_descriptor[hash].process(&hmac->md, buf, HMAC_BLOCKSIZE);
118 hash_descriptor[hash].process(&hmac->md, isha, hashsize);
119 hash_descriptor[hash].done(&hmac->md, hashOut);
122 zeromem(hmac->key, sizeof(hmac->key));
127 int hmac_memory(int hash, const unsigned char *key, unsigned long keylen,
128 const unsigned char *data, unsigned long len,
129 unsigned char *dst, unsigned long *dstlen)
134 _ARGCHK(key != NULL);
135 _ARGCHK(data != NULL);
136 _ARGCHK(dst != NULL);
138 if((err = hash_is_valid(hash)) != CRYPT_OK) {
141 if (hash_descriptor[hash].hashsize > *dstlen) {
142 return CRYPT_BUFFER_OVERFLOW;
144 *dstlen = hash_descriptor[hash].hashsize;
146 if ((err = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) {
150 if ((err = hmac_process(&hmac, data, len)) != CRYPT_OK) {
154 if ((err = hmac_done(&hmac, dst)) != CRYPT_OK) {
160 /* hmac_file added by Tom St Denis */
161 int hmac_file(int hash, const char *fname, const unsigned char *key,
162 unsigned long keylen,
163 unsigned char *dst, unsigned long *dstlen)
170 unsigned char buf[512];
174 _ARGCHK(fname != NULL);
175 _ARGCHK(key != NULL);
176 _ARGCHK(dst != NULL);
178 if((err = hash_is_valid(hash)) != CRYPT_OK) {
181 if (hash_descriptor[hash].hashsize > *dstlen) {
182 return CRYPT_BUFFER_OVERFLOW;
184 *dstlen = hash_descriptor[hash].hashsize;
186 if ((err = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) {
190 in = fopen(fname, "rb");
192 return CRYPT_INVALID_ARG;
195 /* process the file contents */
197 x = fread(buf, 1, sizeof(buf), in);
198 if ((err = hmac_process(&hmac, buf, (unsigned long)x)) != CRYPT_OK) {
202 } while (x == sizeof(buf));
206 if ((err = hmac_done(&hmac, dst)) != CRYPT_OK) {
212 zeromem(buf, sizeof(buf));
222 Network Working Group P. Cheng
223 Request for Comments: 2202 IBM
224 Category: Informational R. Glenn
228 Test Cases for HMAC-MD5 and HMAC-SHA-1
237 unsigned char digest[MAXBLOCKSIZE];
240 struct hmac_test_case {
243 unsigned char key[128];
244 unsigned long keylen;
245 unsigned char data[128];
246 unsigned long datalen;
247 unsigned char digest[MAXBLOCKSIZE];
250 3. Test Cases for HMAC-SHA-1
253 key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
256 digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
257 digest-96 = 0x4c1a03424b55e07fe7f27be1
260 {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
261 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
262 0x0c, 0x0c, 0x0c, 0x0c}, 20,
263 "Test With Truncation", 20,
264 {0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2,
265 0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04} },
269 key = 0xaa repeated 80 times
271 data = "Test Using Larger Than Block-Size Key - Hash Key First"
273 digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112
276 {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
277 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
278 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
279 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
280 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
281 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
282 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
283 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
284 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
285 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
286 "Test Using Larger Than Block-Size Key - Hash Key First", 54,
287 {0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e,
288 0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55,
289 0xed, 0x40, 0x21, 0x12} },
293 key = 0xaa repeated 80 times
295 data = "Test Using Larger Than Block-Size Key and Larger
296 Than One Block-Size Data"
298 digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91
301 {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
302 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
303 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
304 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
305 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
306 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
307 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
308 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
309 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
310 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
311 "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73,
312 {0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d,
313 0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91} },
316 2. Test Cases for HMAC-MD5
326 digest = 0x92 94 72 7a
332 {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
333 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 16,
335 {0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
336 0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d} },
341 data = "what do ya want for nothing?"
343 digest = 0x750c783e6ab0b503eaa86e310a5db738
347 "what do ya want for nothing?", 28,
348 {0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
349 0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38} },
353 key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
355 data = 0xdd repeated 50 times
357 digest = 0x56be34521d144c88dbb8c733f0e8b3f6
360 {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
361 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 16,
362 {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
363 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
364 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
365 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
366 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}, 50,
367 {0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
368 0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6} },
372 key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
374 data = 0xcd repeated 50 times
376 digest = 0x697eaf0aca3a3aea3a75164746ffaa79
379 {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
380 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
381 0x15, 0x16, 0x17, 0x18, 0x19}, 25,
382 {0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
383 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
384 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
385 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
386 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd}, 50,
387 {0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea,
388 0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79} },
394 key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
396 data = "Test With Truncation"
398 digest = 0x56461ef2342edc00f9bab995690efd4c
399 digest-96 0x56461ef2342edc00f9bab995
402 {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
403 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}, 16,
404 "Test With Truncation", 20,
405 {0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00,
406 0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c} },
411 key = 0xaa repeated 80 times
413 data = "Test Using Larger Than Block-Size Key - Hash
416 digest = 0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd
419 {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
420 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
421 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
422 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
423 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
425 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
426 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
427 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
428 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
429 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
430 "Test Using Larger Than Block-Size Key - Hash Key First", 54,
431 {0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f,
432 0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd} },
437 key = 0xaa repeated 80 times
439 data = "Test Using Larger Than Block-Size Key and Larger
440 Than One Block-Size Data"
442 digest = 0x6f630fad67cda0ee1fb1f562db3aa53e
445 {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
446 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
447 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
448 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
449 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
450 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
451 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
452 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
453 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
454 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, 80,
455 "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", 73,
456 {0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee,
457 0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e} }
460 unsigned long outlen;
462 int tested=0,failed=0;
463 for(i=0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
464 int hash = find_hash(cases[i].algo);
465 if (hash == -1) continue;
467 outlen = sizeof(digest);
468 if((err = hmac_memory(hash, cases[i].key, cases[i].keylen, cases[i].data, cases[i].datalen, digest, &outlen)) != CRYPT_OK) {
470 printf("HMAC-%s test #%d\n", cases[i].algo, cases[i].num);
475 if(memcmp(digest, cases[i].digest, (size_t)hash_descriptor[hash].hashsize) != 0) {
478 printf("\nHMAC-%s test #%d:\n", cases[i].algo, cases[i].num);
479 printf( "Result: 0x");
480 for(j=0; j < hash_descriptor[hash].hashsize; j++) {
481 printf("%2x ", digest[j]);
483 printf("\nCorrect: 0x");
484 for(j=0; j < hash_descriptor[hash].hashsize; j++) {
485 printf("%2x ", cases[i].digest[j]);
490 //return CRYPT_ERROR;
492 /* printf("HMAC-%s test #%d: Passed\n", cases[i].algo, cases[i].num); */
497 return CRYPT_FAIL_TESTVECTOR;
498 } else if (tested == 0) {