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