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