1 /* 2 * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #include "inner.h" 26 27 const unsigned char br_hkdf_no_salt = 0; 28 29 /* see bearssl_kdf.h */ 30 void 31 br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable, 32 const void *salt, size_t salt_len) 33 { 34 br_hmac_key_context kc; 35 unsigned char tmp[64]; 36 37 if (salt == BR_HKDF_NO_SALT) { 38 salt = tmp; 39 salt_len = br_digest_size(digest_vtable); 40 memset(tmp, 0, salt_len); 41 } 42 br_hmac_key_init(&kc, digest_vtable, salt, salt_len); 43 br_hmac_init(&hc->u.hmac_ctx, &kc, 0); 44 hc->dig_len = br_hmac_size(&hc->u.hmac_ctx); 45 } 46 47 /* see bearssl_kdf.h */ 48 void 49 br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len) 50 { 51 br_hmac_update(&hc->u.hmac_ctx, ikm, ikm_len); 52 } 53 54 /* see bearssl_kdf.h */ 55 void 56 br_hkdf_flip(br_hkdf_context *hc) 57 { 58 unsigned char tmp[64]; 59 60 br_hmac_out(&hc->u.hmac_ctx, tmp); 61 br_hmac_key_init(&hc->u.prk_ctx, 62 br_hmac_get_digest(&hc->u.hmac_ctx), tmp, hc->dig_len); 63 hc->ptr = hc->dig_len; 64 hc->chunk_num = 0; 65 } 66 67 /* see bearssl_kdf.h */ 68 size_t 69 br_hkdf_produce(br_hkdf_context *hc, 70 const void *info, size_t info_len, void *out, size_t out_len) 71 { 72 size_t tlen; 73 74 tlen = 0; 75 while (out_len > 0) { 76 size_t clen; 77 78 if (hc->ptr == hc->dig_len) { 79 br_hmac_context hmac_ctx; 80 unsigned char x; 81 82 hc->chunk_num ++; 83 if (hc->chunk_num == 256) { 84 return tlen; 85 } 86 x = hc->chunk_num; 87 br_hmac_init(&hmac_ctx, &hc->u.prk_ctx, 0); 88 if (x != 1) { 89 br_hmac_update(&hmac_ctx, hc->buf, hc->dig_len); 90 } 91 br_hmac_update(&hmac_ctx, info, info_len); 92 br_hmac_update(&hmac_ctx, &x, 1); 93 br_hmac_out(&hmac_ctx, hc->buf); 94 hc->ptr = 0; 95 } 96 clen = hc->dig_len - hc->ptr; 97 if (clen > out_len) { 98 clen = out_len; 99 } 100 memcpy(out, hc->buf + hc->ptr, clen); 101 out = (unsigned char *)out + clen; 102 out_len -= clen; 103 hc->ptr += clen; 104 tlen += clen; 105 } 106 return tlen; 107 } 108