/ src / kdf / hkdf.c
hkdf.c
  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  }