xref: /netbsd-src/sbin/cgdconfig/hkdf_hmac_sha256.c (revision 920e28df6585dfb4225870a6b5307bd2775eab35)
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