// SPDX-License-Identifier: BSD-3-Clause /* rfc3961 Kerberos 5 simplified crypto profile. * * Parts borrowed from net/sunrpc/auth_gss/.
*/ /* * COPYRIGHT (c) 2008 * The Regents of the University of Michigan * ALL RIGHTS RESERVED * * Permission is granted to use, copy, create derivative works * and redistribute this software and such derivative works * for any purpose, so long as the name of The University of * Michigan is not used in any advertising or publicity * pertaining to the use of distribution of this software * without specific, written prior authorization. If the * above copyright notice or any other identification of the * University of Michigan is included in any copy of any * portion of this software, then the disclaimer below must * also be included. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF * SUCH DAMAGES.
*/
/* * Copyright (C) 1998 by the FundsXpress, INC. * * All rights reserved. * * Export of this software from the United States of America may require * a specific license from the United States Government. It is the * responsibility of any person or organization contemplating export to * obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/* * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * This is the n-fold function as described in rfc3961, sec 5.1 * Taken from MIT Kerberos and modified.
*/ staticvoid rfc3961_nfold(conststruct krb5_buffer *source, struct krb5_buffer *result)
{ const u8 *in = source->data;
u8 *out = result->data; unsignedlong ulcm; unsignedint inbits, outbits; int byte, i, msbit;
/* the code below is more readable if I make these bytes instead of bits */
inbits = source->len;
outbits = result->len;
/* first compute lcm(n,k) */
ulcm = lcm(inbits, outbits);
/* now do the real work */
memset(out, 0, outbits);
byte = 0;
/* this will end up cycling through k lcm(k,n)/k times, which * is correct.
*/ for (i = ulcm-1; i >= 0; i--) { /* compute the msbit in k which gets added into this byte */
msbit = ( /* first, start with the msbit in the first, * unrotated byte
*/
((inbits << 3) - 1) + /* then, for each byte, shift to the right * for each repetition
*/
(((inbits << 3) + 13) * (i/inbits)) + /* last, pick out the correct byte within * that shifted repetition
*/
((inbits - (i % inbits)) << 3)
) % (inbits << 3);
/* do the addition */
byte += out[i % outbits];
out[i % outbits] = byte & 0xff;
/* keep around the carry bit, if any */
byte >>= 8;
}
/* if there's a carry bit left over, add it back in */ if (byte) { for (i = outbits - 1; i >= 0; i--) { /* do the addition */
byte += out[i];
out[i] = byte & 0xff;
/* keep around the carry bit, if any */
byte >>= 8;
}
}
}
if (in_constant->len == inblock.len)
memcpy(inblock.data, in_constant->data, inblock.len); else
rfc3961_nfold(in_constant, &inblock);
/* loop encrypting the blocks until enough key bytes are generated */
n = 0; while (n < rawkey.len) {
rfc3961_do_encrypt(cipher, NULL, &inblock, &outblock);
if (keybytes - n <= outblock.len) {
memcpy(rawkey.data + n, outblock.data, keybytes - n); break;
}
memcpy(rawkey.data + n, outblock.data, outblock.len);
memcpy(inblock.data, outblock.data, outblock.len);
n += outblock.len;
}
/* postprocess the key */ if (!krb5->random_to_key) { /* Identity random-to-key function. */
memcpy(result->data, rawkey.data, rawkey.len);
ret = 0;
} else {
ret = krb5->random_to_key(krb5, &rawkey, result);
}
ret = rfc3961_calc_DK(krb5, protocol_key, &prfconstant, &derived_key, gfp); if (ret < 0) goto err;
ret = rfc3961_calc_E(krb5, &derived_key, &tmp2, result, gfp);
err:
kfree_sensitive(buffer); return ret;
}
/* * Derive the Ke and Ki keys and package them into a key parameter that can be * given to the setkey of a authenc AEAD crypto object.
*/ int authenc_derive_encrypt_keys(conststruct krb5_enctype *krb5, conststruct krb5_buffer *TK, unsignedint usage, struct krb5_buffer *setkey,
gfp_t gfp)
{ struct crypto_authenc_key_param *param; struct krb5_buffer Ke, Ki; struct rtattr *rta; int ret;
ret = krb5_derive_Ke(krb5, TK, usage, &Ke, gfp); if (ret < 0) {
pr_err("get_Ke failed %d\n", ret); return ret;
}
ret = krb5_derive_Ki(krb5, TK, usage, &Ki, gfp); if (ret < 0)
pr_err("get_Ki failed %d\n", ret); return ret;
}
/* * Package predefined Ke and Ki keys and into a key parameter that can be given * to the setkey of an authenc AEAD crypto object.
*/ int authenc_load_encrypt_keys(conststruct krb5_enctype *krb5, conststruct krb5_buffer *Ke, conststruct krb5_buffer *Ki, struct krb5_buffer *setkey,
gfp_t gfp)
{ struct crypto_authenc_key_param *param; struct rtattr *rta;
/* * Derive the Kc key for checksum-only mode and package it into a key parameter * that can be given to the setkey of a hash crypto object.
*/ int rfc3961_derive_checksum_key(conststruct krb5_enctype *krb5, conststruct krb5_buffer *TK, unsignedint usage, struct krb5_buffer *setkey,
gfp_t gfp)
{ int ret;
ret = krb5_derive_Kc(krb5, TK, usage, setkey, gfp); if (ret < 0)
pr_err("get_Kc failed %d\n", ret); return ret;
}
/* * Package a predefined Kc key for checksum-only mode into a key parameter that * can be given to the setkey of a hash crypto object.
*/ int rfc3961_load_checksum_key(conststruct krb5_enctype *krb5, conststruct krb5_buffer *Kc, struct krb5_buffer *setkey,
gfp_t gfp)
{
setkey->len = krb5->Kc_len;
setkey->data = kmemdup(Kc->data, Kc->len, GFP_KERNEL); if (!setkey->data) return -ENOMEM; return 0;
}
/* Insert the confounder into the buffer */
ret = -EFAULT; if (!preconfounded) {
get_random_bytes(buffer, krb5->conf_len);
done = sg_pcopy_from_buffer(sg, nr_sg, buffer, krb5->conf_len,
secure_offset); if (done != krb5->conf_len) goto error;
}
/* We may need to pad out to the crypto blocksize. */ if (pad_len) {
done = sg_zero_buffer(sg, nr_sg, pad_len, data_offset + data_len); if (done != pad_len) goto error;
}
/* Hash and encrypt the message. */
req = buffer;
iv = buffer + krb5_aead_size(aead);
aead_request_set_tfm(req, aead);
aead_request_set_callback(req, 0, NULL, NULL);
aead_request_set_crypt(req, sg, sg, secure_len, iv);
ret = crypto_aead_encrypt(req); if (ret < 0) goto error;
ret = secure_len + krb5->cksum_len;
error:
kfree_sensitive(buffer); return ret;
}
/* * Apply decryption and checksumming functions to a message. The offset and * length are updated to reflect the actual content of the encrypted region.
*/ int krb5_aead_decrypt(conststruct krb5_enctype *krb5, struct crypto_aead *aead, struct scatterlist *sg, unsignedint nr_sg,
size_t *_offset, size_t *_len)
{ struct aead_request *req;
size_t bsize; void *buffer; int ret;
u8 *iv;
if (WARN_ON(*_offset != 0)) return -EINVAL; /* Can't set offset on aead */
if (*_len < krb5->conf_len + krb5->cksum_len) return -EPROTO;
/* Decrypt the message and verify its checksum. */
req = buffer;
iv = buffer + krb5_aead_size(aead);
aead_request_set_tfm(req, aead);
aead_request_set_callback(req, 0, NULL, NULL);
aead_request_set_crypt(req, sg, sg, *_len, iv);
ret = crypto_aead_decrypt(req); if (ret < 0) goto error;
/* Adjust the boundaries of the data. */
*_offset += krb5->conf_len;
*_len -= krb5->conf_len + krb5->cksum_len;
ret = 0;
error:
kfree_sensitive(buffer); return ret;
}
/* * Generate a checksum over some metadata and part of an skbuff and insert the * MIC into the skbuff immediately prior to the data.
*/
ssize_t rfc3961_get_mic(conststruct krb5_enctype *krb5, struct crypto_shash *shash, conststruct krb5_buffer *metadata, struct scatterlist *sg, unsignedint nr_sg, size_t sg_len,
size_t data_offset, size_t data_len)
{ struct shash_desc *desc;
ssize_t ret, done;
size_t bsize; void *buffer, *digest;
if (WARN_ON(data_offset != krb5->cksum_len)) return -EMSGSIZE;
/* Calculate the MIC with key Kc and store it into the skb */
desc = buffer;
desc->tfm = shash;
ret = crypto_shash_init(desc); if (ret < 0) goto error;
if (metadata) {
ret = crypto_shash_update(desc, metadata->data, metadata->len); if (ret < 0) goto error;
}
ret = crypto_shash_update_sg(desc, sg, data_offset, data_len); if (ret < 0) goto error;
digest = buffer + krb5_shash_size(shash);
ret = crypto_shash_final(desc, digest); if (ret < 0) goto error;
ret = -EFAULT;
done = sg_pcopy_from_buffer(sg, nr_sg, digest, krb5->cksum_len,
data_offset - krb5->cksum_len); if (done != krb5->cksum_len) goto error;
ret = krb5->cksum_len + data_len;
error:
kfree_sensitive(buffer); return ret;
}
/* * Check the MIC on a region of an skbuff. The offset and length are updated * to reflect the actual content of the secure region.
*/ int rfc3961_verify_mic(conststruct krb5_enctype *krb5, struct crypto_shash *shash, conststruct krb5_buffer *metadata, struct scatterlist *sg, unsignedint nr_sg,
size_t *_offset, size_t *_len)
{ struct shash_desc *desc;
ssize_t done;
size_t bsize, data_offset, data_len, offset = *_offset, len = *_len; void *buffer = NULL; int ret;
u8 *cksum, *cksum2;
if (len < krb5->cksum_len) return -EPROTO;
data_offset = offset + krb5->cksum_len;
data_len = len - krb5->cksum_len;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.