1 /*        $NetBSD: hkdf_hmac_sha256.c,v 1.1 2022/08/12 10:49:17 riastradh Exp $ */
2 
3 /*-
4  * Copyright (c) 2022 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: hkdf_hmac_sha256.c,v 1.1 2022/08/12 10:49:17 riastradh Exp $");
31 
32 #include <sys/sha2.h>
33 
34 #include <stdint.h>
35 #include <string.h>
36 
37 #include "hkdf_hmac_sha256.h"
38 
39 /* RFC 2104: HMAC */
40 
41 struct hmacsha256 {
42           SHA256_CTX sha256;
43           uint8_t key[SHA256_BLOCK_LENGTH];
44 };
45 
46 static void
hmacsha256_init(struct hmacsha256 * H,const void * key,size_t keylen)47 hmacsha256_init(struct hmacsha256 *H, const void *key, size_t keylen)
48 {
49           uint8_t hkey[SHA256_DIGEST_LENGTH];
50           uint8_t ipad[SHA256_BLOCK_LENGTH];
51           unsigned i;
52 
53           if (keylen > SHA256_BLOCK_LENGTH) { /* XXX should not happen here */
54                     SHA256_Init(&H->sha256);
55                     SHA256_Update(&H->sha256, key, keylen);
56                     SHA256_Final(hkey, &H->sha256);
57                     key = hkey;
58                     keylen = sizeof(hkey);
59           }
60 
61           memset(H->key, 0, sizeof(H->key));
62           memcpy(H->key, key, keylen);
63 
64           for (i = 0; i < SHA256_BLOCK_LENGTH; i++)
65                     ipad[i] = 0x36 ^ H->key[i];
66 
67           SHA256_Init(&H->sha256);
68           SHA256_Update(&H->sha256, ipad, SHA256_BLOCK_LENGTH);
69 
70           explicit_memset(hkey, 0, sizeof(hkey));
71           explicit_memset(ipad, 0, sizeof(ipad));
72 }
73 
74 static void
hmacsha256_update(struct hmacsha256 * H,const void * buf,size_t buflen)75 hmacsha256_update(struct hmacsha256 *H, const void *buf, size_t buflen)
76 {
77 
78           SHA256_Update(&H->sha256, buf, buflen);
79 }
80 
81 static void
hmacsha256_final(uint8_t h[static SHA256_DIGEST_LENGTH],struct hmacsha256 * H)82 hmacsha256_final(uint8_t h[static SHA256_DIGEST_LENGTH],
83     struct hmacsha256 *H)
84 {
85           uint8_t opad[SHA256_BLOCK_LENGTH];
86           unsigned i;
87 
88           for (i = 0; i < SHA256_BLOCK_LENGTH; i++)
89                     opad[i] = 0x5c ^ H->key[i];
90 
91           SHA256_Final(h, &H->sha256);
92           SHA256_Init(&H->sha256);
93           SHA256_Update(&H->sha256, opad, SHA256_BLOCK_LENGTH);
94           SHA256_Update(&H->sha256, h, SHA256_DIGEST_LENGTH);
95           SHA256_Final(h, &H->sha256);
96 
97           explicit_memset(opad, 0, sizeof(opad));
98           explicit_memset(H, 0, sizeof(*H));
99 }
100 
101 /* RFC 5869 HKDF, Sec. 2.3 HKDF-Expand */
102 
103 int
hkdf_hmac_sha256(void * okm,size_t L,const void * prk,size_t prklen,const void * info,size_t infolen)104 hkdf_hmac_sha256(void *okm, size_t L,
105     const void *prk, size_t prklen,
106     const void *info, size_t infolen)
107 {
108           struct hmacsha256 hmacsha256;
109           size_t n, tlen;
110           uint8_t T[SHA256_DIGEST_LENGTH], *p = okm;
111           uint8_t i;
112 
113           if (L > 255*SHA256_DIGEST_LENGTH)
114                     return -1;
115           if (L == 0)
116                     return 0;
117 
118           for (tlen = 0, i = 1; L > 0; i++, tlen = SHA256_DIGEST_LENGTH) {
119                     hmacsha256_init(&hmacsha256, prk, prklen);
120                     hmacsha256_update(&hmacsha256, T, tlen);
121                     hmacsha256_update(&hmacsha256, info, infolen);
122                     hmacsha256_update(&hmacsha256, &i, 1);
123                     hmacsha256_final(T, &hmacsha256);
124                     n = (L < SHA256_DIGEST_LENGTH ? L : SHA256_DIGEST_LENGTH);
125                     memcpy(p, T, n);
126                     p += n;
127                     L -= n;
128           }
129 
130           explicit_memset(T, 0, sizeof(T));
131           return 0;
132 }
133 
134 #if 0
135 #include <stdarg.h>
136 #include <stdio.h>
137 
138 static void
139 hexdump(const void *buf, size_t len, const char *fmt, ...)
140 {
141           va_list va;
142           const uint8_t *p = buf;
143           size_t i;
144 
145           printf("### ");
146           va_start(va, fmt);
147           vprintf(fmt, va);
148           va_end(va);
149           printf(" (%zu bytes):\n", len);
150           for (i = 0; i < len; i++) {
151                     if (i % 8 == 0)
152                               printf(" ");
153                     printf(" %02x", p[i]);
154                     if (i % 16 == 15)
155                               printf("\n");
156           }
157           if (i % 16)
158                     printf("\n");
159 }
160 #endif
161 
162 int
hkdf_hmac_sha256_selftest(void)163 hkdf_hmac_sha256_selftest(void)
164 {
165           const struct {
166                     size_t L;
167                     const uint8_t *okm;
168                     size_t prklen;
169                     const uint8_t *prk;
170                     size_t infolen;
171                     const uint8_t *info;
172           } C[] = {
173                     [0] = {             /* A.1 Test Case 1 with SHA-256 */
174                               .L = 42,
175                               .okm = (const uint8_t[]) {
176                                         0x3c,0xb2,0x5f,0x25, 0xfa,0xac,0xd5,0x7a,
177                                         0x90,0x43,0x4f,0x64, 0xd0,0x36,0x2f,0x2a,
178                                         0x2d,0x2d,0x0a,0x90, 0xcf,0x1a,0x5a,0x4c,
179                                         0x5d,0xb0,0x2d,0x56, 0xec,0xc4,0xc5,0xbf,
180                                         0x34,0x00,0x72,0x08, 0xd5,0xb8,0x87,0x18,
181                                         0x58,0x65,
182                               },
183                               .prklen = 32,
184                               .prk = (const uint8_t[]) {
185                                         0x07,0x77,0x09,0x36, 0x2c,0x2e,0x32,0xdf,
186                                         0x0d,0xdc,0x3f,0x0d, 0xc4,0x7b,0xba,0x63,
187                                         0x90,0xb6,0xc7,0x3b, 0xb5,0x0f,0x9c,0x31,
188                                         0x22,0xec,0x84,0x4a, 0xd7,0xc2,0xb3,0xe5,
189                               },
190                               .infolen = 10,
191                               .info = (const uint8_t[]) {
192                                         0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
193                                         0xf8,0xf9,
194                               },
195                     },
196                     [1] = {             /* A.2 Test Case 2 with SHA-256, longer I/O */
197                               .L = 82,
198                               .okm = (const uint8_t[]) {
199                                         0xb1,0x1e,0x39,0x8d, 0xc8,0x03,0x27,0xa1,
200                                         0xc8,0xe7,0xf7,0x8c, 0x59,0x6a,0x49,0x34,
201                                         0x4f,0x01,0x2e,0xda, 0x2d,0x4e,0xfa,0xd8,
202                                         0xa0,0x50,0xcc,0x4c, 0x19,0xaf,0xa9,0x7c,
203                                         0x59,0x04,0x5a,0x99, 0xca,0xc7,0x82,0x72,
204                                         0x71,0xcb,0x41,0xc6, 0x5e,0x59,0x0e,0x09,
205                                         0xda,0x32,0x75,0x60, 0x0c,0x2f,0x09,0xb8,
206                                         0x36,0x77,0x93,0xa9, 0xac,0xa3,0xdb,0x71,
207                                         0xcc,0x30,0xc5,0x81, 0x79,0xec,0x3e,0x87,
208                                         0xc1,0x4c,0x01,0xd5, 0xc1,0xf3,0x43,0x4f,
209                                         0x1d,0x87,
210                               },
211                               .prklen = 32,
212                               .prk = (const uint8_t[]) {
213                                         0x06,0xa6,0xb8,0x8c, 0x58,0x53,0x36,0x1a,
214                                         0x06,0x10,0x4c,0x9c, 0xeb,0x35,0xb4,0x5c,
215                                         0xef,0x76,0x00,0x14, 0x90,0x46,0x71,0x01,
216                                         0x4a,0x19,0x3f,0x40, 0xc1,0x5f,0xc2,0x44,
217                               },
218                               .infolen = 80,
219                               .info = (const uint8_t[]) {
220                                         0xb0,0xb1,0xb2,0xb3, 0xb4,0xb5,0xb6,0xb7,
221                                         0xb8,0xb9,0xba,0xbb, 0xbc,0xbd,0xbe,0xbf,
222                                         0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7,
223                                         0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf,
224                                         0xd0,0xd1,0xd2,0xd3, 0xd4,0xd5,0xd6,0xd7,
225                                         0xd8,0xd9,0xda,0xdb, 0xdc,0xdd,0xde,0xdf,
226                                         0xe0,0xe1,0xe2,0xe3, 0xe4,0xe5,0xe6,0xe7,
227                                         0xe8,0xe9,0xea,0xeb, 0xec,0xed,0xee,0xef,
228                                         0xf0,0xf1,0xf2,0xf3, 0xf4,0xf5,0xf6,0xf7,
229                                         0xf8,0xf9,0xfa,0xfb, 0xfc,0xfd,0xfe,0xff,
230                               },
231                     },
232                     [2] = {             /* A.3 Test Case 3 with SHA-256, empty info */
233                               .L = 42,
234                               .okm = (const uint8_t[]) {
235                                         0x8d,0xa4,0xe7,0x75, 0xa5,0x63,0xc1,0x8f,
236                                         0x71,0x5f,0x80,0x2a, 0x06,0x3c,0x5a,0x31,
237                                         0xb8,0xa1,0x1f,0x5c, 0x5e,0xe1,0x87,0x9e,
238                                         0xc3,0x45,0x4e,0x5f, 0x3c,0x73,0x8d,0x2d,
239                                         0x9d,0x20,0x13,0x95, 0xfa,0xa4,0xb6,0x1a,
240                                         0x96,0xc8,
241                               },
242                               .prklen = 32,
243                               .prk = (const uint8_t[]) {
244                                         0x19,0xef,0x24,0xa3, 0x2c,0x71,0x7b,0x16,
245                                         0x7f,0x33,0xa9,0x1d, 0x6f,0x64,0x8b,0xdf,
246                                         0x96,0x59,0x67,0x76, 0xaf,0xdb,0x63,0x77,
247                                         0xac,0x43,0x4c,0x1c, 0x29,0x3c,0xcb,0x04,
248                               },
249                               .infolen = 0,
250                               .info = NULL,
251                     },
252           };
253           uint8_t okm[128];
254           unsigned i;
255 
256           for (i = 0; i < __arraycount(C); i++) {
257                     if (hkdf_hmac_sha256(okm, C[i].L, C[i].prk, C[i].prklen,
258                               C[i].info, C[i].infolen))
259                               return -1;
260                     if (memcmp(okm, C[i].okm, C[i].L))
261                               return -1;
262           }
263 
264           return 0;
265 }
266 
267 #if 0
268 int
269 main(void)
270 {
271           return hkdf_hmac_sha256_selftest();
272 }
273 #endif
274