]>
Commit | Line | Data |
---|---|---|
026a733e SM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | /* | |
4 | * SP800-108 Key-derivation function | |
5 | * | |
6 | * Copyright (C) 2021, Stephan Mueller <[email protected]> | |
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 | { | |
0bf365c0 | 128 | int ret; |
026a733e | 129 | |
0bf365c0 EB |
130 | if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS)) |
131 | return 0; | |
132 | ||
133 | ret = kdf_test(&kdf_ctr_hmac_sha256_tv_template[0], "hmac(sha256)", | |
134 | crypto_kdf108_setkey, crypto_kdf108_ctr_generate); | |
026a733e SM |
135 | if (ret) { |
136 | if (fips_enabled) | |
137 | panic("alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", | |
138 | ret); | |
139 | ||
140 | WARN(1, | |
141 | "alg: self-tests for CTR-KDF (hmac(sha256)) failed (rc=%d)\n", | |
142 | ret); | |
790c4c9f | 143 | } else if (fips_enabled) { |
026a733e SM |
144 | pr_info("alg: self-tests for CTR-KDF (hmac(sha256)) passed\n"); |
145 | } | |
146 | ||
147 | return ret; | |
148 | } | |
149 | ||
150 | static void __exit crypto_kdf108_exit(void) { } | |
151 | ||
152 | module_init(crypto_kdf108_init); | |
153 | module_exit(crypto_kdf108_exit); | |
154 | ||
155 | MODULE_LICENSE("GPL v2"); | |
156 | MODULE_AUTHOR("Stephan Mueller <[email protected]>"); | |
157 | MODULE_DESCRIPTION("Key Derivation Function conformant to SP800-108"); |