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