| 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 (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(tfm: hmac_tfm, key: salt, keylen: saltlen); |
| 51 | if (!err) |
| 52 | err = crypto_shash_tfm_digest(tfm: hmac_tfm, data: ikm, len: ikmlen, out: 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(tfm: 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, data: prev, len: hashlen); |
| 97 | if (err) |
| 98 | goto out; |
| 99 | } |
| 100 | |
| 101 | if (infolen) { |
| 102 | err = crypto_shash_update(desc, data: info, len: 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, data: &counter, len: 1, out: tmp); |
| 110 | if (err) |
| 111 | goto out; |
| 112 | memcpy(&okm[i], tmp, okmlen - i); |
| 113 | memzero_explicit(s: tmp, count: sizeof(tmp)); |
| 114 | } else { |
| 115 | err = crypto_shash_finup(desc, data: &counter, len: 1, out: &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(s: okm, count: okmlen); /* so caller doesn't need to */ |
| 126 | shash_desc_zero(desc); |
| 127 | memzero_explicit(s: 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(alg_name: shash, type: 0, mask: 0); |
| 472 | if (IS_ERR(ptr: tfm)) { |
| 473 | pr_err("%s(%s): failed to allocate transform: %ld\n" , |
| 474 | tv->test, shash, PTR_ERR(tfm)); |
| 475 | return PTR_ERR(ptr: 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(p: prk, q: tv->prk, size: tv->prk_size)) { |
| 502 | pr_err("%s(%s): hkdf_extract prk mismatch\n" , |
| 503 | tv->test, driver); |
| 504 | print_hex_dump(KERN_ERR, prefix_str: "prk: " , prefix_type: DUMP_PREFIX_NONE, |
| 505 | rowsize: 16, groupsize: 1, buf: prk, len: tv->prk_size, ascii: 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, key: tv->prk, keylen: 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(p: okm, q: tv->okm, size: tv->okm_size)) { |
| 529 | pr_err("%s(%s): hkdf_expand() okm mismatch\n" , |
| 530 | tv->test, driver); |
| 531 | print_hex_dump(KERN_ERR, prefix_str: "okm: " , prefix_type: DUMP_PREFIX_NONE, |
| 532 | rowsize: 16, groupsize: 1, buf: okm, len: tv->okm_size, ascii: false); |
| 533 | err = -EINVAL; |
| 534 | } |
| 535 | out_free: |
| 536 | kfree(objp: okm); |
| 537 | kfree(objp: 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_SELFTESTS)) |
| 547 | return 0; |
| 548 | |
| 549 | for (i = 0; i < ARRAY_SIZE(hkdf_sha256_tv); i++) { |
| 550 | ret = hkdf_test(shash: "hmac(sha256)" , tv: &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(shash: "hmac(sha384)" , tv: &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(shash: "hmac(sha512)" , tv: &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 | late_initcall(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)" ); |
| 574 | |