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"); 154