hmac.c (8222B)
1 /* Copyright Rusty Russell (Blockstream) 2015. 2 3 Permission is hereby granted, free of charge, to any person obtaining a copy 4 of this software and associated documentation files (the "Software"), to deal 5 in the Software without restriction, including without limitation the rights 6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 copies of the Software, and to permit persons to whom the Software is 8 furnished to do so, subject to the following conditions: 9 10 The above copyright notice and this permission notice shall be included in 11 all copies or substantial portions of the Software. 12 13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 THE SOFTWARE. 20 */ 21 22 #include <string.h> 23 #include "hmac.h" 24 25 #define IPAD 0x3636363636363636ULL 26 #define OPAD 0x5C5C5C5C5C5C5C5CULL 27 28 #define BLOCK_256_U64S (HMAC_SHA256_BLOCKSIZE / sizeof(uint64_t)) 29 #define BLOCK_512_U64S (HMAC_SHA512_BLOCKSIZE / sizeof(uint64_t)) 30 31 static inline void xor_block_256(uint64_t block[BLOCK_256_U64S], uint64_t pad) 32 { 33 size_t i; 34 35 for (i = 0; i < BLOCK_256_U64S; i++) 36 block[i] ^= pad; 37 } 38 39 40 static inline void xor_block_512(uint64_t block[BLOCK_512_U64S], uint64_t pad) 41 { 42 size_t i; 43 44 for (i = 0; i < BLOCK_512_U64S; i++) 45 block[i] ^= pad; 46 } 47 48 void hmac_sha256_init(struct hmac_sha256_ctx *ctx, 49 const void *k, size_t ksize) 50 { 51 struct sha256 hashed_key; 52 /* We use k_opad as k_ipad temporarily. */ 53 uint64_t *k_ipad = ctx->k_opad; 54 55 /* (keys longer than B bytes are first hashed using H) */ 56 if (ksize > HMAC_SHA256_BLOCKSIZE) { 57 sha256(&hashed_key, k, ksize); 58 k = &hashed_key; 59 ksize = sizeof(hashed_key); 60 } 61 62 /* From RFC2104: 63 * 64 * (1) append zeros to the end of K to create a B byte string 65 * (e.g., if K is of length 20 bytes and B=64, then K will be 66 * appended with 44 zero bytes 0x00) 67 */ 68 memcpy(k_ipad, k, ksize); 69 memset((char *)k_ipad + ksize, 0, HMAC_SHA256_BLOCKSIZE - ksize); 70 71 /* 72 * (2) XOR (bitwise exclusive-OR) the B byte string computed 73 * in step (1) with ipad 74 */ 75 xor_block_256(k_ipad, IPAD); 76 77 /* 78 * We start (4) here, appending text later: 79 * 80 * (3) append the stream of data 'text' to the B byte string resulting 81 * from step (2) 82 * (4) apply H to the stream generated in step (3) 83 */ 84 sha256_init(&ctx->sha); 85 sha256_update(&ctx->sha, k_ipad, HMAC_SHA256_BLOCKSIZE); 86 87 /* 88 * (5) XOR (bitwise exclusive-OR) the B byte string computed in 89 * step (1) with opad 90 */ 91 xor_block_256(ctx->k_opad, IPAD^OPAD); 92 } 93 94 95 void hmac_sha512_init(struct hmac_sha512_ctx *ctx, 96 const void *k, size_t ksize) 97 { 98 struct sha512 hashed_key; 99 /* We use k_opad as k_ipad temporarily. */ 100 uint64_t *k_ipad = ctx->k_opad; 101 102 /* (keys longer than B bytes are first hashed using H) */ 103 if (ksize > HMAC_SHA512_BLOCKSIZE) { 104 sha512(&hashed_key, k, ksize); 105 k = &hashed_key; 106 ksize = sizeof(hashed_key); 107 } 108 109 /* From RFC2104: 110 * 111 * (1) append zeros to the end of K to create a B byte string 112 * (e.g., if K is of length 20 bytes and B=64, then K will be 113 * appended with 44 zero bytes 0x00) 114 */ 115 memcpy(k_ipad, k, ksize); 116 memset((char *)k_ipad + ksize, 0, HMAC_SHA512_BLOCKSIZE - ksize); 117 118 /* 119 * (2) XOR (bitwise exclusive-OR) the B byte string computed 120 * in step (1) with ipad 121 */ 122 xor_block_512(k_ipad, IPAD); 123 124 /* 125 * We start (4) here, appending text later: 126 * 127 * (3) append the stream of data 'text' to the B byte string resulting 128 * from step (2) 129 * (4) apply H to the stream generated in step (3) 130 */ 131 sha512_init(&ctx->sha); 132 sha512_update(&ctx->sha, k_ipad, HMAC_SHA512_BLOCKSIZE); 133 134 /* 135 * (5) XOR (bitwise exclusive-OR) the B byte string computed in 136 * step (1) with opad 137 */ 138 xor_block_512(ctx->k_opad, IPAD^OPAD); 139 } 140 141 142 void hmac_sha256_update(struct hmac_sha256_ctx *ctx, const void *p, size_t size) 143 { 144 /* This is the appending-text part of this: 145 * 146 * (3) append the stream of data 'text' to the B byte string resulting 147 * from step (2) 148 * (4) apply H to the stream generated in step (3) 149 */ 150 sha256_update(&ctx->sha, p, size); 151 } 152 153 154 void hmac_sha512_update(struct hmac_sha512_ctx *ctx, const void *p, size_t size) 155 { 156 sha512_update(&ctx->sha, p, size); 157 } 158 159 160 void hmac_sha256_done(struct hmac_sha256_ctx *ctx, 161 struct hmac_sha256 *hmac) 162 { 163 /* (4) apply H to the stream generated in step (3) */ 164 sha256_done(&ctx->sha, &hmac->sha); 165 166 /* 167 * (6) append the H result from step (4) to the B byte string 168 * resulting from step (5) 169 * (7) apply H to the stream generated in step (6) and output 170 * the result 171 */ 172 sha256_init(&ctx->sha); 173 sha256_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad)); 174 sha256_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha)); 175 sha256_done(&ctx->sha, &hmac->sha); 176 } 177 178 179 void hmac_sha512_done(struct hmac_sha512_ctx *ctx, 180 struct hmac_sha512 *hmac) 181 { 182 /* (4) apply H to the stream generated in step (3) */ 183 sha512_done(&ctx->sha, &hmac->sha); 184 185 /* 186 * (6) append the H result from step (4) to the B byte string 187 * resulting from step (5) 188 * (7) apply H to the stream generated in step (6) and output 189 * the result 190 */ 191 sha512_init(&ctx->sha); 192 sha512_update(&ctx->sha, ctx->k_opad, sizeof(ctx->k_opad)); 193 sha512_update(&ctx->sha, &hmac->sha, sizeof(hmac->sha)); 194 sha512_done(&ctx->sha, &hmac->sha); 195 } 196 197 #if 1 198 void hmac_sha256(struct hmac_sha256 *hmac, 199 const void *k, size_t ksize, 200 const void *d, size_t dsize) 201 { 202 struct hmac_sha256_ctx ctx; 203 204 hmac_sha256_init(&ctx, k, ksize); 205 hmac_sha256_update(&ctx, d, dsize); 206 hmac_sha256_done(&ctx, hmac); 207 } 208 209 210 void hmac_sha512(struct hmac_sha512 *hmac, 211 const void *k, size_t ksize, 212 const void *d, size_t dsize) 213 { 214 struct hmac_sha512_ctx ctx; 215 216 hmac_sha512_init(&ctx, k, ksize); 217 hmac_sha512_update(&ctx, d, dsize); 218 hmac_sha512_done(&ctx, hmac); 219 } 220 221 222 #else 223 /* Direct mapping from MD5 example in RFC2104 */ 224 void hmac_sha256(struct hmac_sha256 *hmac, 225 const void *key, size_t key_len, 226 const void *text, size_t text_len) 227 { 228 struct sha256_ctx context; 229 unsigned char k_ipad[65]; /* inner padding - 230 * key XORd with ipad 231 */ 232 unsigned char k_opad[65]; /* outer padding - 233 * key XORd with opad 234 *//* start out by storing key in pads */ 235 unsigned char tk[32]; 236 int i; 237 238 /* if key is longer than 64 bytes reset it to key=MD5(key) */ 239 if (key_len > 64) { 240 241 struct sha256_ctx tctx; 242 243 sha256_init(&tctx); 244 sha256_update(&tctx, key, key_len); 245 sha256_done(&tctx, tk); 246 247 key = tk; 248 key_len = 32; 249 } 250 bzero( k_ipad, sizeof k_ipad); 251 bzero( k_opad, sizeof k_opad); 252 bcopy( key, k_ipad, key_len); 253 bcopy( key, k_opad, key_len); 254 255 /* XOR key with ipad and opad values */ 256 for (i=0; i<64; i++) { 257 k_ipad[i] ^= 0x36; 258 k_opad[i] ^= 0x5c; 259 } 260 /* 261 * perform inner MD5 262 */ 263 sha256_init(&context); /* init context for 1st 264 * pass */ 265 sha256_update(&context, k_ipad, 64); /* start with inner pad */ 266 sha256_update(&context, text, text_len); /* then text of datagram */ 267 sha256_done(&context, &hmac->sha); /* finish up 1st pass */ 268 /* 269 * perform outer MD5 270 */ 271 sha256_init(&context); /* init context for 2nd 272 * pass */ 273 sha256_update(&context, k_opad, 64); /* start with outer pad */ 274 sha256_update(&context, &hmac->sha, 32); /* then results of 1st 275 * hash */ 276 sha256_done(&context, &hmac->sha); /* finish up 2nd pass */ 277 } 278 #endif