xref: /linux/crypto/krb5enc.c (revision d1775a177f7f38156d541c8a3e3c91eaa6e69699)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * AEAD wrapper for Kerberos 5 RFC3961 simplified profile.
4  *
5  * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
6  * Written by David Howells (dhowells@redhat.com)
7  *
8  * Derived from authenc:
9  * Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au>
10  */
11 
12 #include <crypto/internal/aead.h>
13 #include <crypto/internal/hash.h>
14 #include <crypto/internal/skcipher.h>
15 #include <crypto/authenc.h>
16 #include <crypto/scatterwalk.h>
17 #include <linux/err.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/rtnetlink.h>
22 #include <linux/slab.h>
23 #include <linux/spinlock.h>
24 
25 struct krb5enc_instance_ctx {
26 	struct crypto_ahash_spawn auth;
27 	struct crypto_skcipher_spawn enc;
28 	unsigned int reqoff;
29 };
30 
31 struct krb5enc_ctx {
32 	struct crypto_ahash *auth;
33 	struct crypto_skcipher *enc;
34 };
35 
36 struct krb5enc_request_ctx {
37 	struct scatterlist src[2];
38 	struct scatterlist dst[2];
39 	char tail[];
40 };
41 
42 static void krb5enc_request_complete(struct aead_request *req, int err)
43 {
44 	if (err != -EINPROGRESS)
45 		aead_request_complete(req, err);
46 }
47 
48 /**
49  * crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob.
50  * @keys: Where to put the key sizes and pointers
51  * @key: Encoded key material
52  * @keylen: Amount of key material
53  *
54  * Decode the key blob we're given.  It starts with an rtattr that indicates
55  * the format and the length.  Format CRYPTO_AUTHENC_KEYA_PARAM is:
56  *
57  *	rtattr || __be32 enckeylen || authkey || enckey
58  *
59  * Note that the rtattr is in cpu-endian form, unlike enckeylen.  This must be
60  * handled correctly in static testmgr data.
61  */
62 int crypto_krb5enc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key,
63 			       unsigned int keylen)
64 {
65 	struct rtattr *rta = (struct rtattr *)key;
66 	struct crypto_authenc_key_param *param;
67 
68 	if (!RTA_OK(rta, keylen))
69 		return -EINVAL;
70 	if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
71 		return -EINVAL;
72 
73 	/*
74 	 * RTA_OK() didn't align the rtattr's payload when validating that it
75 	 * fits in the buffer.  Yet, the keys should start on the next 4-byte
76 	 * aligned boundary.  To avoid confusion, require that the rtattr
77 	 * payload be exactly the param struct, which has a 4-byte aligned size.
78 	 */
79 	if (RTA_PAYLOAD(rta) != sizeof(*param))
80 		return -EINVAL;
81 	BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO);
82 
83 	param = RTA_DATA(rta);
84 	keys->enckeylen = be32_to_cpu(param->enckeylen);
85 
86 	key += rta->rta_len;
87 	keylen -= rta->rta_len;
88 
89 	if (keylen < keys->enckeylen)
90 		return -EINVAL;
91 
92 	keys->authkeylen = keylen - keys->enckeylen;
93 	keys->authkey = key;
94 	keys->enckey = key + keys->authkeylen;
95 	return 0;
96 }
97 EXPORT_SYMBOL(crypto_krb5enc_extractkeys);
98 
99 static int krb5enc_setkey(struct crypto_aead *krb5enc, const u8 *key,
100 			  unsigned int keylen)
101 {
102 	struct crypto_authenc_keys keys;
103 	struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
104 	struct crypto_skcipher *enc = ctx->enc;
105 	struct crypto_ahash *auth = ctx->auth;
106 	unsigned int flags = crypto_aead_get_flags(krb5enc);
107 	int err = -EINVAL;
108 
109 	if (crypto_krb5enc_extractkeys(&keys, key, keylen) != 0)
110 		goto out;
111 
112 	crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
113 	crypto_ahash_set_flags(auth, flags & CRYPTO_TFM_REQ_MASK);
114 	err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
115 	if (err)
116 		goto out;
117 
118 	crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
119 	crypto_skcipher_set_flags(enc, flags & CRYPTO_TFM_REQ_MASK);
120 	err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
121 out:
122 	memzero_explicit(&keys, sizeof(keys));
123 	return err;
124 }
125 
126 static void krb5enc_encrypt_done(void *data, int err)
127 {
128 	struct aead_request *req = data;
129 
130 	krb5enc_request_complete(req, err);
131 }
132 
133 /*
134  * Start the encryption of the plaintext.  We skip over the associated data as
135  * that only gets included in the hash.
136  */
137 static int krb5enc_dispatch_encrypt(struct aead_request *req,
138 				    unsigned int flags)
139 {
140 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
141 	struct aead_instance *inst = aead_alg_instance(krb5enc);
142 	struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
143 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
144 	struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
145 	struct crypto_skcipher *enc = ctx->enc;
146 	struct skcipher_request *skreq = (void *)(areq_ctx->tail +
147 						  ictx->reqoff);
148 	struct scatterlist *src, *dst;
149 
150 	src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen);
151 	if (req->src == req->dst)
152 		dst = src;
153 	else
154 		dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
155 
156 	skcipher_request_set_tfm(skreq, enc);
157 	skcipher_request_set_callback(skreq, aead_request_flags(req),
158 				      krb5enc_encrypt_done, req);
159 	skcipher_request_set_crypt(skreq, src, dst, req->cryptlen, req->iv);
160 
161 	return crypto_skcipher_encrypt(skreq);
162 }
163 
164 /*
165  * Insert the hash into the checksum field in the destination buffer directly
166  * after the encrypted region.
167  */
168 static void krb5enc_insert_checksum(struct aead_request *req, u8 *hash)
169 {
170 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
171 
172 	scatterwalk_map_and_copy(hash, req->dst,
173 				 req->assoclen + req->cryptlen,
174 				 crypto_aead_authsize(krb5enc), 1);
175 }
176 
177 /*
178  * Upon completion of an asynchronous digest, transfer the hash to the checksum
179  * field.
180  */
181 static void krb5enc_encrypt_ahash_done(void *data, int err)
182 {
183 	struct aead_request *req = data;
184 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
185 	struct aead_instance *inst = aead_alg_instance(krb5enc);
186 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
187 	struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
188 	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
189 
190 	if (err)
191 		return krb5enc_request_complete(req, err);
192 
193 	krb5enc_insert_checksum(req, ahreq->result);
194 
195 	err = krb5enc_dispatch_encrypt(req, 0);
196 	if (err != -EINPROGRESS)
197 		aead_request_complete(req, err);
198 }
199 
200 /*
201  * Start the digest of the plaintext for encryption.  In theory, this could be
202  * run in parallel with the encryption, provided the src and dst buffers don't
203  * overlap.
204  */
205 static int krb5enc_dispatch_encrypt_hash(struct aead_request *req)
206 {
207 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
208 	struct aead_instance *inst = aead_alg_instance(krb5enc);
209 	struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
210 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
211 	struct crypto_ahash *auth = ctx->auth;
212 	struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
213 	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
214 	u8 *hash = areq_ctx->tail;
215 	int err;
216 
217 	ahash_request_set_callback(ahreq, aead_request_flags(req),
218 				   krb5enc_encrypt_ahash_done, req);
219 	ahash_request_set_tfm(ahreq, auth);
220 	ahash_request_set_crypt(ahreq, req->src, hash, req->assoclen + req->cryptlen);
221 
222 	err = crypto_ahash_digest(ahreq);
223 	if (err)
224 		return err;
225 
226 	krb5enc_insert_checksum(req, hash);
227 	return 0;
228 }
229 
230 /*
231  * Process an encryption operation.  We can perform the cipher and the hash in
232  * parallel, provided the src and dst buffers are separate.
233  */
234 static int krb5enc_encrypt(struct aead_request *req)
235 {
236 	int err;
237 
238 	err = krb5enc_dispatch_encrypt_hash(req);
239 	if (err < 0)
240 		return err;
241 
242 	return krb5enc_dispatch_encrypt(req, aead_request_flags(req));
243 }
244 
245 static int krb5enc_verify_hash(struct aead_request *req)
246 {
247 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
248 	struct aead_instance *inst = aead_alg_instance(krb5enc);
249 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
250 	struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
251 	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
252 	unsigned int authsize = crypto_aead_authsize(krb5enc);
253 	u8 *calc_hash = areq_ctx->tail;
254 	u8 *msg_hash  = areq_ctx->tail + authsize;
255 
256 	scatterwalk_map_and_copy(msg_hash, req->src, ahreq->nbytes, authsize, 0);
257 
258 	if (crypto_memneq(msg_hash, calc_hash, authsize))
259 		return -EBADMSG;
260 	return 0;
261 }
262 
263 static void krb5enc_decrypt_hash_done(void *data, int err)
264 {
265 	struct aead_request *req = data;
266 
267 	if (err)
268 		return krb5enc_request_complete(req, err);
269 
270 	err = krb5enc_verify_hash(req);
271 	krb5enc_request_complete(req, err);
272 }
273 
274 /*
275  * Dispatch the hashing of the plaintext after we've done the decryption.
276  */
277 static int krb5enc_dispatch_decrypt_hash(struct aead_request *req)
278 {
279 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
280 	struct aead_instance *inst = aead_alg_instance(krb5enc);
281 	struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
282 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
283 	struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
284 	struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
285 	struct crypto_ahash *auth = ctx->auth;
286 	unsigned int authsize = crypto_aead_authsize(krb5enc);
287 	u8 *hash = areq_ctx->tail;
288 	int err;
289 
290 	ahash_request_set_tfm(ahreq, auth);
291 	ahash_request_set_crypt(ahreq, req->dst, hash,
292 				req->assoclen + req->cryptlen - authsize);
293 	ahash_request_set_callback(ahreq, aead_request_flags(req),
294 				   krb5enc_decrypt_hash_done, req);
295 
296 	err = crypto_ahash_digest(ahreq);
297 	if (err < 0)
298 		return err;
299 
300 	return krb5enc_verify_hash(req);
301 }
302 
303 /*
304  * Dispatch the decryption of the ciphertext.
305  */
306 static int krb5enc_dispatch_decrypt(struct aead_request *req)
307 {
308 	struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
309 	struct aead_instance *inst = aead_alg_instance(krb5enc);
310 	struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
311 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
312 	struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
313 	struct skcipher_request *skreq = (void *)(areq_ctx->tail +
314 						  ictx->reqoff);
315 	unsigned int authsize = crypto_aead_authsize(krb5enc);
316 	struct scatterlist *src, *dst;
317 
318 	src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen);
319 	dst = src;
320 
321 	if (req->src != req->dst)
322 		dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
323 
324 	skcipher_request_set_tfm(skreq, ctx->enc);
325 	skcipher_request_set_callback(skreq, aead_request_flags(req),
326 				      req->base.complete, req->base.data);
327 	skcipher_request_set_crypt(skreq, src, dst,
328 				   req->cryptlen - authsize, req->iv);
329 
330 	return crypto_skcipher_decrypt(skreq);
331 }
332 
333 static int krb5enc_decrypt(struct aead_request *req)
334 {
335 	int err;
336 
337 	err = krb5enc_dispatch_decrypt(req);
338 	if (err < 0)
339 		return err;
340 
341 	return krb5enc_dispatch_decrypt_hash(req);
342 }
343 
344 static int krb5enc_init_tfm(struct crypto_aead *tfm)
345 {
346 	struct aead_instance *inst = aead_alg_instance(tfm);
347 	struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
348 	struct krb5enc_ctx *ctx = crypto_aead_ctx(tfm);
349 	struct crypto_ahash *auth;
350 	struct crypto_skcipher *enc;
351 	int err;
352 
353 	auth = crypto_spawn_ahash(&ictx->auth);
354 	if (IS_ERR(auth))
355 		return PTR_ERR(auth);
356 
357 	enc = crypto_spawn_skcipher(&ictx->enc);
358 	err = PTR_ERR(enc);
359 	if (IS_ERR(enc))
360 		goto err_free_ahash;
361 
362 	ctx->auth = auth;
363 	ctx->enc = enc;
364 
365 	crypto_aead_set_reqsize(
366 		tfm,
367 		sizeof(struct krb5enc_request_ctx) +
368 		ictx->reqoff + /* Space for two checksums */
369 		umax(sizeof(struct ahash_request) + crypto_ahash_reqsize(auth),
370 		     sizeof(struct skcipher_request) + crypto_skcipher_reqsize(enc)));
371 
372 	return 0;
373 
374 err_free_ahash:
375 	crypto_free_ahash(auth);
376 	return err;
377 }
378 
379 static void krb5enc_exit_tfm(struct crypto_aead *tfm)
380 {
381 	struct krb5enc_ctx *ctx = crypto_aead_ctx(tfm);
382 
383 	crypto_free_ahash(ctx->auth);
384 	crypto_free_skcipher(ctx->enc);
385 }
386 
387 static void krb5enc_free(struct aead_instance *inst)
388 {
389 	struct krb5enc_instance_ctx *ctx = aead_instance_ctx(inst);
390 
391 	crypto_drop_skcipher(&ctx->enc);
392 	crypto_drop_ahash(&ctx->auth);
393 	kfree(inst);
394 }
395 
396 /*
397  * Create an instance of a template for a specific hash and cipher pair.
398  */
399 static int krb5enc_create(struct crypto_template *tmpl, struct rtattr **tb)
400 {
401 	struct krb5enc_instance_ctx *ictx;
402 	struct skcipher_alg_common *enc;
403 	struct hash_alg_common *auth;
404 	struct aead_instance *inst;
405 	struct crypto_alg *auth_base;
406 	u32 mask;
407 	int err;
408 
409 	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
410 	if (err) {
411 		pr_err("attr_type failed\n");
412 		return err;
413 	}
414 
415 	inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
416 	if (!inst)
417 		return -ENOMEM;
418 	ictx = aead_instance_ctx(inst);
419 
420 	err = crypto_grab_ahash(&ictx->auth, aead_crypto_instance(inst),
421 				crypto_attr_alg_name(tb[1]), 0, mask);
422 	if (err) {
423 		pr_err("grab ahash failed\n");
424 		goto err_free_inst;
425 	}
426 	auth = crypto_spawn_ahash_alg(&ictx->auth);
427 	auth_base = &auth->base;
428 
429 	err = crypto_grab_skcipher(&ictx->enc, aead_crypto_instance(inst),
430 				   crypto_attr_alg_name(tb[2]), 0, mask);
431 	if (err) {
432 		pr_err("grab skcipher failed\n");
433 		goto err_free_inst;
434 	}
435 	enc = crypto_spawn_skcipher_alg_common(&ictx->enc);
436 
437 	ictx->reqoff = 2 * auth->digestsize;
438 
439 	err = -ENAMETOOLONG;
440 	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
441 		     "krb5enc(%s,%s)", auth_base->cra_name,
442 		     enc->base.cra_name) >=
443 	    CRYPTO_MAX_ALG_NAME)
444 		goto err_free_inst;
445 
446 	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
447 		     "krb5enc(%s,%s)", auth_base->cra_driver_name,
448 		     enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
449 		goto err_free_inst;
450 
451 	inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
452 				      auth_base->cra_priority;
453 	inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
454 	inst->alg.base.cra_alignmask = enc->base.cra_alignmask;
455 	inst->alg.base.cra_ctxsize = sizeof(struct krb5enc_ctx);
456 
457 	inst->alg.ivsize = enc->ivsize;
458 	inst->alg.chunksize = enc->chunksize;
459 	inst->alg.maxauthsize = auth->digestsize;
460 
461 	inst->alg.init = krb5enc_init_tfm;
462 	inst->alg.exit = krb5enc_exit_tfm;
463 
464 	inst->alg.setkey = krb5enc_setkey;
465 	inst->alg.encrypt = krb5enc_encrypt;
466 	inst->alg.decrypt = krb5enc_decrypt;
467 
468 	inst->free = krb5enc_free;
469 
470 	err = aead_register_instance(tmpl, inst);
471 	if (err) {
472 		pr_err("ref failed\n");
473 		goto err_free_inst;
474 	}
475 
476 	return 0;
477 
478 err_free_inst:
479 	krb5enc_free(inst);
480 	return err;
481 }
482 
483 static struct crypto_template crypto_krb5enc_tmpl = {
484 	.name = "krb5enc",
485 	.create = krb5enc_create,
486 	.module = THIS_MODULE,
487 };
488 
489 static int __init crypto_krb5enc_module_init(void)
490 {
491 	return crypto_register_template(&crypto_krb5enc_tmpl);
492 }
493 
494 static void __exit crypto_krb5enc_module_exit(void)
495 {
496 	crypto_unregister_template(&crypto_krb5enc_tmpl);
497 }
498 
499 subsys_initcall(crypto_krb5enc_module_init);
500 module_exit(crypto_krb5enc_module_exit);
501 
502 MODULE_LICENSE("GPL");
503 MODULE_DESCRIPTION("Simple AEAD wrapper for Kerberos 5 RFC3961");
504 MODULE_ALIAS_CRYPTO("krb5enc");
505