162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci/* 462306a36Sopenharmony_ci * SP800-108 Key-derivation function 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2021, Stephan Mueller <smueller@chronox.de> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/fips.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <crypto/kdf_sp800108.h> 1262306a36Sopenharmony_ci#include <crypto/internal/kdf_selftest.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* 1562306a36Sopenharmony_ci * SP800-108 CTR KDF implementation 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ciint crypto_kdf108_ctr_generate(struct crypto_shash *kmd, 1862306a36Sopenharmony_ci const struct kvec *info, unsigned int info_nvec, 1962306a36Sopenharmony_ci u8 *dst, unsigned int dlen) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci SHASH_DESC_ON_STACK(desc, kmd); 2262306a36Sopenharmony_ci __be32 counter = cpu_to_be32(1); 2362306a36Sopenharmony_ci const unsigned int h = crypto_shash_digestsize(kmd), dlen_orig = dlen; 2462306a36Sopenharmony_ci unsigned int i; 2562306a36Sopenharmony_ci int err = 0; 2662306a36Sopenharmony_ci u8 *dst_orig = dst; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci desc->tfm = kmd; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci while (dlen) { 3162306a36Sopenharmony_ci err = crypto_shash_init(desc); 3262306a36Sopenharmony_ci if (err) 3362306a36Sopenharmony_ci goto out; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32)); 3662306a36Sopenharmony_ci if (err) 3762306a36Sopenharmony_ci goto out; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci for (i = 0; i < info_nvec; i++) { 4062306a36Sopenharmony_ci err = crypto_shash_update(desc, info[i].iov_base, 4162306a36Sopenharmony_ci info[i].iov_len); 4262306a36Sopenharmony_ci if (err) 4362306a36Sopenharmony_ci goto out; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci if (dlen < h) { 4762306a36Sopenharmony_ci u8 tmpbuffer[HASH_MAX_DIGESTSIZE]; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci err = crypto_shash_final(desc, tmpbuffer); 5062306a36Sopenharmony_ci if (err) 5162306a36Sopenharmony_ci goto out; 5262306a36Sopenharmony_ci memcpy(dst, tmpbuffer, dlen); 5362306a36Sopenharmony_ci memzero_explicit(tmpbuffer, h); 5462306a36Sopenharmony_ci goto out; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci err = crypto_shash_final(desc, dst); 5862306a36Sopenharmony_ci if (err) 5962306a36Sopenharmony_ci goto out; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci dlen -= h; 6262306a36Sopenharmony_ci dst += h; 6362306a36Sopenharmony_ci counter = cpu_to_be32(be32_to_cpu(counter) + 1); 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciout: 6762306a36Sopenharmony_ci if (err) 6862306a36Sopenharmony_ci memzero_explicit(dst_orig, dlen_orig); 6962306a36Sopenharmony_ci shash_desc_zero(desc); 7062306a36Sopenharmony_ci return err; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ciEXPORT_SYMBOL(crypto_kdf108_ctr_generate); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * The seeding of the KDF 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ciint crypto_kdf108_setkey(struct crypto_shash *kmd, 7862306a36Sopenharmony_ci const u8 *key, size_t keylen, 7962306a36Sopenharmony_ci const u8 *ikm, size_t ikmlen) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci unsigned int ds = crypto_shash_digestsize(kmd); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* SP800-108 does not support IKM */ 8462306a36Sopenharmony_ci if (ikm || ikmlen) 8562306a36Sopenharmony_ci return -EINVAL; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* Check according to SP800-108 section 7.2 */ 8862306a36Sopenharmony_ci if (ds > keylen) 8962306a36Sopenharmony_ci return -EINVAL; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* Set the key for the MAC used for the KDF. */ 9262306a36Sopenharmony_ci return crypto_shash_setkey(kmd, key, keylen); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ciEXPORT_SYMBOL(crypto_kdf108_setkey); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * Test vector obtained from 9862306a36Sopenharmony_ci * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/CounterMode.zip 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_cistatic const struct kdf_testvec kdf_ctr_hmac_sha256_tv_template[] = { 10162306a36Sopenharmony_ci { 10262306a36Sopenharmony_ci .key = "\xdd\x1d\x91\xb7\xd9\x0b\x2b\xd3" 10362306a36Sopenharmony_ci "\x13\x85\x33\xce\x92\xb2\x72\xfb" 10462306a36Sopenharmony_ci "\xf8\xa3\x69\x31\x6a\xef\xe2\x42" 10562306a36Sopenharmony_ci "\xe6\x59\xcc\x0a\xe2\x38\xaf\xe0", 10662306a36Sopenharmony_ci .keylen = 32, 10762306a36Sopenharmony_ci .ikm = NULL, 10862306a36Sopenharmony_ci .ikmlen = 0, 10962306a36Sopenharmony_ci .info = { 11062306a36Sopenharmony_ci .iov_base = "\x01\x32\x2b\x96\xb3\x0a\xcd\x19" 11162306a36Sopenharmony_ci "\x79\x79\x44\x4e\x46\x8e\x1c\x5c" 11262306a36Sopenharmony_ci "\x68\x59\xbf\x1b\x1c\xf9\x51\xb7" 11362306a36Sopenharmony_ci "\xe7\x25\x30\x3e\x23\x7e\x46\xb8" 11462306a36Sopenharmony_ci "\x64\xa1\x45\xfa\xb2\x5e\x51\x7b" 11562306a36Sopenharmony_ci "\x08\xf8\x68\x3d\x03\x15\xbb\x29" 11662306a36Sopenharmony_ci "\x11\xd8\x0a\x0e\x8a\xba\x17\xf3" 11762306a36Sopenharmony_ci "\xb4\x13\xfa\xac", 11862306a36Sopenharmony_ci .iov_len = 60 11962306a36Sopenharmony_ci }, 12062306a36Sopenharmony_ci .expected = "\x10\x62\x13\x42\xbf\xb0\xfd\x40" 12162306a36Sopenharmony_ci "\x04\x6c\x0e\x29\xf2\xcf\xdb\xf0", 12262306a36Sopenharmony_ci .expectedlen = 16 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int __init crypto_kdf108_init(void) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int ret; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS)) 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci ret = kdf_test(&kdf_ctr_hmac_sha256_tv_template[0], "hmac(sha256)", 13462306a36Sopenharmony_ci crypto_kdf108_setkey, crypto_kdf108_ctr_generate); 13562306a36Sopenharmony_ci if (ret) { 13662306a36Sopenharmony_ci if (fips_enabled) 13762306a36Sopenharmony_ci panic("alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", 13862306a36Sopenharmony_ci ret); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci WARN(1, 14162306a36Sopenharmony_ci "alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", 14262306a36Sopenharmony_ci ret); 14362306a36Sopenharmony_ci } else if (fips_enabled) { 14462306a36Sopenharmony_ci pr_info("alg: self-tests for CTR-KDF (hmac(sha256)) passed\n"); 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return ret; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic void __exit crypto_kdf108_exit(void) { } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cimodule_init(crypto_kdf108_init); 15362306a36Sopenharmony_cimodule_exit(crypto_kdf108_exit); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 15662306a36Sopenharmony_ciMODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); 15762306a36Sopenharmony_ciMODULE_DESCRIPTION("Key Derivation Function conformant to SP800-108"); 158