nostril

A C cli tool for creating nostr events
git clone git://jb55.com/nostril
Log | Files | Refs | Submodules | README | LICENSE

hkdf_sha256.c (2881B)


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