hmac_sha256.c (4847B)
1 /* MIT (BSD) license - see LICENSE file for details */ 2 #include "hmac_sha256.h" 3 #include <string.h> 4 5 #define IPAD 0x3636363636363636ULL 6 #define OPAD 0x5C5C5C5C5C5C5C5CULL 7 8 #define BLOCK_U64S (HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)) 9 10 static inline void xor_block(uint64_t block[BLOCK_U64S], uint64_t pad) 11 { 12 size_t i; 13 14 for (i = 0; i < BLOCK_U64S; i++) 15 block[i] ^= pad; 16 } 17 18 void hmac_sha256_init(struct hmac_sha256_ctx *ctx, 19 const void *k, size_t ksize) 20 { 21 struct sha256 hashed_key; 22 /* We use k_opad as k_ipad temporarily. */ 23 uint64_t *k_ipad = ctx->k_opad; 24 25 /* (keys longer than B bytes are first hashed using H) */ 26 if (ksize > HMAC_SHA256_BLOCKSIZE) { 27 sha256(&hashed_key, k, ksize); 28 k = &hashed_key; 29 ksize = sizeof(hashed_key); 30 } 31 32 /* From RFC2104: 33 * 34 * (1) append zeros to the end of K to create a B byte string 35 * (e.g., if K is of length 20 bytes and B=64, then K will be 36 * appended with 44 zero bytes 0x00) 37 */ 38 if (ksize != 0) 39 memcpy(k_ipad, k, ksize); 40 memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize); 41 42 /* 43 * (2) XOR (bitwise exclusive-OR) the B byte string computed 44 * in step (1) with ipad 45 */ 46 xor_block(k_ipad, IPAD); 47 48 /* 49 * We start (4) here, appending text later: 50 * 51 * (3) append the stream of data 'text' to the B byte string resulting 52 * from step (2) 53 * (4) apply H to the stream generated in step (3) 54 */ 55 sha256_init(&ctx->sha); 56 sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE); 57 58 /* 59 * (5) XOR (bitwise exclusive-OR) the B byte string computed in 60 * step (1) with opad 61 */ 62 xor_block(ctx->k_opad, IPAD^OPAD); 63 } 64 65 void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size) 66 { 67 /* This is the appending-text part of this: 68 * 69 * (3) append the stream of data 'text' to the B byte string resulting 70 * from step (2) 71 * (4) apply H to the stream generated in step (3) 72 */ 73 sha256_update(&ctx->sha, p, size); 74 } 75 76 void hmac_sha256_done(struct hmac_sha256_ctx *ctx, 77 struct hmac_sha256 *hmac) 78 { 79 /* (4) apply H to the stream generated in step (3) */ 80 sha256_done(&ctx->sha, &hmac->sha); 81 82 /* 83 * (6) append the H result from step (4) to the B byte string 84 * resulting from step (5) 85 * (7) apply H to the stream generated in step (6) and output 86 * the result 87 */ 88 sha256_init(&ctx->sha); 89 sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad)); 90 sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha)); 91 sha256_done(&ctx->sha, &hmac->sha); 92 } 93 94 #if 1 95 void hmac_sha256(struct hmac_sha256 *hmac, 96 const void *k, size_t ksize, 97 const void *d, size_t dsize) 98 { 99 struct hmac_sha256_ctx ctx; 100 101 hmac_sha256_init(&ctx, k, ksize); 102 hmac_sha256_update(&ctx, d, dsize); 103 hmac_sha256_done(&ctx, hmac); 104 } 105 #else 106 /* Direct mapping from MD5 example in RFC2104 */ 107 void hmac_sha256(struct hmac_sha256 *hmac, 108 const void *key, size_t key_len, 109 const void *text, size_t text_len) 110 { 111 struct sha256_ctx context; 112 unsigned char k_ipad[65]; /* inner padding - 113 * key XORd with ipad 114 */ 115 unsigned char k_opad[65]; /* outer padding - 116 * key XORd with opad 117 *//* start out by storing key in pads */ 118 unsigned char tk[32]; 119 int i; 120 121 /* if key is longer than 64 bytes reset it to key=MD5(key) */ 122 if (key_len > 64) { 123 124 struct sha256_ctx tctx; 125 126 sha256_init(&tctx); 127 sha256_update(&tctx, key, key_len); 128 sha256_done(&tctx, tk); 129 130 key = tk; 131 key_len = 32; 132 } 133 bzero( k_ipad, sizeof k_ipad); 134 bzero( k_opad, sizeof k_opad); 135 bcopy( key, k_ipad, key_len); 136 bcopy( key, k_opad, key_len); 137 138 /* XOR key with ipad and opad values */ 139 for (i=0; i<64; i++) { 140 k_ipad[i] ^= 0x36; 141 k_opad[i] ^= 0x5c; 142 } 143 /* 144 * perform inner MD5 145 */ 146 sha256_init(&context); /* init context for 1st 147 * pass */ 148 sha256_update(&context, k_ipad, 64); /* start with inner pad */ 149 sha256_update(&context, text, text_len); /* then text of datagram */ 150 sha256_done(&context, &hmac->sha); /* finish up 1st pass */ 151 /* 152 * perform outer MD5 153 */ 154 sha256_init(&context); /* init context for 2nd 155 * pass */ 156 sha256_update(&context, k_opad, 64); /* start with outer pad */ 157 sha256_update(&context, &hmac->sha, 32); /* then results of 1st 158 * hash */ 159 sha256_done(&context, &hmac->sha); /* finish up 2nd pass */ 160 } 161 #endif