1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* rfc6803 Camellia Encryption for Kerberos 5
3  *
4  * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7 
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/slab.h>
11 #include "internal.h"
12 
13 /*
14  * Calculate the key derivation function KDF-FEEDBACK_CMAC(key, constant)
15  *
16  *	n = ceiling(k / 128)
17  *	K(0) = zeros
18  *	K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
19  *	DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n))
20  *	KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant))
21  *
22  *	[rfc6803 sec 3]
23  */
rfc6803_calc_KDF_FEEDBACK_CMAC(const struct krb5_enctype * krb5,const struct krb5_buffer * key,const struct krb5_buffer * constant,struct krb5_buffer * result,gfp_t gfp)24 static int rfc6803_calc_KDF_FEEDBACK_CMAC(const struct krb5_enctype *krb5,
25 					  const struct krb5_buffer *key,
26 					  const struct krb5_buffer *constant,
27 					  struct krb5_buffer *result,
28 					  gfp_t gfp)
29 {
30 	struct crypto_shash *shash;
31 	struct krb5_buffer K, data;
32 	struct shash_desc *desc;
33 	__be32 tmp;
34 	size_t bsize, offset, seg;
35 	void *buffer;
36 	u32 i = 0, k = result->len * 8;
37 	u8 *p;
38 	int ret = -ENOMEM;
39 
40 	shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
41 	if (IS_ERR(shash))
42 		return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
43 	ret = crypto_shash_setkey(shash, key->data, key->len);
44 	if (ret < 0)
45 		goto error_shash;
46 
47 	ret = -ENOMEM;
48 	K.len = crypto_shash_digestsize(shash);
49 	data.len = K.len + 4 + constant->len + 1 + 4;
50 	bsize = krb5_shash_size(shash) +
51 		krb5_digest_size(shash) +
52 		crypto_roundup(K.len) +
53 		crypto_roundup(data.len);
54 	buffer = kzalloc(bsize, GFP_NOFS);
55 	if (!buffer)
56 		goto error_shash;
57 
58 	desc = buffer;
59 	desc->tfm = shash;
60 
61 	K.data = buffer +
62 		krb5_shash_size(shash) +
63 		krb5_digest_size(shash);
64 	data.data = buffer +
65 		krb5_shash_size(shash) +
66 		krb5_digest_size(shash) +
67 		crypto_roundup(K.len);
68 
69 	p = data.data + K.len + 4;
70 	memcpy(p, constant->data, constant->len);
71 	p += constant->len;
72 	*p++ = 0x00;
73 	tmp = htonl(k);
74 	memcpy(p, &tmp, 4);
75 	p += 4;
76 
77 	ret = -EINVAL;
78 	if (WARN_ON(p - (u8 *)data.data != data.len))
79 		goto error;
80 
81 	offset = 0;
82 	do {
83 		i++;
84 		p = data.data;
85 		memcpy(p, K.data, K.len);
86 		p += K.len;
87 		*(__be32 *)p = htonl(i);
88 
89 		ret = crypto_shash_init(desc);
90 		if (ret < 0)
91 			goto error;
92 		ret = crypto_shash_finup(desc, data.data, data.len, K.data);
93 		if (ret < 0)
94 			goto error;
95 
96 		seg = min_t(size_t, result->len - offset, K.len);
97 		memcpy(result->data + offset, K.data, seg);
98 		offset += seg;
99 	} while (offset < result->len);
100 
101 error:
102 	kfree_sensitive(buffer);
103 error_shash:
104 	crypto_free_shash(shash);
105 	return ret;
106 }
107 
108 /*
109  * Calculate the pseudo-random function, PRF().
110  *
111  *	Kp = KDF-FEEDBACK-CMAC(protocol-key, "prf")
112  *	PRF = CMAC(Kp, octet-string)
113  *      [rfc6803 sec 6]
114  */
rfc6803_calc_PRF(const struct krb5_enctype * krb5,const struct krb5_buffer * protocol_key,const struct krb5_buffer * octet_string,struct krb5_buffer * result,gfp_t gfp)115 static int rfc6803_calc_PRF(const struct krb5_enctype *krb5,
116 			    const struct krb5_buffer *protocol_key,
117 			    const struct krb5_buffer *octet_string,
118 			    struct krb5_buffer *result,
119 			    gfp_t gfp)
120 {
121 	static const struct krb5_buffer prfconstant = { 3, "prf" };
122 	struct crypto_shash *shash;
123 	struct krb5_buffer Kp;
124 	struct shash_desc *desc;
125 	size_t bsize;
126 	void *buffer;
127 	int ret;
128 
129 	Kp.len = krb5->prf_len;
130 
131 	shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
132 	if (IS_ERR(shash))
133 		return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
134 
135 	ret = -EINVAL;
136 	if (result->len != crypto_shash_digestsize(shash))
137 		goto out_shash;
138 
139 	ret = -ENOMEM;
140 	bsize = krb5_shash_size(shash) +
141 		krb5_digest_size(shash) +
142 		crypto_roundup(Kp.len);
143 	buffer = kzalloc(bsize, GFP_NOFS);
144 	if (!buffer)
145 		goto out_shash;
146 
147 	Kp.data = buffer +
148 		krb5_shash_size(shash) +
149 		krb5_digest_size(shash);
150 
151 	ret = rfc6803_calc_KDF_FEEDBACK_CMAC(krb5, protocol_key, &prfconstant,
152 					     &Kp, gfp);
153 	if (ret < 0)
154 		goto out;
155 
156 	ret = crypto_shash_setkey(shash, Kp.data, Kp.len);
157 	if (ret < 0)
158 		goto out;
159 
160 	desc = buffer;
161 	desc->tfm = shash;
162 	ret = crypto_shash_init(desc);
163 	if (ret < 0)
164 		goto out;
165 
166 	ret = crypto_shash_finup(desc, octet_string->data, octet_string->len, result->data);
167 	if (ret < 0)
168 		goto out;
169 
170 out:
171 	kfree_sensitive(buffer);
172 out_shash:
173 	crypto_free_shash(shash);
174 	return ret;
175 }
176 
177 
178 static const struct krb5_crypto_profile rfc6803_crypto_profile = {
179 	.calc_PRF		= rfc6803_calc_PRF,
180 	.calc_Kc		= rfc6803_calc_KDF_FEEDBACK_CMAC,
181 	.calc_Ke		= rfc6803_calc_KDF_FEEDBACK_CMAC,
182 	.calc_Ki		= rfc6803_calc_KDF_FEEDBACK_CMAC,
183 	.derive_encrypt_keys	= authenc_derive_encrypt_keys,
184 	.load_encrypt_keys	= authenc_load_encrypt_keys,
185 	.derive_checksum_key	= rfc3961_derive_checksum_key,
186 	.load_checksum_key	= rfc3961_load_checksum_key,
187 	.encrypt		= krb5_aead_encrypt,
188 	.decrypt		= krb5_aead_decrypt,
189 	.get_mic		= rfc3961_get_mic,
190 	.verify_mic		= rfc3961_verify_mic,
191 };
192 
193 const struct krb5_enctype krb5_camellia128_cts_cmac = {
194 	.etype		= KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
195 	.ctype		= KRB5_CKSUMTYPE_CMAC_CAMELLIA128,
196 	.name		= "camellia128-cts-cmac",
197 	.encrypt_name	= "krb5enc(cmac(camellia),cts(cbc(camellia)))",
198 	.cksum_name	= "cmac(camellia)",
199 	.hash_name	= NULL,
200 	.derivation_enc	= "cts(cbc(camellia))",
201 	.key_bytes	= 16,
202 	.key_len	= 16,
203 	.Kc_len		= 16,
204 	.Ke_len		= 16,
205 	.Ki_len		= 16,
206 	.block_len	= 16,
207 	.conf_len	= 16,
208 	.cksum_len	= 16,
209 	.hash_len	= 16,
210 	.prf_len	= 16,
211 	.keyed_cksum	= true,
212 	.random_to_key	= NULL, /* Identity */
213 	.profile	= &rfc6803_crypto_profile,
214 };
215 
216 const struct krb5_enctype krb5_camellia256_cts_cmac = {
217 	.etype		= KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
218 	.ctype		= KRB5_CKSUMTYPE_CMAC_CAMELLIA256,
219 	.name		= "camellia256-cts-cmac",
220 	.encrypt_name	= "krb5enc(cmac(camellia),cts(cbc(camellia)))",
221 	.cksum_name	= "cmac(camellia)",
222 	.hash_name	= NULL,
223 	.derivation_enc	= "cts(cbc(camellia))",
224 	.key_bytes	= 32,
225 	.key_len	= 32,
226 	.Kc_len		= 32,
227 	.Ke_len		= 32,
228 	.Ki_len		= 32,
229 	.block_len	= 16,
230 	.conf_len	= 16,
231 	.cksum_len	= 16,
232 	.hash_len	= 16,
233 	.prf_len	= 16,
234 	.keyed_cksum	= true,
235 	.random_to_key	= NULL, /* Identity */
236 	.profile	= &rfc6803_crypto_profile,
237 };
238