xref: /linux/crypto/krb5/rfc3961_simplified.c (revision fc4bd01d9ff592f620c499686245c093440db0e8)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* rfc3961 Kerberos 5 simplified crypto profile.
3  *
4  * Parts borrowed from net/sunrpc/auth_gss/.
5  */
6 /*
7  * COPYRIGHT (c) 2008
8  * The Regents of the University of Michigan
9  * ALL RIGHTS RESERVED
10  *
11  * Permission is granted to use, copy, create derivative works
12  * and redistribute this software and such derivative works
13  * for any purpose, so long as the name of The University of
14  * Michigan is not used in any advertising or publicity
15  * pertaining to the use of distribution of this software
16  * without specific, written prior authorization.  If the
17  * above copyright notice or any other identification of the
18  * University of Michigan is included in any copy of any
19  * portion of this software, then the disclaimer below must
20  * also be included.
21  *
22  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
23  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
24  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
25  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
26  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
27  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
28  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
29  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
30  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
31  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
32  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGES.
34  */
35 
36 /*
37  * Copyright (C) 1998 by the FundsXpress, INC.
38  *
39  * All rights reserved.
40  *
41  * Export of this software from the United States of America may require
42  * a specific license from the United States Government.  It is the
43  * responsibility of any person or organization contemplating export to
44  * obtain such a license before exporting.
45  *
46  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
47  * distribute this software and its documentation for any purpose and
48  * without fee is hereby granted, provided that the above copyright
49  * notice appear in all copies and that both that copyright notice and
50  * this permission notice appear in supporting documentation, and that
51  * the name of FundsXpress. not be used in advertising or publicity pertaining
52  * to distribution of the software without specific, written prior
53  * permission.  FundsXpress makes no representations about the suitability of
54  * this software for any purpose.  It is provided "as is" without express
55  * or implied warranty.
56  *
57  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
58  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
59  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
60  */
61 
62 /*
63  * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
64  * Written by David Howells (dhowells@redhat.com)
65  */
66 
67 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
68 
69 #include <linux/random.h>
70 #include <linux/skbuff.h>
71 #include <linux/slab.h>
72 #include <linux/highmem.h>
73 #include <linux/lcm.h>
74 #include <linux/rtnetlink.h>
75 #include <crypto/authenc.h>
76 #include <crypto/skcipher.h>
77 #include <crypto/hash.h>
78 #include "internal.h"
79 
80 /* Maximum blocksize for the supported crypto algorithms */
81 #define KRB5_MAX_BLOCKSIZE  (16)
82 
83 int crypto_shash_update_sg(struct shash_desc *desc, struct scatterlist *sg,
84 			   size_t offset, size_t len)
85 {
86 	do {
87 		int ret;
88 
89 		if (offset < sg->length) {
90 			struct page *page = sg_page(sg);
91 			void *p = kmap_local_page(page);
92 			void *q = p + sg->offset + offset;
93 			size_t seg = min_t(size_t, len, sg->length - offset);
94 
95 			ret = crypto_shash_update(desc, q, seg);
96 			kunmap_local(p);
97 			if (ret < 0)
98 				return ret;
99 			len -= seg;
100 			offset = 0;
101 		} else {
102 			offset -= sg->length;
103 		}
104 	} while (len > 0 && (sg = sg_next(sg)));
105 	return 0;
106 }
107 
108 static int rfc3961_do_encrypt(struct crypto_sync_skcipher *tfm, void *iv,
109 			      const struct krb5_buffer *in, struct krb5_buffer *out)
110 {
111 	struct scatterlist sg[1];
112 	u8 local_iv[KRB5_MAX_BLOCKSIZE] __aligned(KRB5_MAX_BLOCKSIZE) = {0};
113 	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
114 	int ret;
115 
116 	if (WARN_ON(in->len != out->len))
117 		return -EINVAL;
118 	if (out->len % crypto_sync_skcipher_blocksize(tfm) != 0)
119 		return -EINVAL;
120 
121 	if (crypto_sync_skcipher_ivsize(tfm) > KRB5_MAX_BLOCKSIZE)
122 		return -EINVAL;
123 
124 	if (iv)
125 		memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
126 
127 	memcpy(out->data, in->data, out->len);
128 	sg_init_one(sg, out->data, out->len);
129 
130 	skcipher_request_set_sync_tfm(req, tfm);
131 	skcipher_request_set_callback(req, 0, NULL, NULL);
132 	skcipher_request_set_crypt(req, sg, sg, out->len, local_iv);
133 
134 	ret = crypto_skcipher_encrypt(req);
135 	skcipher_request_zero(req);
136 	return ret;
137 }
138 
139 /*
140  * Calculate an unkeyed basic hash.
141  */
142 static int rfc3961_calc_H(const struct krb5_enctype *krb5,
143 			  const struct krb5_buffer *data,
144 			  struct krb5_buffer *digest,
145 			  gfp_t gfp)
146 {
147 	struct crypto_shash *tfm;
148 	struct shash_desc *desc;
149 	size_t desc_size;
150 	int ret = -ENOMEM;
151 
152 	tfm = crypto_alloc_shash(krb5->hash_name, 0, 0);
153 	if (IS_ERR(tfm))
154 		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
155 
156 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
157 
158 	desc = kzalloc(desc_size, gfp);
159 	if (!desc)
160 		goto error_tfm;
161 
162 	digest->len = crypto_shash_digestsize(tfm);
163 	digest->data = kzalloc(digest->len, gfp);
164 	if (!digest->data)
165 		goto error_desc;
166 
167 	desc->tfm = tfm;
168 	ret = crypto_shash_init(desc);
169 	if (ret < 0)
170 		goto error_digest;
171 
172 	ret = crypto_shash_finup(desc, data->data, data->len, digest->data);
173 	if (ret < 0)
174 		goto error_digest;
175 
176 	goto error_desc;
177 
178 error_digest:
179 	kfree_sensitive(digest->data);
180 error_desc:
181 	kfree_sensitive(desc);
182 error_tfm:
183 	crypto_free_shash(tfm);
184 	return ret;
185 }
186 
187 /*
188  * This is the n-fold function as described in rfc3961, sec 5.1
189  * Taken from MIT Kerberos and modified.
190  */
191 static void rfc3961_nfold(const struct krb5_buffer *source, struct krb5_buffer *result)
192 {
193 	const u8 *in = source->data;
194 	u8 *out = result->data;
195 	unsigned long ulcm;
196 	unsigned int inbits, outbits;
197 	int byte, i, msbit;
198 
199 	/* the code below is more readable if I make these bytes instead of bits */
200 	inbits = source->len;
201 	outbits = result->len;
202 
203 	/* first compute lcm(n,k) */
204 	ulcm = lcm(inbits, outbits);
205 
206 	/* now do the real work */
207 	memset(out, 0, outbits);
208 	byte = 0;
209 
210 	/* this will end up cycling through k lcm(k,n)/k times, which
211 	 * is correct.
212 	 */
213 	for (i = ulcm-1; i >= 0; i--) {
214 		/* compute the msbit in k which gets added into this byte */
215 		msbit = (
216 			/* first, start with the msbit in the first,
217 			 * unrotated byte
218 			 */
219 			((inbits << 3) - 1) +
220 			/* then, for each byte, shift to the right
221 			 * for each repetition
222 			 */
223 			(((inbits << 3) + 13) * (i/inbits)) +
224 			/* last, pick out the correct byte within
225 			 * that shifted repetition
226 			 */
227 			((inbits - (i % inbits)) << 3)
228 			 ) % (inbits << 3);
229 
230 		/* pull out the byte value itself */
231 		byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8) |
232 			  (in[((inbits)     - (msbit >> 3)) % inbits]))
233 			 >> ((msbit & 7) + 1)) & 0xff;
234 
235 		/* do the addition */
236 		byte += out[i % outbits];
237 		out[i % outbits] = byte & 0xff;
238 
239 		/* keep around the carry bit, if any */
240 		byte >>= 8;
241 	}
242 
243 	/* if there's a carry bit left over, add it back in */
244 	if (byte) {
245 		for (i = outbits - 1; i >= 0; i--) {
246 			/* do the addition */
247 			byte += out[i];
248 			out[i] = byte & 0xff;
249 
250 			/* keep around the carry bit, if any */
251 			byte >>= 8;
252 		}
253 	}
254 }
255 
256 /*
257  * Calculate a derived key, DK(Base Key, Well-Known Constant)
258  *
259  * DK(Key, Constant) = random-to-key(DR(Key, Constant))
260  * DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
261  * K1 = E(Key, n-fold(Constant), initial-cipher-state)
262  * K2 = E(Key, K1, initial-cipher-state)
263  * K3 = E(Key, K2, initial-cipher-state)
264  * K4 = ...
265  * DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
266  * [rfc3961 sec 5.1]
267  */
268 static int rfc3961_calc_DK(const struct krb5_enctype *krb5,
269 			   const struct krb5_buffer *inkey,
270 			   const struct krb5_buffer *in_constant,
271 			   struct krb5_buffer *result,
272 			   gfp_t gfp)
273 {
274 	unsigned int blocksize, keybytes, keylength, n;
275 	struct krb5_buffer inblock, outblock, rawkey;
276 	struct crypto_sync_skcipher *cipher;
277 	int ret = -EINVAL;
278 
279 	blocksize = krb5->block_len;
280 	keybytes = krb5->key_bytes;
281 	keylength = krb5->key_len;
282 
283 	if (inkey->len != keylength || result->len != keylength)
284 		return -EINVAL;
285 	if (!krb5->random_to_key && result->len != keybytes)
286 		return -EINVAL;
287 
288 	cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
289 	if (IS_ERR(cipher)) {
290 		ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
291 		goto err_return;
292 	}
293 	ret = crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len);
294 	if (ret < 0)
295 		goto err_free_cipher;
296 
297 	ret = -ENOMEM;
298 	inblock.data = kzalloc(blocksize * 2 + keybytes, gfp);
299 	if (!inblock.data)
300 		goto err_free_cipher;
301 
302 	inblock.len	= blocksize;
303 	outblock.data	= inblock.data + blocksize;
304 	outblock.len	= blocksize;
305 	rawkey.data	= outblock.data + blocksize;
306 	rawkey.len	= keybytes;
307 
308 	/* initialize the input block */
309 
310 	if (in_constant->len == inblock.len)
311 		memcpy(inblock.data, in_constant->data, inblock.len);
312 	else
313 		rfc3961_nfold(in_constant, &inblock);
314 
315 	/* loop encrypting the blocks until enough key bytes are generated */
316 	n = 0;
317 	while (n < rawkey.len) {
318 		rfc3961_do_encrypt(cipher, NULL, &inblock, &outblock);
319 
320 		if (keybytes - n <= outblock.len) {
321 			memcpy(rawkey.data + n, outblock.data, keybytes - n);
322 			break;
323 		}
324 
325 		memcpy(rawkey.data + n, outblock.data, outblock.len);
326 		memcpy(inblock.data, outblock.data, outblock.len);
327 		n += outblock.len;
328 	}
329 
330 	/* postprocess the key */
331 	if (!krb5->random_to_key) {
332 		/* Identity random-to-key function. */
333 		memcpy(result->data, rawkey.data, rawkey.len);
334 		ret = 0;
335 	} else {
336 		ret = krb5->random_to_key(krb5, &rawkey, result);
337 	}
338 
339 	kfree_sensitive(inblock.data);
340 err_free_cipher:
341 	crypto_free_sync_skcipher(cipher);
342 err_return:
343 	return ret;
344 }
345 
346 /*
347  * Calculate single encryption, E()
348  *
349  *	E(Key, octets)
350  */
351 static int rfc3961_calc_E(const struct krb5_enctype *krb5,
352 			  const struct krb5_buffer *key,
353 			  const struct krb5_buffer *in_data,
354 			  struct krb5_buffer *result,
355 			  gfp_t gfp)
356 {
357 	struct crypto_sync_skcipher *cipher;
358 	int ret;
359 
360 	cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
361 	if (IS_ERR(cipher)) {
362 		ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
363 		goto err;
364 	}
365 
366 	ret = crypto_sync_skcipher_setkey(cipher, key->data, key->len);
367 	if (ret < 0)
368 		goto err_free;
369 
370 	ret = rfc3961_do_encrypt(cipher, NULL, in_data, result);
371 
372 err_free:
373 	crypto_free_sync_skcipher(cipher);
374 err:
375 	return ret;
376 }
377 
378 /*
379  * Calculate the pseudo-random function, PRF().
380  *
381  *      tmp1 = H(octet-string)
382  *      tmp2 = truncate tmp1 to multiple of m
383  *      PRF = E(DK(protocol-key, prfconstant), tmp2, initial-cipher-state)
384  *
385  *      The "prfconstant" used in the PRF operation is the three-octet string
386  *      "prf".
387  *      [rfc3961 sec 5.3]
388  */
389 static int rfc3961_calc_PRF(const struct krb5_enctype *krb5,
390 			    const struct krb5_buffer *protocol_key,
391 			    const struct krb5_buffer *octet_string,
392 			    struct krb5_buffer *result,
393 			    gfp_t gfp)
394 {
395 	static const struct krb5_buffer prfconstant = { 3, "prf" };
396 	struct krb5_buffer derived_key;
397 	struct krb5_buffer tmp1, tmp2;
398 	unsigned int m = krb5->block_len;
399 	void *buffer;
400 	int ret;
401 
402 	if (result->len != krb5->prf_len)
403 		return -EINVAL;
404 
405 	tmp1.len = krb5->hash_len;
406 	derived_key.len = krb5->key_bytes;
407 	buffer = kzalloc(round16(tmp1.len) + round16(derived_key.len), gfp);
408 	if (!buffer)
409 		return -ENOMEM;
410 
411 	tmp1.data = buffer;
412 	derived_key.data = buffer + round16(tmp1.len);
413 
414 	ret = rfc3961_calc_H(krb5, octet_string, &tmp1, gfp);
415 	if (ret < 0)
416 		goto err;
417 
418 	tmp2.len = tmp1.len & ~(m - 1);
419 	tmp2.data = tmp1.data;
420 
421 	ret = rfc3961_calc_DK(krb5, protocol_key, &prfconstant, &derived_key, gfp);
422 	if (ret < 0)
423 		goto err;
424 
425 	ret = rfc3961_calc_E(krb5, &derived_key, &tmp2, result, gfp);
426 
427 err:
428 	kfree_sensitive(buffer);
429 	return ret;
430 }
431 
432 /*
433  * Derive the Ke and Ki keys and package them into a key parameter that can be
434  * given to the setkey of a authenc AEAD crypto object.
435  */
436 int authenc_derive_encrypt_keys(const struct krb5_enctype *krb5,
437 				const struct krb5_buffer *TK,
438 				unsigned int usage,
439 				struct krb5_buffer *setkey,
440 				gfp_t gfp)
441 {
442 	struct crypto_authenc_key_param *param;
443 	struct krb5_buffer Ke, Ki;
444 	struct rtattr *rta;
445 	int ret;
446 
447 	Ke.len  = krb5->Ke_len;
448 	Ki.len  = krb5->Ki_len;
449 	setkey->len = RTA_LENGTH(sizeof(*param)) + Ke.len + Ki.len;
450 	setkey->data = kzalloc(setkey->len, GFP_KERNEL);
451 	if (!setkey->data)
452 		return -ENOMEM;
453 
454 	rta = setkey->data;
455 	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
456 	rta->rta_len = RTA_LENGTH(sizeof(*param));
457 	param = RTA_DATA(rta);
458 	param->enckeylen = htonl(Ke.len);
459 
460 	Ki.data = (void *)(param + 1);
461 	Ke.data = Ki.data + Ki.len;
462 
463 	ret = krb5_derive_Ke(krb5, TK, usage, &Ke, gfp);
464 	if (ret < 0) {
465 		pr_err("get_Ke failed %d\n", ret);
466 		return ret;
467 	}
468 	ret = krb5_derive_Ki(krb5, TK, usage, &Ki, gfp);
469 	if (ret < 0)
470 		pr_err("get_Ki failed %d\n", ret);
471 	return ret;
472 }
473 
474 /*
475  * Package predefined Ke and Ki keys and into a key parameter that can be given
476  * to the setkey of an authenc AEAD crypto object.
477  */
478 int authenc_load_encrypt_keys(const struct krb5_enctype *krb5,
479 			      const struct krb5_buffer *Ke,
480 			      const struct krb5_buffer *Ki,
481 			      struct krb5_buffer *setkey,
482 			      gfp_t gfp)
483 {
484 	struct crypto_authenc_key_param *param;
485 	struct rtattr *rta;
486 
487 	setkey->len = RTA_LENGTH(sizeof(*param)) + Ke->len + Ki->len;
488 	setkey->data = kzalloc(setkey->len, GFP_KERNEL);
489 	if (!setkey->data)
490 		return -ENOMEM;
491 
492 	rta = setkey->data;
493 	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
494 	rta->rta_len = RTA_LENGTH(sizeof(*param));
495 	param = RTA_DATA(rta);
496 	param->enckeylen = htonl(Ke->len);
497 	memcpy((void *)(param + 1), Ki->data, Ki->len);
498 	memcpy((void *)(param + 1) + Ki->len, Ke->data, Ke->len);
499 	return 0;
500 }
501 
502 /*
503  * Derive the Kc key for checksum-only mode and package it into a key parameter
504  * that can be given to the setkey of a hash crypto object.
505  */
506 int rfc3961_derive_checksum_key(const struct krb5_enctype *krb5,
507 				const struct krb5_buffer *TK,
508 				unsigned int usage,
509 				struct krb5_buffer *setkey,
510 				gfp_t gfp)
511 {
512 	int ret;
513 
514 	setkey->len = krb5->Kc_len;
515 	setkey->data = kzalloc(setkey->len, GFP_KERNEL);
516 	if (!setkey->data)
517 		return -ENOMEM;
518 
519 	ret = krb5_derive_Kc(krb5, TK, usage, setkey, gfp);
520 	if (ret < 0)
521 		pr_err("get_Kc failed %d\n", ret);
522 	return ret;
523 }
524 
525 /*
526  * Package a predefined Kc key for checksum-only mode into a key parameter that
527  * can be given to the setkey of a hash crypto object.
528  */
529 int rfc3961_load_checksum_key(const struct krb5_enctype *krb5,
530 			      const struct krb5_buffer *Kc,
531 			      struct krb5_buffer *setkey,
532 			      gfp_t gfp)
533 {
534 	setkey->len = krb5->Kc_len;
535 	setkey->data = kmemdup(Kc->data, Kc->len, GFP_KERNEL);
536 	if (!setkey->data)
537 		return -ENOMEM;
538 	return 0;
539 }
540 
541 /*
542  * Apply encryption and checksumming functions to part of a scatterlist.
543  */
544 ssize_t krb5_aead_encrypt(const struct krb5_enctype *krb5,
545 			  struct crypto_aead *aead,
546 			  struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
547 			  size_t data_offset, size_t data_len,
548 			  bool preconfounded)
549 {
550 	struct aead_request *req;
551 	ssize_t ret, done;
552 	size_t bsize, base_len, secure_offset, secure_len, pad_len, cksum_offset;
553 	void *buffer;
554 	u8 *iv;
555 
556 	if (WARN_ON(data_offset != krb5->conf_len))
557 		return -EINVAL; /* Data is in wrong place */
558 
559 	secure_offset	= 0;
560 	base_len	= krb5->conf_len + data_len;
561 	pad_len		= 0;
562 	secure_len	= base_len + pad_len;
563 	cksum_offset	= secure_len;
564 	if (WARN_ON(cksum_offset + krb5->cksum_len > sg_len))
565 		return -EFAULT;
566 
567 	bsize = krb5_aead_size(aead) +
568 		krb5_aead_ivsize(aead);
569 	buffer = kzalloc(bsize, GFP_NOFS);
570 	if (!buffer)
571 		return -ENOMEM;
572 
573 	/* Insert the confounder into the buffer */
574 	ret = -EFAULT;
575 	if (!preconfounded) {
576 		get_random_bytes(buffer, krb5->conf_len);
577 		done = sg_pcopy_from_buffer(sg, nr_sg, buffer, krb5->conf_len,
578 					    secure_offset);
579 		if (done != krb5->conf_len)
580 			goto error;
581 	}
582 
583 	/* We may need to pad out to the crypto blocksize. */
584 	if (pad_len) {
585 		done = sg_zero_buffer(sg, nr_sg, pad_len, data_offset + data_len);
586 		if (done != pad_len)
587 			goto error;
588 	}
589 
590 	/* Hash and encrypt the message. */
591 	req = buffer;
592 	iv = buffer + krb5_aead_size(aead);
593 
594 	aead_request_set_tfm(req, aead);
595 	aead_request_set_callback(req, 0, NULL, NULL);
596 	aead_request_set_crypt(req, sg, sg, secure_len, iv);
597 	ret = crypto_aead_encrypt(req);
598 	if (ret < 0)
599 		goto error;
600 
601 	ret = secure_len + krb5->cksum_len;
602 
603 error:
604 	kfree_sensitive(buffer);
605 	return ret;
606 }
607 
608 /*
609  * Apply decryption and checksumming functions to a message.  The offset and
610  * length are updated to reflect the actual content of the encrypted region.
611  */
612 int krb5_aead_decrypt(const struct krb5_enctype *krb5,
613 		      struct crypto_aead *aead,
614 		      struct scatterlist *sg, unsigned int nr_sg,
615 		      size_t *_offset, size_t *_len)
616 {
617 	struct aead_request *req;
618 	size_t bsize;
619 	void *buffer;
620 	int ret;
621 	u8 *iv;
622 
623 	if (WARN_ON(*_offset != 0))
624 		return -EINVAL; /* Can't set offset on aead */
625 
626 	if (*_len < krb5->conf_len + krb5->cksum_len)
627 		return -EPROTO;
628 
629 	bsize = krb5_aead_size(aead) +
630 		krb5_aead_ivsize(aead);
631 	buffer = kzalloc(bsize, GFP_NOFS);
632 	if (!buffer)
633 		return -ENOMEM;
634 
635 	/* Decrypt the message and verify its checksum. */
636 	req = buffer;
637 	iv = buffer + krb5_aead_size(aead);
638 
639 	aead_request_set_tfm(req, aead);
640 	aead_request_set_callback(req, 0, NULL, NULL);
641 	aead_request_set_crypt(req, sg, sg, *_len, iv);
642 	ret = crypto_aead_decrypt(req);
643 	if (ret < 0)
644 		goto error;
645 
646 	/* Adjust the boundaries of the data. */
647 	*_offset += krb5->conf_len;
648 	*_len -= krb5->conf_len + krb5->cksum_len;
649 	ret = 0;
650 
651 error:
652 	kfree_sensitive(buffer);
653 	return ret;
654 }
655 
656 /*
657  * Generate a checksum over some metadata and part of an skbuff and insert the
658  * MIC into the skbuff immediately prior to the data.
659  */
660 ssize_t rfc3961_get_mic(const struct krb5_enctype *krb5,
661 			struct crypto_shash *shash,
662 			const struct krb5_buffer *metadata,
663 			struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
664 			size_t data_offset, size_t data_len)
665 {
666 	struct shash_desc *desc;
667 	ssize_t ret, done;
668 	size_t bsize;
669 	void *buffer, *digest;
670 
671 	if (WARN_ON(data_offset != krb5->cksum_len))
672 		return -EMSGSIZE;
673 
674 	bsize = krb5_shash_size(shash) +
675 		krb5_digest_size(shash);
676 	buffer = kzalloc(bsize, GFP_NOFS);
677 	if (!buffer)
678 		return -ENOMEM;
679 
680 	/* Calculate the MIC with key Kc and store it into the skb */
681 	desc = buffer;
682 	desc->tfm = shash;
683 	ret = crypto_shash_init(desc);
684 	if (ret < 0)
685 		goto error;
686 
687 	if (metadata) {
688 		ret = crypto_shash_update(desc, metadata->data, metadata->len);
689 		if (ret < 0)
690 			goto error;
691 	}
692 
693 	ret = crypto_shash_update_sg(desc, sg, data_offset, data_len);
694 	if (ret < 0)
695 		goto error;
696 
697 	digest = buffer + krb5_shash_size(shash);
698 	ret = crypto_shash_final(desc, digest);
699 	if (ret < 0)
700 		goto error;
701 
702 	ret = -EFAULT;
703 	done = sg_pcopy_from_buffer(sg, nr_sg, digest, krb5->cksum_len,
704 				    data_offset - krb5->cksum_len);
705 	if (done != krb5->cksum_len)
706 		goto error;
707 
708 	ret = krb5->cksum_len + data_len;
709 
710 error:
711 	kfree_sensitive(buffer);
712 	return ret;
713 }
714 
715 /*
716  * Check the MIC on a region of an skbuff.  The offset and length are updated
717  * to reflect the actual content of the secure region.
718  */
719 int rfc3961_verify_mic(const struct krb5_enctype *krb5,
720 		       struct crypto_shash *shash,
721 		       const struct krb5_buffer *metadata,
722 		       struct scatterlist *sg, unsigned int nr_sg,
723 		       size_t *_offset, size_t *_len)
724 {
725 	struct shash_desc *desc;
726 	ssize_t done;
727 	size_t bsize, data_offset, data_len, offset = *_offset, len = *_len;
728 	void *buffer = NULL;
729 	int ret;
730 	u8 *cksum, *cksum2;
731 
732 	if (len < krb5->cksum_len)
733 		return -EPROTO;
734 	data_offset = offset + krb5->cksum_len;
735 	data_len = len - krb5->cksum_len;
736 
737 	bsize = krb5_shash_size(shash) +
738 		krb5_digest_size(shash) * 2;
739 	buffer = kzalloc(bsize, GFP_NOFS);
740 	if (!buffer)
741 		return -ENOMEM;
742 
743 	cksum = buffer +
744 		krb5_shash_size(shash);
745 	cksum2 = buffer +
746 		krb5_shash_size(shash) +
747 		krb5_digest_size(shash);
748 
749 	/* Calculate the MIC */
750 	desc = buffer;
751 	desc->tfm = shash;
752 	ret = crypto_shash_init(desc);
753 	if (ret < 0)
754 		goto error;
755 
756 	if (metadata) {
757 		ret = crypto_shash_update(desc, metadata->data, metadata->len);
758 		if (ret < 0)
759 			goto error;
760 	}
761 
762 	crypto_shash_update_sg(desc, sg, data_offset, data_len);
763 	crypto_shash_final(desc, cksum);
764 
765 	ret = -EFAULT;
766 	done = sg_pcopy_to_buffer(sg, nr_sg, cksum2, krb5->cksum_len, offset);
767 	if (done != krb5->cksum_len)
768 		goto error;
769 
770 	if (memcmp(cksum, cksum2, krb5->cksum_len) != 0) {
771 		ret = -EBADMSG;
772 		goto error;
773 	}
774 
775 	*_offset += krb5->cksum_len;
776 	*_len -= krb5->cksum_len;
777 	ret = 0;
778 
779 error:
780 	kfree_sensitive(buffer);
781 	return ret;
782 }
783 
784 const struct krb5_crypto_profile rfc3961_simplified_profile = {
785 	.calc_PRF		= rfc3961_calc_PRF,
786 	.calc_Kc		= rfc3961_calc_DK,
787 	.calc_Ke		= rfc3961_calc_DK,
788 	.calc_Ki		= rfc3961_calc_DK,
789 	.derive_encrypt_keys	= authenc_derive_encrypt_keys,
790 	.load_encrypt_keys	= authenc_load_encrypt_keys,
791 	.derive_checksum_key	= rfc3961_derive_checksum_key,
792 	.load_checksum_key	= rfc3961_load_checksum_key,
793 	.encrypt		= krb5_aead_encrypt,
794 	.decrypt		= krb5_aead_decrypt,
795 	.get_mic		= rfc3961_get_mic,
796 	.verify_mic		= rfc3961_verify_mic,
797 };
798