lnsocket

A minimal C library for connecting to the lightning network
git clone git://jb55.com/lnsocket
Log | Files | Refs | Submodules | README | LICENSE

hkdf.c (2648B)


      1 /* MIT (BSD) license */
      2 
      3 #include "hmac.h"
      4 #include "sha256.h"
      5 #include <assert.h>
      6 #include <string.h>
      7 
      8 void hkdf_sha256(void *okm, size_t okm_size,
      9 		 const void *s, size_t ssize,
     10 		 const void *k, size_t ksize,
     11 		 const void *info, size_t isize)
     12 {
     13 	struct hmac_sha256 prk, t;
     14 	struct hmac_sha256_ctx ctx;
     15 	unsigned char c;
     16 
     17 	assert(okm_size < 255 * sizeof(t));
     18 
     19 	/* RFC 5869:
     20 	 *
     21 	 * 2.2.  Step 1: Extract
     22 	 *
     23 	 *   HKDF-Extract(salt, IKM) -> PRK
     24 	 *
     25 	 *    Options:
     26 	 *       Hash     a hash function; HashLen denotes the length of the
     27 	 *                hash function output in octets
     28 	 *
     29 	 *    Inputs:
     30 	 *       salt     optional salt value (a non-secret random value);
     31 	 *                if not provided, it is set to a string of HashLen zeros.
     32 	 *       IKM      input keying material
     33 	 *
     34 	 *    Output:
     35 	 *       PRK      a pseudorandom key (of HashLen octets)
     36 	 *
     37 	 *    The output PRK is calculated as follows:
     38 	 *
     39 	 *    PRK = HMAC-Hash(salt, IKM)
     40 	 */
     41 	hmac_sha256(&prk, s, ssize, k, ksize);
     42 
     43 	/*
     44 	 * 2.3.  Step 2: Expand
     45 	 *
     46 	 *    HKDF-Expand(PRK, info, L) -> OKM
     47 	 *
     48 	 *    Options:
     49 	 *       Hash     a hash function; HashLen denotes the length of the
     50 	 *                hash function output in octets
     51 	 *
     52 	 *    Inputs:
     53 	 *       PRK      a pseudorandom key of at least HashLen octets
     54 	 *                (usually, the output from the extract step)
     55 	 *       info     optional context and application specific information
     56 	 *                (can be a zero-length string)
     57 	 *       L        length of output keying material in octets
     58 	 *                (<= 255*HashLen)
     59 	 *
     60 	 *    Output:
     61 	 *       OKM      output keying material (of L octets)
     62 	 *
     63 	 *    The output OKM is calculated as follows:
     64 	 *
     65 	 *    N = ceil(L/HashLen)
     66 	 *    T = T(1) | T(2) | T(3) | ... | T(N)
     67 	 *    OKM = first L octets of T
     68 	 *
     69 	 *    where:
     70 	 *    T(0) = empty string (zero length)
     71 	 *    T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
     72 	 *    T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
     73 	 *    T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
     74 	 *    ...
     75 	 *
     76 	 *    (where the constant concatenated to the end of each T(n) is a
     77 	 *    single octet.)
     78 	 */
     79 	c = 1;
     80 	hmac_sha256_init(&ctx, &prk, sizeof(prk));
     81 	hmac_sha256_update(&ctx, info, isize);
     82 	hmac_sha256_update(&ctx, &c, 1);
     83 	hmac_sha256_done(&ctx, &t);
     84 
     85 	while (okm_size > sizeof(t)) {
     86 		memcpy(okm, &t, sizeof(t));
     87 		okm = (char *)okm + sizeof(t);
     88 		okm_size -= sizeof(t);
     89 
     90 		c++;
     91 		hmac_sha256_init(&ctx, &prk, sizeof(prk));
     92 		hmac_sha256_update(&ctx, &t, sizeof(t));
     93 		hmac_sha256_update(&ctx, info, isize);
     94 		hmac_sha256_update(&ctx, &c, 1);
     95 		hmac_sha256_done(&ctx, &t);
     96 	}
     97 	memcpy(okm, &t, okm_size);
     98 }