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: kdf - add SP800-108 counter key derivation function

SP800-108 defines three KDFs - this patch provides the counter KDF
implementation.

The KDF is implemented as a service function where the caller has to
maintain the hash / HMAC state. Apart from this hash/HMAC state, no
additional state is required to be maintained by either the caller or
the KDF implementation.

The key for the KDF is set with the crypto_kdf108_setkey function which
is intended to be invoked before the caller requests a key derivation
operation via crypto_kdf108_ctr_generate.

SP800-108 allows the use of either a HMAC or a hash as crypto primitive
for the KDF. When a HMAC primtive is intended to be used,
crypto_kdf108_setkey must be used to set the HMAC key. Otherwise, for a
hash crypto primitve crypto_kdf108_ctr_generate can be used immediately
after allocating the hash handle.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Stephan Müller and committed by
Herbert Xu
026a733e b808f320

+223
+4
crypto/Kconfig
··· 1845 1845 random numbers. This Jitterentropy RNG registers with 1846 1846 the kernel crypto API and can be used by any caller. 1847 1847 1848 + config CRYPTO_KDF800108_CTR 1849 + tristate 1850 + select CRYPTO_HASH 1851 + 1848 1852 config CRYPTO_USER_API 1849 1853 tristate 1850 1854
+5
crypto/Makefile
··· 200 200 obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o 201 201 crypto_simd-y := simd.o 202 202 obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o 203 + 204 + # 205 + # Key derivation function 206 + # 207 + obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
+153
crypto/kdf_sp800108.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* 4 + * SP800-108 Key-derivation function 5 + * 6 + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> 7 + */ 8 + 9 + #include <linux/fips.h> 10 + #include <linux/module.h> 11 + #include <crypto/kdf_sp800108.h> 12 + #include <crypto/internal/kdf_selftest.h> 13 + 14 + /* 15 + * SP800-108 CTR KDF implementation 16 + */ 17 + int crypto_kdf108_ctr_generate(struct crypto_shash *kmd, 18 + const struct kvec *info, unsigned int info_nvec, 19 + u8 *dst, unsigned int dlen) 20 + { 21 + SHASH_DESC_ON_STACK(desc, kmd); 22 + __be32 counter = cpu_to_be32(1); 23 + const unsigned int h = crypto_shash_digestsize(kmd), dlen_orig = dlen; 24 + unsigned int i; 25 + int err = 0; 26 + u8 *dst_orig = dst; 27 + 28 + desc->tfm = kmd; 29 + 30 + while (dlen) { 31 + err = crypto_shash_init(desc); 32 + if (err) 33 + goto out; 34 + 35 + err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32)); 36 + if (err) 37 + goto out; 38 + 39 + for (i = 0; i < info_nvec; i++) { 40 + err = crypto_shash_update(desc, info[i].iov_base, 41 + info[i].iov_len); 42 + if (err) 43 + goto out; 44 + } 45 + 46 + if (dlen < h) { 47 + u8 tmpbuffer[HASH_MAX_DIGESTSIZE]; 48 + 49 + err = crypto_shash_final(desc, tmpbuffer); 50 + if (err) 51 + goto out; 52 + memcpy(dst, tmpbuffer, dlen); 53 + memzero_explicit(tmpbuffer, h); 54 + goto out; 55 + } 56 + 57 + err = crypto_shash_final(desc, dst); 58 + if (err) 59 + goto out; 60 + 61 + dlen -= h; 62 + dst += h; 63 + counter = cpu_to_be32(be32_to_cpu(counter) + 1); 64 + } 65 + 66 + out: 67 + if (err) 68 + memzero_explicit(dst_orig, dlen_orig); 69 + shash_desc_zero(desc); 70 + return err; 71 + } 72 + EXPORT_SYMBOL(crypto_kdf108_ctr_generate); 73 + 74 + /* 75 + * The seeding of the KDF 76 + */ 77 + int crypto_kdf108_setkey(struct crypto_shash *kmd, 78 + const u8 *key, size_t keylen, 79 + const u8 *ikm, size_t ikmlen) 80 + { 81 + unsigned int ds = crypto_shash_digestsize(kmd); 82 + 83 + /* SP800-108 does not support IKM */ 84 + if (ikm || ikmlen) 85 + return -EINVAL; 86 + 87 + /* Check according to SP800-108 section 7.2 */ 88 + if (ds > keylen) 89 + return -EINVAL; 90 + 91 + /* Set the key for the MAC used for the KDF. */ 92 + return crypto_shash_setkey(kmd, key, keylen); 93 + } 94 + EXPORT_SYMBOL(crypto_kdf108_setkey); 95 + 96 + /* 97 + * Test vector obtained from 98 + * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/CounterMode.zip 99 + */ 100 + static const struct kdf_testvec kdf_ctr_hmac_sha256_tv_template[] = { 101 + { 102 + .key = "\xdd\x1d\x91\xb7\xd9\x0b\x2b\xd3" 103 + "\x13\x85\x33\xce\x92\xb2\x72\xfb" 104 + "\xf8\xa3\x69\x31\x6a\xef\xe2\x42" 105 + "\xe6\x59\xcc\x0a\xe2\x38\xaf\xe0", 106 + .keylen = 32, 107 + .ikm = NULL, 108 + .ikmlen = 0, 109 + .info = { 110 + .iov_base = "\x01\x32\x2b\x96\xb3\x0a\xcd\x19" 111 + "\x79\x79\x44\x4e\x46\x8e\x1c\x5c" 112 + "\x68\x59\xbf\x1b\x1c\xf9\x51\xb7" 113 + "\xe7\x25\x30\x3e\x23\x7e\x46\xb8" 114 + "\x64\xa1\x45\xfa\xb2\x5e\x51\x7b" 115 + "\x08\xf8\x68\x3d\x03\x15\xbb\x29" 116 + "\x11\xd8\x0a\x0e\x8a\xba\x17\xf3" 117 + "\xb4\x13\xfa\xac", 118 + .iov_len = 60 119 + }, 120 + .expected = "\x10\x62\x13\x42\xbf\xb0\xfd\x40" 121 + "\x04\x6c\x0e\x29\xf2\xcf\xdb\xf0", 122 + .expectedlen = 16 123 + } 124 + }; 125 + 126 + static int __init crypto_kdf108_init(void) 127 + { 128 + int ret = kdf_test(&kdf_ctr_hmac_sha256_tv_template[0], "hmac(sha256)", 129 + crypto_kdf108_setkey, crypto_kdf108_ctr_generate); 130 + 131 + if (ret) { 132 + if (fips_enabled) 133 + panic("alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", 134 + ret); 135 + 136 + WARN(1, 137 + "alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", 138 + ret); 139 + } else { 140 + pr_info("alg: self-tests for CTR-KDF (hmac(sha256)) passed\n"); 141 + } 142 + 143 + return ret; 144 + } 145 + 146 + static void __exit crypto_kdf108_exit(void) { } 147 + 148 + module_init(crypto_kdf108_init); 149 + module_exit(crypto_kdf108_exit); 150 + 151 + MODULE_LICENSE("GPL v2"); 152 + MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); 153 + MODULE_DESCRIPTION("Key Derivation Function conformant to SP800-108");
+61
include/crypto/kdf_sp800108.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* 4 + * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> 5 + */ 6 + 7 + #ifndef _CRYPTO_KDF108_H 8 + #define _CRYPTO_KDF108_H 9 + 10 + #include <crypto/hash.h> 11 + #include <linux/uio.h> 12 + 13 + /** 14 + * Counter KDF generate operation according to SP800-108 section 5.1 15 + * as well as SP800-56A section 5.8.1 (Single-step KDF). 16 + * 17 + * @kmd Keyed message digest whose key was set with crypto_kdf108_setkey or 18 + * unkeyed message digest 19 + * @info optional context and application specific information - this may be 20 + * NULL 21 + * @info_vec number of optional context/application specific information entries 22 + * @dst destination buffer that the caller already allocated 23 + * @dlen length of the destination buffer - the KDF derives that amount of 24 + * bytes. 25 + * 26 + * To comply with SP800-108, the caller must provide Label || 0x00 || Context 27 + * in the info parameter. 28 + * 29 + * @return 0 on success, < 0 on error 30 + */ 31 + int crypto_kdf108_ctr_generate(struct crypto_shash *kmd, 32 + const struct kvec *info, unsigned int info_nvec, 33 + u8 *dst, unsigned int dlen); 34 + 35 + /** 36 + * Counter KDF setkey operation 37 + * 38 + * @kmd Keyed message digest allocated by the caller. The key should not have 39 + * been set. 40 + * @key Seed key to be used to initialize the keyed message digest context. 41 + * @keylen This length of the key buffer. 42 + * @ikm The SP800-108 KDF does not support IKM - this parameter must be NULL 43 + * @ikmlen This parameter must be 0. 44 + * 45 + * According to SP800-108 section 7.2, the seed key must be at least as large as 46 + * the message digest size of the used keyed message digest. This limitation 47 + * is enforced by the implementation. 48 + * 49 + * SP800-108 allows the use of either a HMAC or a hash primitive. When 50 + * the caller intends to use a hash primitive, the call to 51 + * crypto_kdf108_setkey is not required and the key derivation operation can 52 + * immediately performed using crypto_kdf108_ctr_generate after allocating 53 + * a handle. 54 + * 55 + * @return 0 on success, < 0 on error 56 + */ 57 + int crypto_kdf108_setkey(struct crypto_shash *kmd, 58 + const u8 *key, size_t keylen, 59 + const u8 *ikm, size_t ikmlen); 60 + 61 + #endif /* _CRYPTO_KDF108_H */