Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto,fs: Separate out hkdf_extract() and hkdf_expand()

Separate out the HKDF functions into a separate module to
to make them available to other callers.
And add a testsuite to the module with test vectors
from RFC 5869 (and additional vectors for SHA384 and SHA512)
to ensure the integrity of the algorithm.

Signed-off-by: Hannes Reinecke <hare@kernel.org>
Acked-by: Eric Biggers <ebiggers@kernel.org>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Keith Busch <kbusch@kernel.org>

authored by

Hannes Reinecke and committed by
Keith Busch
3241cd0c fc22b34e

+615 -69
+6
crypto/Kconfig
··· 141 141 select CRYPTO_ALGAPI 142 142 select CRYPTO_ACOMP2 143 143 144 + config CRYPTO_HKDF 145 + tristate 146 + select CRYPTO_SHA256 if !CONFIG_CRYPTO_MANAGER_DISABLE_TESTS 147 + select CRYPTO_SHA512 if !CONFIG_CRYPTO_MANAGER_DISABLE_TESTS 148 + select CRYPTO_HASH2 149 + 144 150 config CRYPTO_MANAGER 145 151 tristate "Cryptographic algorithm manager" 146 152 select CRYPTO_MANAGER2
+1
crypto/Makefile
··· 34 34 obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o 35 35 obj-$(CONFIG_CRYPTO_SIG2) += sig.o 36 36 obj-$(CONFIG_CRYPTO_KPP2) += kpp.o 37 + obj-$(CONFIG_CRYPTO_HKDF) += hkdf.o 37 38 38 39 dh_generic-y := dh.o 39 40 dh_generic-y += dh_helper.o
+573
crypto/hkdf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Implementation of HKDF ("HMAC-based Extract-and-Expand Key Derivation 4 + * Function"), aka RFC 5869. See also the original paper (Krawczyk 2010): 5 + * "Cryptographic Extraction and Key Derivation: The HKDF Scheme". 6 + * 7 + * Copyright 2019 Google LLC 8 + */ 9 + 10 + #include <crypto/internal/hash.h> 11 + #include <crypto/sha2.h> 12 + #include <crypto/hkdf.h> 13 + #include <linux/module.h> 14 + 15 + /* 16 + * HKDF consists of two steps: 17 + * 18 + * 1. HKDF-Extract: extract a pseudorandom key from the input keying material 19 + * and optional salt. 20 + * 2. HKDF-Expand: expand the pseudorandom key into output keying material of 21 + * any length, parameterized by an application-specific info string. 22 + * 23 + */ 24 + 25 + /** 26 + * hkdf_extract - HKDF-Extract (RFC 5869 section 2.2) 27 + * @hmac_tfm: an HMAC transform using the hash function desired for HKDF. The 28 + * caller is responsible for setting the @prk afterwards. 29 + * @ikm: input keying material 30 + * @ikmlen: length of @ikm 31 + * @salt: input salt value 32 + * @saltlen: length of @salt 33 + * @prk: resulting pseudorandom key 34 + * 35 + * Extracts a pseudorandom key @prk from the input keying material 36 + * @ikm with length @ikmlen and salt @salt with length @saltlen. 37 + * The length of @prk is given by the digest size of @hmac_tfm. 38 + * For an 'unsalted' version of HKDF-Extract @salt must be set 39 + * to all zeroes and @saltlen must be set to the length of @prk. 40 + * 41 + * Returns 0 on success with the pseudorandom key stored in @prk, 42 + * or a negative errno value otherwise. 43 + */ 44 + int hkdf_extract(struct crypto_shash *hmac_tfm, const u8 *ikm, 45 + unsigned int ikmlen, const u8 *salt, unsigned int saltlen, 46 + u8 *prk) 47 + { 48 + int err; 49 + 50 + err = crypto_shash_setkey(hmac_tfm, salt, saltlen); 51 + if (!err) 52 + err = crypto_shash_tfm_digest(hmac_tfm, ikm, ikmlen, prk); 53 + 54 + return err; 55 + } 56 + EXPORT_SYMBOL_GPL(hkdf_extract); 57 + 58 + /** 59 + * hkdf_expand - HKDF-Expand (RFC 5869 section 2.3) 60 + * @hmac_tfm: hash context keyed with pseudorandom key 61 + * @info: application-specific information 62 + * @infolen: length of @info 63 + * @okm: output keying material 64 + * @okmlen: length of @okm 65 + * 66 + * This expands the pseudorandom key, which was already keyed into @hmac_tfm, 67 + * into @okmlen bytes of output keying material parameterized by the 68 + * application-specific @info of length @infolen bytes. 69 + * This is thread-safe and may be called by multiple threads in parallel. 70 + * 71 + * Returns 0 on success with output keying material stored in @okm, 72 + * or a negative errno value otherwise. 73 + */ 74 + int hkdf_expand(struct crypto_shash *hmac_tfm, 75 + const u8 *info, unsigned int infolen, 76 + u8 *okm, unsigned int okmlen) 77 + { 78 + SHASH_DESC_ON_STACK(desc, hmac_tfm); 79 + unsigned int i, hashlen = crypto_shash_digestsize(hmac_tfm); 80 + int err; 81 + const u8 *prev = NULL; 82 + u8 counter = 1; 83 + u8 tmp[HASH_MAX_DIGESTSIZE] = {}; 84 + 85 + if (WARN_ON(okmlen > 255 * hashlen)) 86 + return -EINVAL; 87 + 88 + desc->tfm = hmac_tfm; 89 + 90 + for (i = 0; i < okmlen; i += hashlen) { 91 + err = crypto_shash_init(desc); 92 + if (err) 93 + goto out; 94 + 95 + if (prev) { 96 + err = crypto_shash_update(desc, prev, hashlen); 97 + if (err) 98 + goto out; 99 + } 100 + 101 + if (infolen) { 102 + err = crypto_shash_update(desc, info, infolen); 103 + if (err) 104 + goto out; 105 + } 106 + 107 + BUILD_BUG_ON(sizeof(counter) != 1); 108 + if (okmlen - i < hashlen) { 109 + err = crypto_shash_finup(desc, &counter, 1, tmp); 110 + if (err) 111 + goto out; 112 + memcpy(&okm[i], tmp, okmlen - i); 113 + memzero_explicit(tmp, sizeof(tmp)); 114 + } else { 115 + err = crypto_shash_finup(desc, &counter, 1, &okm[i]); 116 + if (err) 117 + goto out; 118 + } 119 + counter++; 120 + prev = &okm[i]; 121 + } 122 + err = 0; 123 + out: 124 + if (unlikely(err)) 125 + memzero_explicit(okm, okmlen); /* so caller doesn't need to */ 126 + shash_desc_zero(desc); 127 + memzero_explicit(tmp, HASH_MAX_DIGESTSIZE); 128 + return err; 129 + } 130 + EXPORT_SYMBOL_GPL(hkdf_expand); 131 + 132 + struct hkdf_testvec { 133 + const char *test; 134 + const u8 *ikm; 135 + const u8 *salt; 136 + const u8 *info; 137 + const u8 *prk; 138 + const u8 *okm; 139 + u16 ikm_size; 140 + u16 salt_size; 141 + u16 info_size; 142 + u16 prk_size; 143 + u16 okm_size; 144 + }; 145 + 146 + /* 147 + * HKDF test vectors from RFC5869 148 + * 149 + * Additional HKDF test vectors from 150 + * https://github.com/brycx/Test-Vector-Generation/blob/master/HKDF/hkdf-hmac-sha2-test-vectors.md 151 + */ 152 + static const struct hkdf_testvec hkdf_sha256_tv[] = { 153 + { 154 + .test = "basic hdkf test", 155 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 156 + "\x0b\x0b\x0b\x0b\x0b\x0b", 157 + .ikm_size = 22, 158 + .salt = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", 159 + .salt_size = 13, 160 + .info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 161 + .info_size = 10, 162 + .prk = "\x07\x77\x09\x36\x2c\x2e\x32\xdf\x0d\xdc\x3f\x0d\xc4\x7b\xba\x63" 163 + "\x90\xb6\xc7\x3b\xb5\x0f\x9c\x31\x22\xec\x84\x4a\xd7\xc2\xb3\xe5", 164 + .prk_size = 32, 165 + .okm = "\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a\x90\x43\x4f\x64\xd0\x36\x2f\x2a" 166 + "\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf" 167 + "\x34\x00\x72\x08\xd5\xb8\x87\x18\x58\x65", 168 + .okm_size = 42, 169 + }, { 170 + .test = "hkdf test with long input", 171 + .ikm = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 172 + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" 173 + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" 174 + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" 175 + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 176 + .ikm_size = 80, 177 + .salt = "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" 178 + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" 179 + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" 180 + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" 181 + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 182 + .salt_size = 80, 183 + .info = "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" 184 + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" 185 + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" 186 + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" 187 + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 188 + .info_size = 80, 189 + .prk = "\x06\xa6\xb8\x8c\x58\x53\x36\x1a\x06\x10\x4c\x9c\xeb\x35\xb4\x5c" 190 + "\xef\x76\x00\x14\x90\x46\x71\x01\x4a\x19\x3f\x40\xc1\x5f\xc2\x44", 191 + .prk_size = 32, 192 + .okm = "\xb1\x1e\x39\x8d\xc8\x03\x27\xa1\xc8\xe7\xf7\x8c\x59\x6a\x49\x34" 193 + "\x4f\x01\x2e\xda\x2d\x4e\xfa\xd8\xa0\x50\xcc\x4c\x19\xaf\xa9\x7c" 194 + "\x59\x04\x5a\x99\xca\xc7\x82\x72\x71\xcb\x41\xc6\x5e\x59\x0e\x09" 195 + "\xda\x32\x75\x60\x0c\x2f\x09\xb8\x36\x77\x93\xa9\xac\xa3\xdb\x71" 196 + "\xcc\x30\xc5\x81\x79\xec\x3e\x87\xc1\x4c\x01\xd5\xc1\xf3\x43\x4f" 197 + "\x1d\x87", 198 + .okm_size = 82, 199 + }, { 200 + .test = "hkdf test with zero salt and info", 201 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 202 + "\x0b\x0b\x0b\x0b\x0b\x0b", 203 + .ikm_size = 22, 204 + .salt = NULL, 205 + .salt_size = 0, 206 + .info = NULL, 207 + .info_size = 0, 208 + .prk = "\x19\xef\x24\xa3\x2c\x71\x7b\x16\x7f\x33\xa9\x1d\x6f\x64\x8b\xdf" 209 + "\x96\x59\x67\x76\xaf\xdb\x63\x77\xac\x43\x4c\x1c\x29\x3c\xcb\x04", 210 + .prk_size = 32, 211 + .okm = "\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f\x71\x5f\x80\x2a\x06\x3c\x5a\x31" 212 + "\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d" 213 + "\x9d\x20\x13\x95\xfa\xa4\xb6\x1a\x96\xc8", 214 + .okm_size = 42, 215 + }, { 216 + .test = "hkdf test with short input", 217 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 218 + .ikm_size = 11, 219 + .salt = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", 220 + .salt_size = 13, 221 + .info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 222 + .info_size = 10, 223 + .prk = "\x82\x65\xf6\x9d\x7f\xf7\xe5\x01\x37\x93\x01\x5c\xa0\xef\x92\x0c" 224 + "\xb1\x68\x21\x99\xc8\xbc\x3a\x00\xda\x0c\xab\x47\xb7\xb0\x0f\xdf", 225 + .prk_size = 32, 226 + .okm = "\x58\xdc\xe1\x0d\x58\x01\xcd\xfd\xa8\x31\x72\x6b\xfe\xbc\xb7\x43" 227 + "\xd1\x4a\x7e\xe8\x3a\xa0\x57\xa9\x3d\x59\xb0\xa1\x31\x7f\xf0\x9d" 228 + "\x10\x5c\xce\xcf\x53\x56\x92\xb1\x4d\xd5", 229 + .okm_size = 42, 230 + }, { 231 + .test = "unsalted hkdf test with zero info", 232 + .ikm = "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" 233 + "\x0c\x0c\x0c\x0c\x0c\x0c", 234 + .ikm_size = 22, 235 + .salt = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 236 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 237 + .salt_size = 32, 238 + .info = NULL, 239 + .info_size = 0, 240 + .prk = "\xaa\x84\x1e\x1f\x35\x74\xf3\x2d\x13\xfb\xa8\x00\x5f\xcd\x9b\x8d" 241 + "\x77\x67\x82\xa5\xdf\xa1\x92\x38\x92\xfd\x8b\x63\x5d\x3a\x89\xdf", 242 + .prk_size = 32, 243 + .okm = "\x59\x68\x99\x17\x9a\xb1\xbc\x00\xa7\xc0\x37\x86\xff\x43\xee\x53" 244 + "\x50\x04\xbe\x2b\xb9\xbe\x68\xbc\x14\x06\x63\x6f\x54\xbd\x33\x8a" 245 + "\x66\xa2\x37\xba\x2a\xcb\xce\xe3\xc9\xa7", 246 + .okm_size = 42, 247 + } 248 + }; 249 + 250 + static const struct hkdf_testvec hkdf_sha384_tv[] = { 251 + { 252 + .test = "basic hkdf test", 253 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 254 + "\x0b\x0b\x0b\x0b\x0b\x0b", 255 + .ikm_size = 22, 256 + .salt = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", 257 + .salt_size = 13, 258 + .info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 259 + .info_size = 10, 260 + .prk = "\x70\x4b\x39\x99\x07\x79\xce\x1d\xc5\x48\x05\x2c\x7d\xc3\x9f\x30" 261 + "\x35\x70\xdd\x13\xfb\x39\xf7\xac\xc5\x64\x68\x0b\xef\x80\xe8\xde" 262 + "\xc7\x0e\xe9\xa7\xe1\xf3\xe2\x93\xef\x68\xec\xeb\x07\x2a\x5a\xde", 263 + .prk_size = 48, 264 + .okm = "\x9b\x50\x97\xa8\x60\x38\xb8\x05\x30\x90\x76\xa4\x4b\x3a\x9f\x38" 265 + "\x06\x3e\x25\xb5\x16\xdc\xbf\x36\x9f\x39\x4c\xfa\xb4\x36\x85\xf7" 266 + "\x48\xb6\x45\x77\x63\xe4\xf0\x20\x4f\xc5", 267 + .okm_size = 42, 268 + }, { 269 + .test = "hkdf test with long input", 270 + .ikm = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 271 + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" 272 + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" 273 + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" 274 + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 275 + .ikm_size = 80, 276 + .salt = "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" 277 + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" 278 + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" 279 + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" 280 + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 281 + .salt_size = 80, 282 + .info = "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" 283 + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" 284 + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" 285 + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" 286 + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 287 + .info_size = 80, 288 + .prk = "\xb3\x19\xf6\x83\x1d\xff\x93\x14\xef\xb6\x43\xba\xa2\x92\x63\xb3" 289 + "\x0e\x4a\x8d\x77\x9f\xe3\x1e\x9c\x90\x1e\xfd\x7d\xe7\x37\xc8\x5b" 290 + "\x62\xe6\x76\xd4\xdc\x87\xb0\x89\x5c\x6a\x7d\xc9\x7b\x52\xce\xbb", 291 + .prk_size = 48, 292 + .okm = "\x48\x4c\xa0\x52\xb8\xcc\x72\x4f\xd1\xc4\xec\x64\xd5\x7b\x4e\x81" 293 + "\x8c\x7e\x25\xa8\xe0\xf4\x56\x9e\xd7\x2a\x6a\x05\xfe\x06\x49\xee" 294 + "\xbf\x69\xf8\xd5\xc8\x32\x85\x6b\xf4\xe4\xfb\xc1\x79\x67\xd5\x49" 295 + "\x75\x32\x4a\x94\x98\x7f\x7f\x41\x83\x58\x17\xd8\x99\x4f\xdb\xd6" 296 + "\xf4\xc0\x9c\x55\x00\xdc\xa2\x4a\x56\x22\x2f\xea\x53\xd8\x96\x7a" 297 + "\x8b\x2e", 298 + .okm_size = 82, 299 + }, { 300 + .test = "hkdf test with zero salt and info", 301 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 302 + "\x0b\x0b\x0b\x0b\x0b\x0b", 303 + .ikm_size = 22, 304 + .salt = NULL, 305 + .salt_size = 0, 306 + .info = NULL, 307 + .info_size = 0, 308 + .prk = "\x10\xe4\x0c\xf0\x72\xa4\xc5\x62\x6e\x43\xdd\x22\xc1\xcf\x72\x7d" 309 + "\x4b\xb1\x40\x97\x5c\x9a\xd0\xcb\xc8\xe4\x5b\x40\x06\x8f\x8f\x0b" 310 + "\xa5\x7c\xdb\x59\x8a\xf9\xdf\xa6\x96\x3a\x96\x89\x9a\xf0\x47\xe5", 311 + .prk_size = 48, 312 + .okm = "\xc8\xc9\x6e\x71\x0f\x89\xb0\xd7\x99\x0b\xca\x68\xbc\xde\xc8\xcf" 313 + "\x85\x40\x62\xe5\x4c\x73\xa7\xab\xc7\x43\xfa\xde\x9b\x24\x2d\xaa" 314 + "\xcc\x1c\xea\x56\x70\x41\x5b\x52\x84\x9c", 315 + .okm_size = 42, 316 + }, { 317 + .test = "hkdf test with short input", 318 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 319 + .ikm_size = 11, 320 + .salt = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", 321 + .salt_size = 13, 322 + .info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 323 + .info_size = 10, 324 + .prk = "\x6d\x31\x69\x98\x28\x79\x80\x88\xb3\x59\xda\xd5\x0b\x8f\x01\xb0" 325 + "\x15\xf1\x7a\xa3\xbd\x4e\x27\xa6\xe9\xf8\x73\xb7\x15\x85\xca\x6a" 326 + "\x00\xd1\xf0\x82\x12\x8a\xdb\x3c\xf0\x53\x0b\x57\xc0\xf9\xac\x72", 327 + .prk_size = 48, 328 + .okm = "\xfb\x7e\x67\x43\xeb\x42\xcd\xe9\x6f\x1b\x70\x77\x89\x52\xab\x75" 329 + "\x48\xca\xfe\x53\x24\x9f\x7f\xfe\x14\x97\xa1\x63\x5b\x20\x1f\xf1" 330 + "\x85\xb9\x3e\x95\x19\x92\xd8\x58\xf1\x1a", 331 + .okm_size = 42, 332 + }, { 333 + .test = "unsalted hkdf test with zero info", 334 + .ikm = "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" 335 + "\x0c\x0c\x0c\x0c\x0c\x0c", 336 + .ikm_size = 22, 337 + .salt = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 338 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 339 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 340 + .salt_size = 48, 341 + .info = NULL, 342 + .info_size = 0, 343 + .prk = "\x9d\x2d\xa5\x06\x6f\x05\xd1\x6c\x59\xfe\xdf\x6c\x5f\x32\xc7\x5e" 344 + "\xda\x9a\x47\xa7\x9c\x93\x6a\xa4\x4c\xb7\x63\xa8\xe2\x2f\xfb\xfc" 345 + "\xd8\xfe\x55\x43\x58\x53\x47\x21\x90\x39\xd1\x68\x28\x36\x33\xf5", 346 + .prk_size = 48, 347 + .okm = "\x6a\xd7\xc7\x26\xc8\x40\x09\x54\x6a\x76\xe0\x54\x5d\xf2\x66\x78" 348 + "\x7e\x2b\x2c\xd6\xca\x43\x73\xa1\xf3\x14\x50\xa7\xbd\xf9\x48\x2b" 349 + "\xfa\xb8\x11\xf5\x54\x20\x0e\xad\x8f\x53", 350 + .okm_size = 42, 351 + } 352 + }; 353 + 354 + static const struct hkdf_testvec hkdf_sha512_tv[] = { 355 + { 356 + .test = "basic hkdf test", 357 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 358 + "\x0b\x0b\x0b\x0b\x0b\x0b", 359 + .ikm_size = 22, 360 + .salt = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", 361 + .salt_size = 13, 362 + .info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 363 + .info_size = 10, 364 + .prk = "\x66\x57\x99\x82\x37\x37\xde\xd0\x4a\x88\xe4\x7e\x54\xa5\x89\x0b" 365 + "\xb2\xc3\xd2\x47\xc7\xa4\x25\x4a\x8e\x61\x35\x07\x23\x59\x0a\x26" 366 + "\xc3\x62\x38\x12\x7d\x86\x61\xb8\x8c\xf8\x0e\xf8\x02\xd5\x7e\x2f" 367 + "\x7c\xeb\xcf\x1e\x00\xe0\x83\x84\x8b\xe1\x99\x29\xc6\x1b\x42\x37", 368 + .prk_size = 64, 369 + .okm = "\x83\x23\x90\x08\x6c\xda\x71\xfb\x47\x62\x5b\xb5\xce\xb1\x68\xe4" 370 + "\xc8\xe2\x6a\x1a\x16\xed\x34\xd9\xfc\x7f\xe9\x2c\x14\x81\x57\x93" 371 + "\x38\xda\x36\x2c\xb8\xd9\xf9\x25\xd7\xcb", 372 + .okm_size = 42, 373 + }, { 374 + .test = "hkdf test with long input", 375 + .ikm = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" 376 + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" 377 + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" 378 + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" 379 + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", 380 + .ikm_size = 80, 381 + .salt = "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" 382 + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" 383 + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" 384 + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" 385 + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 386 + .salt_size = 80, 387 + .info = "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" 388 + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" 389 + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" 390 + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" 391 + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", 392 + .info_size = 80, 393 + .prk = "\x35\x67\x25\x42\x90\x7d\x4e\x14\x2c\x00\xe8\x44\x99\xe7\x4e\x1d" 394 + "\xe0\x8b\xe8\x65\x35\xf9\x24\xe0\x22\x80\x4a\xd7\x75\xdd\xe2\x7e" 395 + "\xc8\x6c\xd1\xe5\xb7\xd1\x78\xc7\x44\x89\xbd\xbe\xb3\x07\x12\xbe" 396 + "\xb8\x2d\x4f\x97\x41\x6c\x5a\x94\xea\x81\xeb\xdf\x3e\x62\x9e\x4a", 397 + .prk_size = 64, 398 + .okm = "\xce\x6c\x97\x19\x28\x05\xb3\x46\xe6\x16\x1e\x82\x1e\xd1\x65\x67" 399 + "\x3b\x84\xf4\x00\xa2\xb5\x14\xb2\xfe\x23\xd8\x4c\xd1\x89\xdd\xf1" 400 + "\xb6\x95\xb4\x8c\xbd\x1c\x83\x88\x44\x11\x37\xb3\xce\x28\xf1\x6a" 401 + "\xa6\x4b\xa3\x3b\xa4\x66\xb2\x4d\xf6\xcf\xcb\x02\x1e\xcf\xf2\x35" 402 + "\xf6\xa2\x05\x6c\xe3\xaf\x1d\xe4\x4d\x57\x20\x97\xa8\x50\x5d\x9e" 403 + "\x7a\x93", 404 + .okm_size = 82, 405 + }, { 406 + .test = "hkdf test with zero salt and info", 407 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" 408 + "\x0b\x0b\x0b\x0b\x0b\x0b", 409 + .ikm_size = 22, 410 + .salt = NULL, 411 + .salt_size = 0, 412 + .info = NULL, 413 + .info_size = 0, 414 + .prk = "\xfd\x20\x0c\x49\x87\xac\x49\x13\x13\xbd\x4a\x2a\x13\x28\x71\x21" 415 + "\x24\x72\x39\xe1\x1c\x9e\xf8\x28\x02\x04\x4b\x66\xef\x35\x7e\x5b" 416 + "\x19\x44\x98\xd0\x68\x26\x11\x38\x23\x48\x57\x2a\x7b\x16\x11\xde" 417 + "\x54\x76\x40\x94\x28\x63\x20\x57\x8a\x86\x3f\x36\x56\x2b\x0d\xf6", 418 + .prk_size = 64, 419 + .okm = "\xf5\xfa\x02\xb1\x82\x98\xa7\x2a\x8c\x23\x89\x8a\x87\x03\x47\x2c" 420 + "\x6e\xb1\x79\xdc\x20\x4c\x03\x42\x5c\x97\x0e\x3b\x16\x4b\xf9\x0f" 421 + "\xff\x22\xd0\x48\x36\xd0\xe2\x34\x3b\xac", 422 + .okm_size = 42, 423 + }, { 424 + .test = "hkdf test with short input", 425 + .ikm = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 426 + .ikm_size = 11, 427 + .salt = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", 428 + .salt_size = 13, 429 + .info = "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", 430 + .info_size = 10, 431 + .prk = "\x67\x40\x9c\x9c\xac\x28\xb5\x2e\xe9\xfa\xd9\x1c\x2f\xda\x99\x9f" 432 + "\x7c\xa2\x2e\x34\x34\xf0\xae\x77\x28\x63\x83\x65\x68\xad\x6a\x7f" 433 + "\x10\xcf\x11\x3b\xfd\xdd\x56\x01\x29\xa5\x94\xa8\xf5\x23\x85\xc2" 434 + "\xd6\x61\xd7\x85\xd2\x9c\xe9\x3a\x11\x40\x0c\x92\x06\x83\x18\x1d", 435 + .prk_size = 64, 436 + .okm = "\x74\x13\xe8\x99\x7e\x02\x06\x10\xfb\xf6\x82\x3f\x2c\xe1\x4b\xff" 437 + "\x01\x87\x5d\xb1\xca\x55\xf6\x8c\xfc\xf3\x95\x4d\xc8\xaf\xf5\x35" 438 + "\x59\xbd\x5e\x30\x28\xb0\x80\xf7\xc0\x68", 439 + .okm_size = 42, 440 + }, { 441 + .test = "unsalted hkdf test with zero info", 442 + .ikm = "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" 443 + "\x0c\x0c\x0c\x0c\x0c\x0c", 444 + .ikm_size = 22, 445 + .salt = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 446 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 447 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" 448 + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 449 + .salt_size = 64, 450 + .info = NULL, 451 + .info_size = 0, 452 + .prk = "\x53\x46\xb3\x76\xbf\x3a\xa9\xf8\x4f\x8f\x6e\xd5\xb1\xc4\xf4\x89" 453 + "\x17\x2e\x24\x4d\xac\x30\x3d\x12\xf6\x8e\xcc\x76\x6e\xa6\x00\xaa" 454 + "\x88\x49\x5e\x7f\xb6\x05\x80\x31\x22\xfa\x13\x69\x24\xa8\x40\xb1" 455 + "\xf0\x71\x9d\x2d\x5f\x68\xe2\x9b\x24\x22\x99\xd7\x58\xed\x68\x0c", 456 + .prk_size = 64, 457 + .okm = "\x14\x07\xd4\x60\x13\xd9\x8b\xc6\xde\xce\xfc\xfe\xe5\x5f\x0f\x90" 458 + "\xb0\xc7\xf6\x3d\x68\xeb\x1a\x80\xea\xf0\x7e\x95\x3c\xfc\x0a\x3a" 459 + "\x52\x40\xa1\x55\xd6\xe4\xda\xa9\x65\xbb", 460 + .okm_size = 42, 461 + } 462 + }; 463 + 464 + static int hkdf_test(const char *shash, const struct hkdf_testvec *tv) 465 + { struct crypto_shash *tfm = NULL; 466 + u8 *prk = NULL, *okm = NULL; 467 + unsigned int prk_size; 468 + const char *driver; 469 + int err; 470 + 471 + tfm = crypto_alloc_shash(shash, 0, 0); 472 + if (IS_ERR(tfm)) { 473 + pr_err("%s(%s): failed to allocate transform: %ld\n", 474 + tv->test, shash, PTR_ERR(tfm)); 475 + return PTR_ERR(tfm); 476 + } 477 + driver = crypto_shash_driver_name(tfm); 478 + 479 + prk_size = crypto_shash_digestsize(tfm); 480 + prk = kzalloc(prk_size, GFP_KERNEL); 481 + if (!prk) { 482 + err = -ENOMEM; 483 + goto out_free; 484 + } 485 + 486 + if (tv->prk_size != prk_size) { 487 + pr_err("%s(%s): prk size mismatch (vec %u, digest %u\n", 488 + tv->test, driver, tv->prk_size, prk_size); 489 + err = -EINVAL; 490 + goto out_free; 491 + } 492 + 493 + err = hkdf_extract(tfm, tv->ikm, tv->ikm_size, 494 + tv->salt, tv->salt_size, prk); 495 + if (err) { 496 + pr_err("%s(%s): hkdf_extract failed with %d\n", 497 + tv->test, driver, err); 498 + goto out_free; 499 + } 500 + 501 + if (memcmp(prk, tv->prk, tv->prk_size)) { 502 + pr_err("%s(%s): hkdf_extract prk mismatch\n", 503 + tv->test, driver); 504 + print_hex_dump(KERN_ERR, "prk: ", DUMP_PREFIX_NONE, 505 + 16, 1, prk, tv->prk_size, false); 506 + err = -EINVAL; 507 + goto out_free; 508 + } 509 + 510 + okm = kzalloc(tv->okm_size, GFP_KERNEL); 511 + if (!okm) { 512 + err = -ENOMEM; 513 + goto out_free; 514 + } 515 + 516 + err = crypto_shash_setkey(tfm, tv->prk, tv->prk_size); 517 + if (err) { 518 + pr_err("%s(%s): failed to set prk, error %d\n", 519 + tv->test, driver, err); 520 + goto out_free; 521 + } 522 + 523 + err = hkdf_expand(tfm, tv->info, tv->info_size, 524 + okm, tv->okm_size); 525 + if (err) { 526 + pr_err("%s(%s): hkdf_expand() failed with %d\n", 527 + tv->test, driver, err); 528 + } else if (memcmp(okm, tv->okm, tv->okm_size)) { 529 + pr_err("%s(%s): hkdf_expand() okm mismatch\n", 530 + tv->test, driver); 531 + print_hex_dump(KERN_ERR, "okm: ", DUMP_PREFIX_NONE, 532 + 16, 1, okm, tv->okm_size, false); 533 + err = -EINVAL; 534 + } 535 + out_free: 536 + kfree(okm); 537 + kfree(prk); 538 + crypto_free_shash(tfm); 539 + return err; 540 + } 541 + 542 + static int __init crypto_hkdf_module_init(void) 543 + { 544 + int ret = 0, i; 545 + 546 + if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS)) 547 + return 0; 548 + 549 + for (i = 0; i < ARRAY_SIZE(hkdf_sha256_tv); i++) { 550 + ret = hkdf_test("hmac(sha256)", &hkdf_sha256_tv[i]); 551 + if (ret) 552 + return ret; 553 + } 554 + for (i = 0; i < ARRAY_SIZE(hkdf_sha384_tv); i++) { 555 + ret = hkdf_test("hmac(sha384)", &hkdf_sha384_tv[i]); 556 + if (ret) 557 + return ret; 558 + } 559 + for (i = 0; i < ARRAY_SIZE(hkdf_sha512_tv); i++) { 560 + ret = hkdf_test("hmac(sha512)", &hkdf_sha512_tv[i]); 561 + if (ret) 562 + return ret; 563 + } 564 + return 0; 565 + } 566 + 567 + static void __exit crypto_hkdf_module_exit(void) {} 568 + 569 + module_init(crypto_hkdf_module_init); 570 + module_exit(crypto_hkdf_module_exit); 571 + 572 + MODULE_LICENSE("GPL"); 573 + MODULE_DESCRIPTION("HMAC-based Key Derivation Function (HKDF)");
+1
fs/crypto/Kconfig
··· 3 3 bool "FS Encryption (Per-file encryption)" 4 4 select CRYPTO 5 5 select CRYPTO_HASH 6 + select CRYPTO_HKDF 6 7 select CRYPTO_SKCIPHER 7 8 select CRYPTO_LIB_SHA256 8 9 select KEYS
+14 -69
fs/crypto/hkdf.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 - * Implementation of HKDF ("HMAC-based Extract-and-Expand Key Derivation 4 - * Function"), aka RFC 5869. See also the original paper (Krawczyk 2010): 5 - * "Cryptographic Extraction and Key Derivation: The HKDF Scheme". 6 - * 7 3 * This is used to derive keys from the fscrypt master keys. 8 4 * 9 5 * Copyright 2019 Google LLC ··· 7 11 8 12 #include <crypto/hash.h> 9 13 #include <crypto/sha2.h> 14 + #include <crypto/hkdf.h> 10 15 11 16 #include "fscrypt_private.h" 12 17 ··· 41 44 * there's no way to persist a random salt per master key from kernel mode. 42 45 */ 43 46 44 - /* HKDF-Extract (RFC 5869 section 2.2), unsalted */ 45 - static int hkdf_extract(struct crypto_shash *hmac_tfm, const u8 *ikm, 46 - unsigned int ikmlen, u8 prk[HKDF_HASHLEN]) 47 - { 48 - static const u8 default_salt[HKDF_HASHLEN]; 49 - int err; 50 - 51 - err = crypto_shash_setkey(hmac_tfm, default_salt, HKDF_HASHLEN); 52 - if (err) 53 - return err; 54 - 55 - return crypto_shash_tfm_digest(hmac_tfm, ikm, ikmlen, prk); 56 - } 57 - 58 47 /* 59 48 * Compute HKDF-Extract using the given master key as the input keying material, 60 49 * and prepare an HMAC transform object keyed by the resulting pseudorandom key. ··· 52 69 unsigned int master_key_size) 53 70 { 54 71 struct crypto_shash *hmac_tfm; 72 + static const u8 default_salt[HKDF_HASHLEN]; 55 73 u8 prk[HKDF_HASHLEN]; 56 74 int err; 57 75 ··· 68 84 goto err_free_tfm; 69 85 } 70 86 71 - err = hkdf_extract(hmac_tfm, master_key, master_key_size, prk); 87 + err = hkdf_extract(hmac_tfm, master_key, master_key_size, 88 + default_salt, HKDF_HASHLEN, prk); 72 89 if (err) 73 90 goto err_free_tfm; 74 91 ··· 103 118 u8 *okm, unsigned int okmlen) 104 119 { 105 120 SHASH_DESC_ON_STACK(desc, hkdf->hmac_tfm); 106 - u8 prefix[9]; 107 - unsigned int i; 121 + u8 *full_info; 108 122 int err; 109 - const u8 *prev = NULL; 110 - u8 counter = 1; 111 - u8 tmp[HKDF_HASHLEN]; 112 123 113 - if (WARN_ON_ONCE(okmlen > 255 * HKDF_HASHLEN)) 114 - return -EINVAL; 115 - 124 + full_info = kzalloc(infolen + 9, GFP_KERNEL); 125 + if (!full_info) 126 + return -ENOMEM; 116 127 desc->tfm = hkdf->hmac_tfm; 117 128 118 - memcpy(prefix, "fscrypt\0", 8); 119 - prefix[8] = context; 129 + memcpy(full_info, "fscrypt\0", 8); 130 + full_info[8] = context; 131 + memcpy(full_info + 9, info, infolen); 120 132 121 - for (i = 0; i < okmlen; i += HKDF_HASHLEN) { 122 - 123 - err = crypto_shash_init(desc); 124 - if (err) 125 - goto out; 126 - 127 - if (prev) { 128 - err = crypto_shash_update(desc, prev, HKDF_HASHLEN); 129 - if (err) 130 - goto out; 131 - } 132 - 133 - err = crypto_shash_update(desc, prefix, sizeof(prefix)); 134 - if (err) 135 - goto out; 136 - 137 - err = crypto_shash_update(desc, info, infolen); 138 - if (err) 139 - goto out; 140 - 141 - BUILD_BUG_ON(sizeof(counter) != 1); 142 - if (okmlen - i < HKDF_HASHLEN) { 143 - err = crypto_shash_finup(desc, &counter, 1, tmp); 144 - if (err) 145 - goto out; 146 - memcpy(&okm[i], tmp, okmlen - i); 147 - memzero_explicit(tmp, sizeof(tmp)); 148 - } else { 149 - err = crypto_shash_finup(desc, &counter, 1, &okm[i]); 150 - if (err) 151 - goto out; 152 - } 153 - counter++; 154 - prev = &okm[i]; 155 - } 156 - err = 0; 157 - out: 158 - if (unlikely(err)) 159 - memzero_explicit(okm, okmlen); /* so caller doesn't need to */ 160 - shash_desc_zero(desc); 133 + err = hkdf_expand(hkdf->hmac_tfm, full_info, infolen + 9, 134 + okm, okmlen); 135 + kfree_sensitive(full_info); 161 136 return err; 162 137 } 163 138
+20
include/crypto/hkdf.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * HKDF: HMAC-based Key Derivation Function (HKDF), RFC 5869 4 + * 5 + * Extracted from fs/crypto/hkdf.c, which has 6 + * Copyright 2019 Google LLC 7 + */ 8 + 9 + #ifndef _CRYPTO_HKDF_H 10 + #define _CRYPTO_HKDF_H 11 + 12 + #include <crypto/hash.h> 13 + 14 + int hkdf_extract(struct crypto_shash *hmac_tfm, const u8 *ikm, 15 + unsigned int ikmlen, const u8 *salt, unsigned int saltlen, 16 + u8 *prk); 17 + int hkdf_expand(struct crypto_shash *hmac_tfm, 18 + const u8 *info, unsigned int infolen, 19 + u8 *okm, unsigned int okmlen); 20 + #endif