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