1+ // Permission is hereby granted, free of charge, to any person obtaining a copy
2+ // of this software and associated documentation files (the "Software"), to deal
3+ // in the Software without restriction, including without limitation the rights
4+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5+ // copies of the Software, and to permit persons to whom the Software is
6+ // furnished to do so, subject to the following conditions:
7+
8+ // The above copyright notice and this permission notice shall be included in
9+ // all copies or substantial portions of the Software.
10+
11+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17+ // THE SOFTWARE.
18+
19+ #include "hkdf.h"
20+
21+ #include <bc-crypto-base/bc-crypto-base.h>
22+
23+ #include <assert.h>
24+ #include <string.h>
25+
26+ void hkdf_sha256 (uint8_t * okm , size_t okm_size ,
27+ const uint8_t * s , size_t ssize ,
28+ const uint8_t * k , size_t ksize ,
29+ const uint8_t * info , size_t isize )
30+ {
31+ uint8_t prk [SHA256_DIGEST_LENGTH ];
32+ uint8_t t [SHA256_DIGEST_LENGTH ];
33+ HMAC_SHA256_CTX ctx ;
34+ unsigned char c ;
35+
36+ assert (okm_size < 255 * sizeof (t ));
37+
38+ /* RFC 5869:
39+ *
40+ * 2.2. Step 1: Extract
41+ *
42+ * HKDF-Extract(salt, IKM) -> PRK
43+ *
44+ * Options:
45+ * Hash a hash function; HashLen denotes the length of the
46+ * hash function output in octets
47+ *
48+ * Inputs:
49+ * salt optional salt value (a non-secret random value);
50+ * if not provided, it is set to a string of HashLen zeros.
51+ * IKM input keying material
52+ *
53+ * Output:
54+ * PRK a pseudorandom key (of HashLen octets)
55+ *
56+ * The output PRK is calculated as follows:
57+ *
58+ * PRK = HMAC-Hash(salt, IKM)
59+ */
60+ if (s == NULL || ssize == 0 ) {
61+ uint8_t a [SHA256_DIGEST_LENGTH ];
62+ memset (a , 0 , SHA256_DIGEST_LENGTH );
63+ hmac_sha256 (a , SHA256_DIGEST_LENGTH , k , ksize , prk );
64+ } else {
65+ hmac_sha256 (s , ssize , k , ksize , prk );
66+ }
67+
68+ /*
69+ * 2.3. Step 2: Expand
70+ *
71+ * HKDF-Expand(PRK, info, L) -> OKM
72+ *
73+ * Options:
74+ * Hash a hash function; HashLen denotes the length of the
75+ * hash function output in octets
76+ *
77+ * Inputs:
78+ * PRK a pseudorandom key of at least HashLen octets
79+ * (usually, the output from the extract step)
80+ * info optional context and application specific information
81+ * (can be a zero-length string)
82+ * L length of output keying material in octets
83+ * (<= 255*HashLen)
84+ *
85+ * Output:
86+ * OKM output keying material (of L octets)
87+ *
88+ * The output OKM is calculated as follows:
89+ *
90+ * N = ceil(L/HashLen)
91+ * T = T(1) | T(2) | T(3) | ... | T(N)
92+ * OKM = first L octets of T
93+ *
94+ * where:
95+ * T(0) = empty string (zero length)
96+ * T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
97+ * T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
98+ * T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
99+ * ...
100+ *
101+ * (where the constant concatenated to the end of each T(n) is a
102+ * single octet.)
103+ */
104+ c = 1 ;
105+ hmac_sha256_Init (& ctx , prk , sizeof (prk ));
106+ hmac_sha256_Update (& ctx , info , isize );
107+ hmac_sha256_Update (& ctx , & c , 1 );
108+ hmac_sha256_Final (& ctx , t );
109+
110+ while (okm_size > sizeof (t )) {
111+ memcpy (okm , & t , sizeof (t ));
112+ okm = okm + sizeof (t );
113+ okm_size -= sizeof (t );
114+
115+ c ++ ;
116+ hmac_sha256_Init (& ctx , prk , sizeof (prk ));
117+ hmac_sha256_Update (& ctx , t , sizeof (t ));
118+ hmac_sha256_Update (& ctx , info , isize );
119+ hmac_sha256_Update (& ctx , & c , 1 );
120+ hmac_sha256_Final (& ctx , t );
121+ }
122+ memcpy (okm , & t , okm_size );
123+ }
0 commit comments