Home | History | Annotate | Line # | Download | only in cgdconfig
      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
     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
     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
     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
    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
    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