mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 11:03:43 +02:00
crypto: Add Kerberos crypto lib
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEqG5UsNXhtOCrfGQP+7dXa6fLC2sFAmfFa1UACgkQ+7dXa6fL
C2ucgA//YRhCKDCQXe9Sf8l7PY8gDS15oLKbldwCHdKl2QZRasIVvWO+/67nXWi0
jarNXOxHXSI9gPf5V/W28Ya8l3ANNCNRksd/78OqHfblKGHiMmWk+Lvs8E0upTnD
C2zjorbMoJBcMTmDQF602ENlSJdI/Qn+zqSZlulhI+LFwCzU5xPzg9LUfCNu6MzJ
b9RKEYd2OC9Nst/pcIRZjz7M/TsOy8Fj457QOYjKXmNh6zTP8E5QMOyb4MThOacz
uu4K7JWpxJaQHv9BpYCLCCl1Mfjq8xUDxLwh3uMXbh2RUi4ZjCjnAnaZNF71kj/C
sRL6wm1U0QwPfaG9WZ0r2qytgtEGru5+roTdPF1ieXnZzLAy7fNU/fNXpaoHpRuI
g3cpxzYHD+lQg97uIFDi79uYm5t8NLRBxqh4ORXLobB2Yx4XMmpdG8sZvgRY/RIs
y3i6XAL3Te04sDywknNB+qb9Pc5AKdYLv4g7hWBvAqYq6fkZW7QBDNR3IobnnvXi
88w1wHQIrpr3o23be4v5GtrZYENlaQpDSa8oHcKd4yN5xs6Mj/6oGOzbII9aQWaM
+wgPkX6M02mJgoi2msL6a6WBnDBo5Jnq+OTY8VIw0eeMUMytHBkr46/3mY/cfbyl
yXgWrZxI9VsbD7JBjP8OkZreBTyYK1XjXrMzhHhvJozl2YJSWmw=
=7+o7
-----END PGP SIGNATURE-----
Merge tag 'crypto-krb5-20250303' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git
Pull Kerberos crypto library from David Howells:
crypto: Add Kerberos crypto lib
It does a couple of things:
(1) Provide an AEAD crypto driver, krb5enc, that mirrors the authenc
driver, but that hashes the plaintext, not the ciphertext. This was
made a separate module rather than just being a part of the authenc
driver because it has to do all of the constituent operations in the
opposite order - which impacts the async op handling.
Testmgr data is provided for AES+SHA2 and Camellia combinations of
authenc and krb5enc used by the krb5 library. AES+SHA1 is not
provided as the RFCs don't contain usable test vectors.
(2) Provide a Kerberos 5 crypto library. This is an extract from the
sunrpc driver as that code can be shared between sunrpc/nfs and
rxrpc/afs. This provides encryption, decryption, get MIC and verify
MIC routines that use and wrap the crypto functions, along with some
functions to provide layout management.
This supports AES+SHA1, AES+SHA2 and Camellia encryption types.
Self-testing is provided that goes further than is possible with
testmgr, doing subkey derivation as well.
The patches were previously posted here:
https://lore.kernel.org/r/20250203142343.248839-1-dhowells@redhat.com/
as part of a larger series, but the networking guys would prefer these to
go through the crypto tree. If you want them reposting independently, I
can do that.
This commit is contained in:
commit
d4880fe6fd
|
|
@ -26,3 +26,4 @@ for cryptographic use cases, as well as programming examples.
|
|||
api-samples
|
||||
descore-readme
|
||||
device_drivers/index
|
||||
krb5
|
||||
|
|
|
|||
262
Documentation/crypto/krb5.rst
Normal file
262
Documentation/crypto/krb5.rst
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
===========================
|
||||
Kerberos V Cryptography API
|
||||
===========================
|
||||
|
||||
.. Contents:
|
||||
|
||||
- Overview.
|
||||
- Small Buffer.
|
||||
- Encoding Type.
|
||||
- Key Derivation.
|
||||
- PRF+ Calculation.
|
||||
- Kc, Ke And Ki Derivation.
|
||||
- Crypto Functions.
|
||||
- Preparation Functions.
|
||||
- Encryption Mode.
|
||||
- Checksum Mode.
|
||||
- The krb5enc AEAD algorithm
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
This API provides Kerberos 5-style cryptography for key derivation, encryption
|
||||
and checksumming for use in network filesystems and can be used to implement
|
||||
the low-level crypto that's needed for GSSAPI.
|
||||
|
||||
The following crypto types are supported::
|
||||
|
||||
KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96
|
||||
KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96
|
||||
KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128
|
||||
KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192
|
||||
KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC
|
||||
KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC
|
||||
|
||||
KRB5_CKSUMTYPE_HMAC_SHA1_96_AES128
|
||||
KRB5_CKSUMTYPE_HMAC_SHA1_96_AES256
|
||||
KRB5_CKSUMTYPE_CMAC_CAMELLIA128
|
||||
KRB5_CKSUMTYPE_CMAC_CAMELLIA256
|
||||
KRB5_CKSUMTYPE_HMAC_SHA256_128_AES128
|
||||
KRB5_CKSUMTYPE_HMAC_SHA384_192_AES256
|
||||
|
||||
The API can be included by::
|
||||
|
||||
#include <crypto/krb5.h>
|
||||
|
||||
Small Buffer
|
||||
------------
|
||||
|
||||
To pass small pieces of data about, such as keys, a buffer structure is
|
||||
defined, giving a pointer to the data and the size of that data::
|
||||
|
||||
struct krb5_buffer {
|
||||
unsigned int len;
|
||||
void *data;
|
||||
};
|
||||
|
||||
Encoding Type
|
||||
=============
|
||||
|
||||
The encoding type is defined by the following structure::
|
||||
|
||||
struct krb5_enctype {
|
||||
int etype;
|
||||
int ctype;
|
||||
const char *name;
|
||||
u16 key_bytes;
|
||||
u16 key_len;
|
||||
u16 Kc_len;
|
||||
u16 Ke_len;
|
||||
u16 Ki_len;
|
||||
u16 prf_len;
|
||||
u16 block_len;
|
||||
u16 conf_len;
|
||||
u16 cksum_len;
|
||||
...
|
||||
};
|
||||
|
||||
The fields of interest to the user of the API are as follows:
|
||||
|
||||
* ``etype`` and ``ctype`` indicate the protocol number for this encoding
|
||||
type for encryption and checksumming respectively. They hold
|
||||
``KRB5_ENCTYPE_*`` and ``KRB5_CKSUMTYPE_*`` constants.
|
||||
|
||||
* ``name`` is the formal name of the encoding.
|
||||
|
||||
* ``key_len`` and ``key_bytes`` are the input key length and the derived key
|
||||
length. (I think they only differ for DES, which isn't supported here).
|
||||
|
||||
* ``Kc_len``, ``Ke_len`` and ``Ki_len`` are the sizes of the derived Kc, Ke
|
||||
and Ki keys. Kc is used for in checksum mode; Ke and Ki are used in
|
||||
encryption mode.
|
||||
|
||||
* ``prf_len`` is the size of the result from the PRF+ function calculation.
|
||||
|
||||
* ``block_len``, ``conf_len`` and ``cksum_len`` are the encryption block
|
||||
length, confounder length and checksum length respectively. All three are
|
||||
used in encryption mode, but only the checksum length is used in checksum
|
||||
mode.
|
||||
|
||||
The encoding type is looked up by number using the following function::
|
||||
|
||||
const struct krb5_enctype *crypto_krb5_find_enctype(u32 enctype);
|
||||
|
||||
Key Derivation
|
||||
==============
|
||||
|
||||
Once the application has selected an encryption type, the keys that will be
|
||||
used to do the actual crypto can be derived from the transport key.
|
||||
|
||||
PRF+ Calculation
|
||||
----------------
|
||||
|
||||
To aid in key derivation, a function to calculate the Kerberos GSSAPI
|
||||
mechanism's PRF+ is provided::
|
||||
|
||||
int crypto_krb5_calc_PRFplus(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *K,
|
||||
unsigned int L,
|
||||
const struct krb5_buffer *S,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp);
|
||||
|
||||
This can be used to derive the transport key from a source key plus additional
|
||||
data to limit its use.
|
||||
|
||||
Crypto Functions
|
||||
================
|
||||
|
||||
Once the keys have been derived, crypto can be performed on the data. The
|
||||
caller must leave gaps in the buffer for the storage of the confounder (if
|
||||
needed) and the checksum when preparing a message for transmission. An enum
|
||||
and a pair of functions are provided to aid in this::
|
||||
|
||||
enum krb5_crypto_mode {
|
||||
KRB5_CHECKSUM_MODE,
|
||||
KRB5_ENCRYPT_MODE,
|
||||
};
|
||||
|
||||
size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t data_size, size_t *_offset);
|
||||
|
||||
size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_buffer_size, size_t *_offset);
|
||||
|
||||
All these functions take the encoding type and an indication the mode of crypto
|
||||
(checksum-only or full encryption).
|
||||
|
||||
The first function returns how big the buffer will need to be to house a given
|
||||
amount of data; the second function returns how much data will fit in a buffer
|
||||
of a particular size, and adjusts down the size of the required buffer
|
||||
accordingly. In both cases, the offset of the data within the buffer is also
|
||||
returned.
|
||||
|
||||
When a message has been received, the location and size of the data with the
|
||||
message can be determined by calling::
|
||||
|
||||
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
The caller provides the offset and length of the message to the function, which
|
||||
then alters those values to indicate the region containing the data (plus any
|
||||
padding). It is up to the caller to determine how much padding there is.
|
||||
|
||||
Preparation Functions
|
||||
---------------------
|
||||
|
||||
Two functions are provided to allocated and prepare a crypto object for use by
|
||||
the action functions::
|
||||
|
||||
struct crypto_aead *
|
||||
crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp);
|
||||
struct crypto_shash *
|
||||
crypto_krb5_prepare_checksum(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp);
|
||||
|
||||
Both of these functions take the encoding type, the transport key and the usage
|
||||
value used to derive the appropriate subkey(s). They create an appropriate
|
||||
crypto object, an AEAD template for encryption and a synchronous hash for
|
||||
checksumming, set the key(s) on it and configure it. The caller is expected to
|
||||
pass these handles to the action functions below.
|
||||
|
||||
Encryption Mode
|
||||
---------------
|
||||
|
||||
A pair of functions are provided to encrypt and decrypt a message::
|
||||
|
||||
ssize_t crypto_krb5_encrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded);
|
||||
int crypto_krb5_decrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
In both cases, the input and output buffers are indicated by the same
|
||||
scatterlist.
|
||||
|
||||
For the encryption function, the output buffer may be larger than is needed
|
||||
(the amount of output generated is returned) and the location and size of the
|
||||
data are indicated (which must match the encoding). If no confounder is set,
|
||||
the function will insert one.
|
||||
|
||||
For the decryption function, the offset and length of the message in buffer are
|
||||
supplied and these are shrunk to fit the data. The decryption function will
|
||||
verify any checksums within the message and give an error if they don't match.
|
||||
|
||||
Checksum Mode
|
||||
-------------
|
||||
|
||||
A pair of function are provided to generate the checksum on a message and to
|
||||
verify that checksum::
|
||||
|
||||
ssize_t crypto_krb5_get_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len);
|
||||
int crypto_krb5_verify_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
In both cases, the input and output buffers are indicated by the same
|
||||
scatterlist. Additional metadata can be passed in which will get added to the
|
||||
hash before the data.
|
||||
|
||||
For the get_mic function, the output buffer may be larger than is needed (the
|
||||
amount of output generated is returned) and the location and size of the data
|
||||
are indicated (which must match the encoding).
|
||||
|
||||
For the verification function, the offset and length of the message in buffer
|
||||
are supplied and these are shrunk to fit the data. An error will be returned
|
||||
if the checksums don't match.
|
||||
|
||||
The krb5enc AEAD algorithm
|
||||
==========================
|
||||
|
||||
A template AEAD crypto algorithm, called "krb5enc", is provided that hashes the
|
||||
plaintext before encrypting it (the reverse of authenc). The handle returned
|
||||
by ``crypto_krb5_prepare_encryption()`` may be one of these, but there's no
|
||||
requirement for the user of this API to interact with it directly.
|
||||
|
||||
For reference, its key format begins with a BE32 of the format number. Only
|
||||
format 1 is provided and that continues with a BE32 of the Ke key length
|
||||
followed by a BE32 of the Ki key length, followed by the bytes from the Ke key
|
||||
and then the Ki key.
|
||||
|
||||
Using specifically ordered words means that the static test data doesn't
|
||||
require byteswapping.
|
||||
|
|
@ -228,6 +228,18 @@ config CRYPTO_AUTHENC
|
|||
|
||||
This is required for IPSec ESP (XFRM_ESP).
|
||||
|
||||
config CRYPTO_KRB5ENC
|
||||
tristate "Kerberos 5 combined hash+cipher support"
|
||||
select CRYPTO_AEAD
|
||||
select CRYPTO_SKCIPHER
|
||||
select CRYPTO_MANAGER
|
||||
select CRYPTO_HASH
|
||||
select CRYPTO_NULL
|
||||
help
|
||||
Combined hash and cipher support for Kerberos 5 RFC3961 simplified
|
||||
profile. This is required for Kerberos 5-style encryption, used by
|
||||
sunrpc/NFS and rxrpc/AFS.
|
||||
|
||||
config CRYPTO_TEST
|
||||
tristate "Testing module"
|
||||
depends on m || EXPERT
|
||||
|
|
@ -1460,5 +1472,6 @@ endif
|
|||
source "drivers/crypto/Kconfig"
|
||||
source "crypto/asymmetric_keys/Kconfig"
|
||||
source "certs/Kconfig"
|
||||
source "crypto/krb5/Kconfig"
|
||||
|
||||
endif # if CRYPTO
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_generic.o
|
|||
CFLAGS_crct10dif_generic.o += -DARCH=$(ARCH)
|
||||
obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o
|
||||
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
|
||||
obj-$(CONFIG_CRYPTO_KRB5ENC) += krb5enc.o
|
||||
obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o
|
||||
obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
|
||||
obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o
|
||||
|
|
@ -212,3 +213,5 @@ obj-$(CONFIG_CRYPTO_SIMD) += crypto_simd.o
|
|||
# Key derivation function
|
||||
#
|
||||
obj-$(CONFIG_CRYPTO_KDF800108_CTR) += kdf_sp800108.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_KRB5) += krb5/
|
||||
|
|
|
|||
26
crypto/krb5/Kconfig
Normal file
26
crypto/krb5/Kconfig
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
config CRYPTO_KRB5
|
||||
tristate "Kerberos 5 crypto"
|
||||
select CRYPTO_MANAGER
|
||||
select CRYPTO_KRB5ENC
|
||||
select CRYPTO_AUTHENC
|
||||
select CRYPTO_SKCIPHER
|
||||
select CRYPTO_HASH_INFO
|
||||
select CRYPTO_HMAC
|
||||
select CRYPTO_CMAC
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_SHA256
|
||||
select CRYPTO_SHA512
|
||||
select CRYPTO_CBC
|
||||
select CRYPTO_CTS
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CAMELLIA
|
||||
help
|
||||
Provide a library for provision of Kerberos-5-based crypto. This is
|
||||
intended for network filesystems to use.
|
||||
|
||||
config CRYPTO_KRB5_SELFTESTS
|
||||
bool "Kerberos 5 crypto selftests"
|
||||
depends on CRYPTO_KRB5
|
||||
help
|
||||
Turn on some self-testing for the kerberos 5 crypto functions. These
|
||||
will be performed on module load or boot, if compiled in.
|
||||
18
crypto/krb5/Makefile
Normal file
18
crypto/krb5/Makefile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for asymmetric cryptographic keys
|
||||
#
|
||||
|
||||
krb5-y += \
|
||||
krb5_kdf.o \
|
||||
krb5_api.o \
|
||||
rfc3961_simplified.o \
|
||||
rfc3962_aes.o \
|
||||
rfc6803_camellia.o \
|
||||
rfc8009_aes2.o
|
||||
|
||||
krb5-$(CONFIG_CRYPTO_KRB5_SELFTESTS) += \
|
||||
selftest.o \
|
||||
selftest_data.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_KRB5) += krb5.o
|
||||
247
crypto/krb5/internal.h
Normal file
247
crypto/krb5/internal.h
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Kerberos5 crypto internals
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/krb5.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/skcipher.h>
|
||||
|
||||
/*
|
||||
* Profile used for key derivation and encryption.
|
||||
*/
|
||||
struct krb5_crypto_profile {
|
||||
/* Pseudo-random function */
|
||||
int (*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);
|
||||
|
||||
/* Checksum key derivation */
|
||||
int (*calc_Kc)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
const struct krb5_buffer *usage_constant,
|
||||
struct krb5_buffer *Kc,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Encryption key derivation */
|
||||
int (*calc_Ke)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
const struct krb5_buffer *usage_constant,
|
||||
struct krb5_buffer *Ke,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Integrity key derivation */
|
||||
int (*calc_Ki)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
const struct krb5_buffer *usage_constant,
|
||||
struct krb5_buffer *Ki,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Derive the keys needed for an encryption AEAD object. */
|
||||
int (*derive_encrypt_keys)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
unsigned int usage,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Directly load the keys needed for an encryption AEAD object. */
|
||||
int (*load_encrypt_keys)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Ke,
|
||||
const struct krb5_buffer *Ki,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Derive the key needed for a checksum hash object. */
|
||||
int (*derive_checksum_key)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
unsigned int usage,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Directly load the keys needed for a checksum hash object. */
|
||||
int (*load_checksum_key)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Kc,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
|
||||
/* Encrypt data in-place, inserting confounder and checksum. */
|
||||
ssize_t (*encrypt)(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded);
|
||||
|
||||
/* Decrypt data in-place, removing confounder and checksum */
|
||||
int (*decrypt)(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
/* Generate a MIC on part of a packet, inserting the checksum */
|
||||
ssize_t (*get_mic)(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len);
|
||||
|
||||
/* Verify the MIC on a piece of data, removing the checksum */
|
||||
int (*verify_mic)(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
};
|
||||
|
||||
/*
|
||||
* Crypto size/alignment rounding convenience macros.
|
||||
*/
|
||||
#define crypto_roundup(X) ((unsigned int)round_up((X), CRYPTO_MINALIGN))
|
||||
|
||||
#define krb5_aead_size(TFM) \
|
||||
crypto_roundup(sizeof(struct aead_request) + crypto_aead_reqsize(TFM))
|
||||
#define krb5_aead_ivsize(TFM) \
|
||||
crypto_roundup(crypto_aead_ivsize(TFM))
|
||||
#define krb5_shash_size(TFM) \
|
||||
crypto_roundup(sizeof(struct shash_desc) + crypto_shash_descsize(TFM))
|
||||
#define krb5_digest_size(TFM) \
|
||||
crypto_roundup(crypto_shash_digestsize(TFM))
|
||||
#define round16(x) (((x) + 15) & ~15)
|
||||
|
||||
/*
|
||||
* Self-testing data.
|
||||
*/
|
||||
struct krb5_prf_test {
|
||||
u32 etype;
|
||||
const char *name, *key, *octet, *prf;
|
||||
};
|
||||
|
||||
struct krb5_key_test_one {
|
||||
u32 use;
|
||||
const char *key;
|
||||
};
|
||||
|
||||
struct krb5_key_test {
|
||||
u32 etype;
|
||||
const char *name, *key;
|
||||
struct krb5_key_test_one Kc, Ke, Ki;
|
||||
};
|
||||
|
||||
struct krb5_enc_test {
|
||||
u32 etype;
|
||||
u32 usage;
|
||||
const char *name, *plain, *conf, *K0, *Ke, *Ki, *ct;
|
||||
};
|
||||
|
||||
struct krb5_mic_test {
|
||||
u32 etype;
|
||||
u32 usage;
|
||||
const char *name, *plain, *K0, *Kc, *mic;
|
||||
};
|
||||
|
||||
/*
|
||||
* krb5_api.c
|
||||
*/
|
||||
struct crypto_aead *krb5_prepare_encryption(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *keys,
|
||||
gfp_t gfp);
|
||||
struct crypto_shash *krb5_prepare_checksum(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Kc,
|
||||
gfp_t gfp);
|
||||
|
||||
/*
|
||||
* krb5_kdf.c
|
||||
*/
|
||||
int krb5_derive_Kc(const struct krb5_enctype *krb5, const struct krb5_buffer *TK,
|
||||
u32 usage, struct krb5_buffer *key, gfp_t gfp);
|
||||
int krb5_derive_Ke(const struct krb5_enctype *krb5, const struct krb5_buffer *TK,
|
||||
u32 usage, struct krb5_buffer *key, gfp_t gfp);
|
||||
int krb5_derive_Ki(const struct krb5_enctype *krb5, const struct krb5_buffer *TK,
|
||||
u32 usage, struct krb5_buffer *key, gfp_t gfp);
|
||||
|
||||
/*
|
||||
* rfc3961_simplified.c
|
||||
*/
|
||||
extern const struct krb5_crypto_profile rfc3961_simplified_profile;
|
||||
|
||||
int crypto_shash_update_sg(struct shash_desc *desc, struct scatterlist *sg,
|
||||
size_t offset, size_t len);
|
||||
int authenc_derive_encrypt_keys(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
unsigned int usage,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
int authenc_load_encrypt_keys(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Ke,
|
||||
const struct krb5_buffer *Ki,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
int rfc3961_derive_checksum_key(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
unsigned int usage,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
int rfc3961_load_checksum_key(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Kc,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp);
|
||||
ssize_t krb5_aead_encrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded);
|
||||
int krb5_aead_decrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
ssize_t rfc3961_get_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
|
||||
size_t data_offset, size_t data_len);
|
||||
int rfc3961_verify_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
/*
|
||||
* rfc3962_aes.c
|
||||
*/
|
||||
extern const struct krb5_enctype krb5_aes128_cts_hmac_sha1_96;
|
||||
extern const struct krb5_enctype krb5_aes256_cts_hmac_sha1_96;
|
||||
|
||||
/*
|
||||
* rfc6803_camellia.c
|
||||
*/
|
||||
extern const struct krb5_enctype krb5_camellia128_cts_cmac;
|
||||
extern const struct krb5_enctype krb5_camellia256_cts_cmac;
|
||||
|
||||
/*
|
||||
* rfc8009_aes2.c
|
||||
*/
|
||||
extern const struct krb5_enctype krb5_aes128_cts_hmac_sha256_128;
|
||||
extern const struct krb5_enctype krb5_aes256_cts_hmac_sha384_192;
|
||||
|
||||
/*
|
||||
* selftest.c
|
||||
*/
|
||||
#ifdef CONFIG_CRYPTO_KRB5_SELFTESTS
|
||||
int krb5_selftest(void);
|
||||
#else
|
||||
static inline int krb5_selftest(void) { return 0; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* selftest_data.c
|
||||
*/
|
||||
extern const struct krb5_prf_test krb5_prf_tests[];
|
||||
extern const struct krb5_key_test krb5_key_tests[];
|
||||
extern const struct krb5_enc_test krb5_enc_tests[];
|
||||
extern const struct krb5_mic_test krb5_mic_tests[];
|
||||
452
crypto/krb5/krb5_api.c
Normal file
452
crypto/krb5/krb5_api.c
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Kerberos 5 crypto library.
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "internal.h"
|
||||
|
||||
MODULE_DESCRIPTION("Kerberos 5 crypto");
|
||||
MODULE_AUTHOR("Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static const struct krb5_enctype *const krb5_supported_enctypes[] = {
|
||||
&krb5_aes128_cts_hmac_sha1_96,
|
||||
&krb5_aes256_cts_hmac_sha1_96,
|
||||
&krb5_aes128_cts_hmac_sha256_128,
|
||||
&krb5_aes256_cts_hmac_sha384_192,
|
||||
&krb5_camellia128_cts_cmac,
|
||||
&krb5_camellia256_cts_cmac,
|
||||
};
|
||||
|
||||
/**
|
||||
* crypto_krb5_find_enctype - Find the handler for a Kerberos5 encryption type
|
||||
* @enctype: The standard Kerberos encryption type number
|
||||
*
|
||||
* Look up a Kerberos encryption type by number. If successful, returns a
|
||||
* pointer to the type tables; returns NULL otherwise.
|
||||
*/
|
||||
const struct krb5_enctype *crypto_krb5_find_enctype(u32 enctype)
|
||||
{
|
||||
const struct krb5_enctype *krb5;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(krb5_supported_enctypes); i++) {
|
||||
krb5 = krb5_supported_enctypes[i];
|
||||
if (krb5->etype == enctype)
|
||||
return krb5;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_find_enctype);
|
||||
|
||||
/**
|
||||
* crypto_krb5_how_much_buffer - Work out how much buffer is required for an amount of data
|
||||
* @krb5: The encoding to use.
|
||||
* @mode: The mode in which to operated (checksum/encrypt)
|
||||
* @data_size: How much data we want to allow for
|
||||
* @_offset: Where to place the offset into the buffer
|
||||
*
|
||||
* Calculate how much buffer space is required to wrap a given amount of data.
|
||||
* This allows for a confounder, padding and checksum as appropriate. The
|
||||
* amount of buffer required is returned and the offset into the buffer at
|
||||
* which the data will start is placed in *_offset.
|
||||
*/
|
||||
size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t data_size, size_t *_offset)
|
||||
{
|
||||
switch (mode) {
|
||||
case KRB5_CHECKSUM_MODE:
|
||||
*_offset = krb5->cksum_len;
|
||||
return krb5->cksum_len + data_size;
|
||||
|
||||
case KRB5_ENCRYPT_MODE:
|
||||
*_offset = krb5->conf_len;
|
||||
return krb5->conf_len + data_size + krb5->cksum_len;
|
||||
|
||||
default:
|
||||
WARN_ON(1);
|
||||
*_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_how_much_buffer);
|
||||
|
||||
/**
|
||||
* crypto_krb5_how_much_data - Work out how much data can fit in an amount of buffer
|
||||
* @krb5: The encoding to use.
|
||||
* @mode: The mode in which to operated (checksum/encrypt)
|
||||
* @_buffer_size: How much buffer we want to allow for (may be reduced)
|
||||
* @_offset: Where to place the offset into the buffer
|
||||
*
|
||||
* Calculate how much data can be fitted into given amount of buffer. This
|
||||
* allows for a confounder, padding and checksum as appropriate. The amount of
|
||||
* data that will fit is returned, the amount of buffer required is shrunk to
|
||||
* allow for alignment and the offset into the buffer at which the data will
|
||||
* start is placed in *_offset.
|
||||
*/
|
||||
size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_buffer_size, size_t *_offset)
|
||||
{
|
||||
size_t buffer_size = *_buffer_size, data_size;
|
||||
|
||||
switch (mode) {
|
||||
case KRB5_CHECKSUM_MODE:
|
||||
if (WARN_ON(buffer_size < krb5->cksum_len + 1))
|
||||
goto bad;
|
||||
*_offset = krb5->cksum_len;
|
||||
return buffer_size - krb5->cksum_len;
|
||||
|
||||
case KRB5_ENCRYPT_MODE:
|
||||
if (WARN_ON(buffer_size < krb5->conf_len + 1 + krb5->cksum_len))
|
||||
goto bad;
|
||||
data_size = buffer_size - krb5->cksum_len;
|
||||
*_offset = krb5->conf_len;
|
||||
return data_size - krb5->conf_len;
|
||||
|
||||
default:
|
||||
WARN_ON(1);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
bad:
|
||||
*_offset = 0;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_how_much_data);
|
||||
|
||||
/**
|
||||
* crypto_krb5_where_is_the_data - Find the data in a decrypted message
|
||||
* @krb5: The encoding to use.
|
||||
* @mode: Mode of operation
|
||||
* @_offset: Offset of the secure blob in the buffer; updated to data offset.
|
||||
* @_len: The length of the secure blob; updated to data length.
|
||||
*
|
||||
* Find the offset and size of the data in a secure message so that this
|
||||
* information can be used in the metadata buffer which will get added to the
|
||||
* digest by crypto_krb5_verify_mic().
|
||||
*/
|
||||
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len)
|
||||
{
|
||||
switch (mode) {
|
||||
case KRB5_CHECKSUM_MODE:
|
||||
*_offset += krb5->cksum_len;
|
||||
*_len -= krb5->cksum_len;
|
||||
return;
|
||||
case KRB5_ENCRYPT_MODE:
|
||||
*_offset += krb5->conf_len;
|
||||
*_len -= krb5->conf_len + krb5->cksum_len;
|
||||
return;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_where_is_the_data);
|
||||
|
||||
/*
|
||||
* Prepare the encryption with derived key data.
|
||||
*/
|
||||
struct crypto_aead *krb5_prepare_encryption(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *keys,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_aead *ci = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
ci = crypto_alloc_aead(krb5->encrypt_name, 0, 0);
|
||||
if (IS_ERR(ci)) {
|
||||
ret = PTR_ERR(ci);
|
||||
if (ret == -ENOENT)
|
||||
ret = -ENOPKG;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = crypto_aead_setkey(ci, keys->data, keys->len);
|
||||
if (ret < 0) {
|
||||
pr_err("Couldn't set AEAD key %s: %d\n", krb5->encrypt_name, ret);
|
||||
goto err_ci;
|
||||
}
|
||||
|
||||
ret = crypto_aead_setauthsize(ci, krb5->cksum_len);
|
||||
if (ret < 0) {
|
||||
pr_err("Couldn't set AEAD authsize %s: %d\n", krb5->encrypt_name, ret);
|
||||
goto err_ci;
|
||||
}
|
||||
|
||||
return ci;
|
||||
err_ci:
|
||||
crypto_free_aead(ci);
|
||||
err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto_krb5_prepare_encryption - Prepare AEAD crypto object for encryption-mode
|
||||
* @krb5: The encoding to use.
|
||||
* @TK: The transport key to use.
|
||||
* @usage: The usage constant for key derivation.
|
||||
* @gfp: Allocation flags.
|
||||
*
|
||||
* Allocate a crypto object that does all the necessary crypto, key it and set
|
||||
* its parameters and return the crypto handle to it. This can then be used to
|
||||
* dispatch encrypt and decrypt operations.
|
||||
*/
|
||||
struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp)
|
||||
{
|
||||
struct crypto_aead *ci = NULL;
|
||||
struct krb5_buffer keys = {};
|
||||
int ret;
|
||||
|
||||
ret = krb5->profile->derive_encrypt_keys(krb5, TK, usage, &keys, gfp);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ci = krb5_prepare_encryption(krb5, &keys, gfp);
|
||||
if (IS_ERR(ci)) {
|
||||
ret = PTR_ERR(ci);
|
||||
goto err;
|
||||
}
|
||||
|
||||
kfree(keys.data);
|
||||
return ci;
|
||||
err:
|
||||
kfree(keys.data);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_prepare_encryption);
|
||||
|
||||
/*
|
||||
* Prepare the checksum with derived key data.
|
||||
*/
|
||||
struct crypto_shash *krb5_prepare_checksum(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Kc,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_shash *ci = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
ci = crypto_alloc_shash(krb5->cksum_name, 0, 0);
|
||||
if (IS_ERR(ci)) {
|
||||
ret = PTR_ERR(ci);
|
||||
if (ret == -ENOENT)
|
||||
ret = -ENOPKG;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = crypto_shash_setkey(ci, Kc->data, Kc->len);
|
||||
if (ret < 0) {
|
||||
pr_err("Couldn't set shash key %s: %d\n", krb5->cksum_name, ret);
|
||||
goto err_ci;
|
||||
}
|
||||
|
||||
return ci;
|
||||
err_ci:
|
||||
crypto_free_shash(ci);
|
||||
err:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto_krb5_prepare_checksum - Prepare AEAD crypto object for checksum-mode
|
||||
* @krb5: The encoding to use.
|
||||
* @TK: The transport key to use.
|
||||
* @usage: The usage constant for key derivation.
|
||||
* @gfp: Allocation flags.
|
||||
*
|
||||
* Allocate a crypto object that does all the necessary crypto, key it and set
|
||||
* its parameters and return the crypto handle to it. This can then be used to
|
||||
* dispatch get_mic and verify_mic operations.
|
||||
*/
|
||||
struct crypto_shash *crypto_krb5_prepare_checksum(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp)
|
||||
{
|
||||
struct crypto_shash *ci = NULL;
|
||||
struct krb5_buffer keys = {};
|
||||
int ret;
|
||||
|
||||
ret = krb5->profile->derive_checksum_key(krb5, TK, usage, &keys, gfp);
|
||||
if (ret < 0) {
|
||||
pr_err("get_Kc failed %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ci = krb5_prepare_checksum(krb5, &keys, gfp);
|
||||
if (IS_ERR(ci)) {
|
||||
ret = PTR_ERR(ci);
|
||||
goto err;
|
||||
}
|
||||
|
||||
kfree(keys.data);
|
||||
return ci;
|
||||
err:
|
||||
kfree(keys.data);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_prepare_checksum);
|
||||
|
||||
/**
|
||||
* crypto_krb5_encrypt - Apply Kerberos encryption and integrity.
|
||||
* @krb5: The encoding to use.
|
||||
* @aead: The keyed crypto object to use.
|
||||
* @sg: Scatterlist defining the crypto buffer.
|
||||
* @nr_sg: The number of elements in @sg.
|
||||
* @sg_len: The size of the buffer.
|
||||
* @data_offset: The offset of the data in the @sg buffer.
|
||||
* @data_len: The length of the data.
|
||||
* @preconfounded: True if the confounder is already inserted.
|
||||
*
|
||||
* Using the specified Kerberos encoding, insert a confounder and padding as
|
||||
* needed, encrypt this and the data in place and insert an integrity checksum
|
||||
* into the buffer.
|
||||
*
|
||||
* The buffer must include space for the confounder, the checksum and any
|
||||
* padding required. The caller can preinsert the confounder into the buffer
|
||||
* (for testing, for example).
|
||||
*
|
||||
* The resulting secured blob may be less than the size of the buffer.
|
||||
*
|
||||
* Returns the size of the secure blob if successful, -ENOMEM on an allocation
|
||||
* failure, -EFAULT if there is insufficient space, -EMSGSIZE if the confounder
|
||||
* is too short or the data is misaligned. Other errors may also be returned
|
||||
* from the crypto layer.
|
||||
*/
|
||||
ssize_t crypto_krb5_encrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded)
|
||||
{
|
||||
if (WARN_ON(data_offset > sg_len ||
|
||||
data_len > sg_len ||
|
||||
data_offset > sg_len - data_len))
|
||||
return -EMSGSIZE;
|
||||
return krb5->profile->encrypt(krb5, aead, sg, nr_sg, sg_len,
|
||||
data_offset, data_len, preconfounded);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_encrypt);
|
||||
|
||||
/**
|
||||
* crypto_krb5_decrypt - Validate and remove Kerberos encryption and integrity.
|
||||
* @krb5: The encoding to use.
|
||||
* @aead: The keyed crypto object to use.
|
||||
* @sg: Scatterlist defining the crypto buffer.
|
||||
* @nr_sg: The number of elements in @sg.
|
||||
* @_offset: Offset of the secure blob in the buffer; updated to data offset.
|
||||
* @_len: The length of the secure blob; updated to data length.
|
||||
*
|
||||
* Using the specified Kerberos encoding, check and remove the integrity
|
||||
* checksum and decrypt the secure region, stripping off the confounder.
|
||||
*
|
||||
* If successful, @_offset and @_len are updated to outline the region in which
|
||||
* the data plus the trailing padding are stored. The caller is responsible
|
||||
* for working out how much padding there is and removing it.
|
||||
*
|
||||
* Returns the 0 if successful, -ENOMEM on an allocation failure; sets
|
||||
* *_error_code and returns -EPROTO if the data cannot be parsed, or -EBADMSG
|
||||
* if the integrity checksum doesn't match). Other errors may also be returned
|
||||
* from the crypto layer.
|
||||
*/
|
||||
int crypto_krb5_decrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len)
|
||||
{
|
||||
return krb5->profile->decrypt(krb5, aead, sg, nr_sg, _offset, _len);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_decrypt);
|
||||
|
||||
/**
|
||||
* crypto_krb5_get_mic - Apply Kerberos integrity checksum.
|
||||
* @krb5: The encoding to use.
|
||||
* @shash: The keyed hash to use.
|
||||
* @metadata: Metadata to add into the hash before adding the data.
|
||||
* @sg: Scatterlist defining the crypto buffer.
|
||||
* @nr_sg: The number of elements in @sg.
|
||||
* @sg_len: The size of the buffer.
|
||||
* @data_offset: The offset of the data in the @sg buffer.
|
||||
* @data_len: The length of the data.
|
||||
*
|
||||
* Using the specified Kerberos encoding, calculate and insert an integrity
|
||||
* checksum into the buffer.
|
||||
*
|
||||
* The buffer must include space for the checksum at the front.
|
||||
*
|
||||
* Returns the size of the secure blob if successful, -ENOMEM on an allocation
|
||||
* failure, -EFAULT if there is insufficient space, -EMSGSIZE if the gap for
|
||||
* the checksum is too short. Other errors may also be returned from the
|
||||
* crypto layer.
|
||||
*/
|
||||
ssize_t crypto_krb5_get_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len)
|
||||
{
|
||||
if (WARN_ON(data_offset > sg_len ||
|
||||
data_len > sg_len ||
|
||||
data_offset > sg_len - data_len))
|
||||
return -EMSGSIZE;
|
||||
return krb5->profile->get_mic(krb5, shash, metadata, sg, nr_sg, sg_len,
|
||||
data_offset, data_len);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_get_mic);
|
||||
|
||||
/**
|
||||
* crypto_krb5_verify_mic - Validate and remove Kerberos integrity checksum.
|
||||
* @krb5: The encoding to use.
|
||||
* @shash: The keyed hash to use.
|
||||
* @metadata: Metadata to add into the hash before adding the data.
|
||||
* @sg: Scatterlist defining the crypto buffer.
|
||||
* @nr_sg: The number of elements in @sg.
|
||||
* @_offset: Offset of the secure blob in the buffer; updated to data offset.
|
||||
* @_len: The length of the secure blob; updated to data length.
|
||||
*
|
||||
* Using the specified Kerberos encoding, check and remove the integrity
|
||||
* checksum.
|
||||
*
|
||||
* If successful, @_offset and @_len are updated to outline the region in which
|
||||
* the data is stored.
|
||||
*
|
||||
* Returns the 0 if successful, -ENOMEM on an allocation failure; sets
|
||||
* *_error_code and returns -EPROTO if the data cannot be parsed, or -EBADMSG
|
||||
* if the checksum doesn't match). Other errors may also be returned from the
|
||||
* crypto layer.
|
||||
*/
|
||||
int crypto_krb5_verify_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len)
|
||||
{
|
||||
return krb5->profile->verify_mic(krb5, shash, metadata, sg, nr_sg,
|
||||
_offset, _len);
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_verify_mic);
|
||||
|
||||
static int __init crypto_krb5_init(void)
|
||||
{
|
||||
return krb5_selftest();
|
||||
}
|
||||
module_init(crypto_krb5_init);
|
||||
|
||||
static void __exit crypto_krb5_exit(void)
|
||||
{
|
||||
}
|
||||
module_exit(crypto_krb5_exit);
|
||||
145
crypto/krb5/krb5_kdf.c
Normal file
145
crypto/krb5/krb5_kdf.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Kerberos key derivation.
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <crypto/hash.h>
|
||||
#include "internal.h"
|
||||
|
||||
/**
|
||||
* crypto_krb5_calc_PRFplus - Calculate PRF+ [RFC4402]
|
||||
* @krb5: The encryption type to use
|
||||
* @K: The protocol key for the pseudo-random function
|
||||
* @L: The length of the output
|
||||
* @S: The input octet string
|
||||
* @result: Result buffer, sized to krb5->prf_len
|
||||
* @gfp: Allocation restrictions
|
||||
*
|
||||
* Calculate the kerberos pseudo-random function, PRF+() by the following
|
||||
* method:
|
||||
*
|
||||
* PRF+(K, L, S) = truncate(L, T1 || T2 || .. || Tn)
|
||||
* Tn = PRF(K, n || S)
|
||||
* [rfc4402 sec 2]
|
||||
*/
|
||||
int crypto_krb5_calc_PRFplus(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *K,
|
||||
unsigned int L,
|
||||
const struct krb5_buffer *S,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct krb5_buffer T_series, Tn, n_S;
|
||||
void *buffer;
|
||||
int ret, n = 1;
|
||||
|
||||
Tn.len = krb5->prf_len;
|
||||
T_series.len = 0;
|
||||
n_S.len = 4 + S->len;
|
||||
|
||||
buffer = kzalloc(round16(L + Tn.len) + round16(n_S.len), gfp);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
T_series.data = buffer;
|
||||
n_S.data = buffer + round16(L + Tn.len);
|
||||
memcpy(n_S.data + 4, S->data, S->len);
|
||||
|
||||
while (T_series.len < L) {
|
||||
*(__be32 *)(n_S.data) = htonl(n);
|
||||
Tn.data = T_series.data + Tn.len * (n - 1);
|
||||
ret = krb5->profile->calc_PRF(krb5, K, &n_S, &Tn, gfp);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
T_series.len += Tn.len;
|
||||
n++;
|
||||
}
|
||||
|
||||
/* Truncate to L */
|
||||
memcpy(result->data, T_series.data, L);
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
kfree_sensitive(buffer);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5_calc_PRFplus);
|
||||
|
||||
/**
|
||||
* krb5_derive_Kc - Derive key Kc and install into a hash
|
||||
* @krb5: The encryption type to use
|
||||
* @TK: The base key
|
||||
* @usage: The key usage number
|
||||
* @key: Prepped buffer to store the key into
|
||||
* @gfp: Allocation restrictions
|
||||
*
|
||||
* Derive the Kerberos Kc checksumming key. The key is stored into the
|
||||
* prepared buffer.
|
||||
*/
|
||||
int krb5_derive_Kc(const struct krb5_enctype *krb5, const struct krb5_buffer *TK,
|
||||
u32 usage, struct krb5_buffer *key, gfp_t gfp)
|
||||
{
|
||||
u8 buf[5] __aligned(CRYPTO_MINALIGN);
|
||||
struct krb5_buffer usage_constant = { .len = 5, .data = buf };
|
||||
|
||||
*(__be32 *)buf = cpu_to_be32(usage);
|
||||
buf[4] = KEY_USAGE_SEED_CHECKSUM;
|
||||
|
||||
key->len = krb5->Kc_len;
|
||||
return krb5->profile->calc_Kc(krb5, TK, &usage_constant, key, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* krb5_derive_Ke - Derive key Ke and install into an skcipher
|
||||
* @krb5: The encryption type to use
|
||||
* @TK: The base key
|
||||
* @usage: The key usage number
|
||||
* @key: Prepped buffer to store the key into
|
||||
* @gfp: Allocation restrictions
|
||||
*
|
||||
* Derive the Kerberos Ke encryption key. The key is stored into the prepared
|
||||
* buffer.
|
||||
*/
|
||||
int krb5_derive_Ke(const struct krb5_enctype *krb5, const struct krb5_buffer *TK,
|
||||
u32 usage, struct krb5_buffer *key, gfp_t gfp)
|
||||
{
|
||||
u8 buf[5] __aligned(CRYPTO_MINALIGN);
|
||||
struct krb5_buffer usage_constant = { .len = 5, .data = buf };
|
||||
|
||||
*(__be32 *)buf = cpu_to_be32(usage);
|
||||
buf[4] = KEY_USAGE_SEED_ENCRYPTION;
|
||||
|
||||
key->len = krb5->Ke_len;
|
||||
return krb5->profile->calc_Ke(krb5, TK, &usage_constant, key, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* krb5_derive_Ki - Derive key Ki and install into a hash
|
||||
* @krb5: The encryption type to use
|
||||
* @TK: The base key
|
||||
* @usage: The key usage number
|
||||
* @key: Prepped buffer to store the key into
|
||||
* @gfp: Allocation restrictions
|
||||
*
|
||||
* Derive the Kerberos Ki integrity checksum key. The key is stored into the
|
||||
* prepared buffer.
|
||||
*/
|
||||
int krb5_derive_Ki(const struct krb5_enctype *krb5, const struct krb5_buffer *TK,
|
||||
u32 usage, struct krb5_buffer *key, gfp_t gfp)
|
||||
{
|
||||
u8 buf[5] __aligned(CRYPTO_MINALIGN);
|
||||
struct krb5_buffer usage_constant = { .len = 5, .data = buf };
|
||||
|
||||
*(__be32 *)buf = cpu_to_be32(usage);
|
||||
buf[4] = KEY_USAGE_SEED_INTEGRITY;
|
||||
|
||||
key->len = krb5->Ki_len;
|
||||
return krb5->profile->calc_Ki(krb5, TK, &usage_constant, key, gfp);
|
||||
}
|
||||
797
crypto/krb5/rfc3961_simplified.c
Normal file
797
crypto/krb5/rfc3961_simplified.c
Normal file
|
|
@ -0,0 +1,797 @@
|
|||
// 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)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/random.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/lcm.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <crypto/authenc.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <crypto/hash.h>
|
||||
#include "internal.h"
|
||||
|
||||
/* Maximum blocksize for the supported crypto algorithms */
|
||||
#define KRB5_MAX_BLOCKSIZE (16)
|
||||
|
||||
int crypto_shash_update_sg(struct shash_desc *desc, struct scatterlist *sg,
|
||||
size_t offset, size_t len)
|
||||
{
|
||||
do {
|
||||
int ret;
|
||||
|
||||
if (offset < sg->length) {
|
||||
struct page *page = sg_page(sg);
|
||||
void *p = kmap_local_page(page);
|
||||
void *q = p + sg->offset + offset;
|
||||
size_t seg = min_t(size_t, len, sg->length - offset);
|
||||
|
||||
ret = crypto_shash_update(desc, q, seg);
|
||||
kunmap_local(p);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
len -= seg;
|
||||
offset = 0;
|
||||
} else {
|
||||
offset -= sg->length;
|
||||
}
|
||||
} while (len > 0 && (sg = sg_next(sg)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rfc3961_do_encrypt(struct crypto_sync_skcipher *tfm, void *iv,
|
||||
const struct krb5_buffer *in, struct krb5_buffer *out)
|
||||
{
|
||||
struct scatterlist sg[1];
|
||||
u8 local_iv[KRB5_MAX_BLOCKSIZE] __aligned(KRB5_MAX_BLOCKSIZE) = {0};
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
int ret;
|
||||
|
||||
if (WARN_ON(in->len != out->len))
|
||||
return -EINVAL;
|
||||
if (out->len % crypto_sync_skcipher_blocksize(tfm) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (crypto_sync_skcipher_ivsize(tfm) > KRB5_MAX_BLOCKSIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (iv)
|
||||
memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
|
||||
|
||||
memcpy(out->data, in->data, out->len);
|
||||
sg_init_one(sg, out->data, out->len);
|
||||
|
||||
skcipher_request_set_sync_tfm(req, tfm);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, sg, sg, out->len, local_iv);
|
||||
|
||||
ret = crypto_skcipher_encrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate an unkeyed basic hash.
|
||||
*/
|
||||
static int rfc3961_calc_H(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *data,
|
||||
struct krb5_buffer *digest,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
size_t desc_size;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
tfm = crypto_alloc_shash(krb5->hash_name, 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
|
||||
|
||||
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
|
||||
|
||||
desc = kzalloc(desc_size, gfp);
|
||||
if (!desc)
|
||||
goto error_tfm;
|
||||
|
||||
digest->len = crypto_shash_digestsize(tfm);
|
||||
digest->data = kzalloc(digest->len, gfp);
|
||||
if (!digest->data)
|
||||
goto error_desc;
|
||||
|
||||
desc->tfm = tfm;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error_digest;
|
||||
|
||||
ret = crypto_shash_finup(desc, data->data, data->len, digest->data);
|
||||
if (ret < 0)
|
||||
goto error_digest;
|
||||
|
||||
goto error_desc;
|
||||
|
||||
error_digest:
|
||||
kfree_sensitive(digest->data);
|
||||
error_desc:
|
||||
kfree_sensitive(desc);
|
||||
error_tfm:
|
||||
crypto_free_shash(tfm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the n-fold function as described in rfc3961, sec 5.1
|
||||
* Taken from MIT Kerberos and modified.
|
||||
*/
|
||||
static void rfc3961_nfold(const struct krb5_buffer *source, struct krb5_buffer *result)
|
||||
{
|
||||
const u8 *in = source->data;
|
||||
u8 *out = result->data;
|
||||
unsigned long ulcm;
|
||||
unsigned int 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);
|
||||
|
||||
/* pull out the byte value itself */
|
||||
byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8) |
|
||||
(in[((inbits) - (msbit >> 3)) % inbits]))
|
||||
>> ((msbit & 7) + 1)) & 0xff;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate a derived key, DK(Base Key, Well-Known Constant)
|
||||
*
|
||||
* DK(Key, Constant) = random-to-key(DR(Key, Constant))
|
||||
* DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state))
|
||||
* K1 = E(Key, n-fold(Constant), initial-cipher-state)
|
||||
* K2 = E(Key, K1, initial-cipher-state)
|
||||
* K3 = E(Key, K2, initial-cipher-state)
|
||||
* K4 = ...
|
||||
* DR(Key, Constant) = k-truncate(K1 | K2 | K3 | K4 ...)
|
||||
* [rfc3961 sec 5.1]
|
||||
*/
|
||||
static int rfc3961_calc_DK(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *inkey,
|
||||
const struct krb5_buffer *in_constant,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
unsigned int blocksize, keybytes, keylength, n;
|
||||
struct krb5_buffer inblock, outblock, rawkey;
|
||||
struct crypto_sync_skcipher *cipher;
|
||||
int ret = -EINVAL;
|
||||
|
||||
blocksize = krb5->block_len;
|
||||
keybytes = krb5->key_bytes;
|
||||
keylength = krb5->key_len;
|
||||
|
||||
if (inkey->len != keylength || result->len != keylength)
|
||||
return -EINVAL;
|
||||
if (!krb5->random_to_key && result->len != keybytes)
|
||||
return -EINVAL;
|
||||
|
||||
cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
|
||||
if (IS_ERR(cipher)) {
|
||||
ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
|
||||
goto err_return;
|
||||
}
|
||||
ret = crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len);
|
||||
if (ret < 0)
|
||||
goto err_free_cipher;
|
||||
|
||||
ret = -ENOMEM;
|
||||
inblock.data = kzalloc(blocksize * 2 + keybytes, gfp);
|
||||
if (!inblock.data)
|
||||
goto err_free_cipher;
|
||||
|
||||
inblock.len = blocksize;
|
||||
outblock.data = inblock.data + blocksize;
|
||||
outblock.len = blocksize;
|
||||
rawkey.data = outblock.data + blocksize;
|
||||
rawkey.len = keybytes;
|
||||
|
||||
/* initialize the input block */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
kfree_sensitive(inblock.data);
|
||||
err_free_cipher:
|
||||
crypto_free_sync_skcipher(cipher);
|
||||
err_return:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate single encryption, E()
|
||||
*
|
||||
* E(Key, octets)
|
||||
*/
|
||||
static int rfc3961_calc_E(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *key,
|
||||
const struct krb5_buffer *in_data,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_sync_skcipher *cipher;
|
||||
int ret;
|
||||
|
||||
cipher = crypto_alloc_sync_skcipher(krb5->derivation_enc, 0, 0);
|
||||
if (IS_ERR(cipher)) {
|
||||
ret = (PTR_ERR(cipher) == -ENOENT) ? -ENOPKG : PTR_ERR(cipher);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = crypto_sync_skcipher_setkey(cipher, key->data, key->len);
|
||||
if (ret < 0)
|
||||
goto err_free;
|
||||
|
||||
ret = rfc3961_do_encrypt(cipher, NULL, in_data, result);
|
||||
|
||||
err_free:
|
||||
crypto_free_sync_skcipher(cipher);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the pseudo-random function, PRF().
|
||||
*
|
||||
* tmp1 = H(octet-string)
|
||||
* tmp2 = truncate tmp1 to multiple of m
|
||||
* PRF = E(DK(protocol-key, prfconstant), tmp2, initial-cipher-state)
|
||||
*
|
||||
* The "prfconstant" used in the PRF operation is the three-octet string
|
||||
* "prf".
|
||||
* [rfc3961 sec 5.3]
|
||||
*/
|
||||
static int rfc3961_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)
|
||||
{
|
||||
static const struct krb5_buffer prfconstant = { 3, "prf" };
|
||||
struct krb5_buffer derived_key;
|
||||
struct krb5_buffer tmp1, tmp2;
|
||||
unsigned int m = krb5->block_len;
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
if (result->len != krb5->prf_len)
|
||||
return -EINVAL;
|
||||
|
||||
tmp1.len = krb5->hash_len;
|
||||
derived_key.len = krb5->key_bytes;
|
||||
buffer = kzalloc(round16(tmp1.len) + round16(derived_key.len), gfp);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp1.data = buffer;
|
||||
derived_key.data = buffer + round16(tmp1.len);
|
||||
|
||||
ret = rfc3961_calc_H(krb5, octet_string, &tmp1, gfp);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
tmp2.len = tmp1.len & ~(m - 1);
|
||||
tmp2.data = tmp1.data;
|
||||
|
||||
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(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
unsigned int usage,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_authenc_key_param *param;
|
||||
struct krb5_buffer Ke, Ki;
|
||||
struct rtattr *rta;
|
||||
int ret;
|
||||
|
||||
Ke.len = krb5->Ke_len;
|
||||
Ki.len = krb5->Ki_len;
|
||||
setkey->len = RTA_LENGTH(sizeof(*param)) + Ke.len + Ki.len;
|
||||
setkey->data = kzalloc(setkey->len, GFP_KERNEL);
|
||||
if (!setkey->data)
|
||||
return -ENOMEM;
|
||||
|
||||
rta = setkey->data;
|
||||
rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(*param));
|
||||
param = RTA_DATA(rta);
|
||||
param->enckeylen = htonl(Ke.len);
|
||||
|
||||
Ki.data = (void *)(param + 1);
|
||||
Ke.data = Ki.data + Ki.len;
|
||||
|
||||
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(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *Ke,
|
||||
const struct krb5_buffer *Ki,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_authenc_key_param *param;
|
||||
struct rtattr *rta;
|
||||
|
||||
setkey->len = RTA_LENGTH(sizeof(*param)) + Ke->len + Ki->len;
|
||||
setkey->data = kzalloc(setkey->len, GFP_KERNEL);
|
||||
if (!setkey->data)
|
||||
return -ENOMEM;
|
||||
|
||||
rta = setkey->data;
|
||||
rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
|
||||
rta->rta_len = RTA_LENGTH(sizeof(*param));
|
||||
param = RTA_DATA(rta);
|
||||
param->enckeylen = htonl(Ke->len);
|
||||
memcpy((void *)(param + 1), Ki->data, Ki->len);
|
||||
memcpy((void *)(param + 1) + Ki->len, Ke->data, Ke->len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
unsigned int usage,
|
||||
struct krb5_buffer *setkey,
|
||||
gfp_t gfp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
setkey->len = krb5->Kc_len;
|
||||
setkey->data = kzalloc(setkey->len, GFP_KERNEL);
|
||||
if (!setkey->data)
|
||||
return -ENOMEM;
|
||||
|
||||
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(const struct krb5_enctype *krb5,
|
||||
const struct 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply encryption and checksumming functions to part of a scatterlist.
|
||||
*/
|
||||
ssize_t krb5_aead_encrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded)
|
||||
{
|
||||
struct aead_request *req;
|
||||
ssize_t ret, done;
|
||||
size_t bsize, base_len, secure_offset, secure_len, pad_len, cksum_offset;
|
||||
void *buffer;
|
||||
u8 *iv;
|
||||
|
||||
if (WARN_ON(data_offset != krb5->conf_len))
|
||||
return -EINVAL; /* Data is in wrong place */
|
||||
|
||||
secure_offset = 0;
|
||||
base_len = krb5->conf_len + data_len;
|
||||
pad_len = 0;
|
||||
secure_len = base_len + pad_len;
|
||||
cksum_offset = secure_len;
|
||||
if (WARN_ON(cksum_offset + krb5->cksum_len > sg_len))
|
||||
return -EFAULT;
|
||||
|
||||
bsize = krb5_aead_size(aead) +
|
||||
krb5_aead_ivsize(aead);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int 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;
|
||||
|
||||
bsize = krb5_aead_size(aead) +
|
||||
krb5_aead_ivsize(aead);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int 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;
|
||||
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int 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;
|
||||
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash) * 2;
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
cksum = buffer +
|
||||
krb5_shash_size(shash);
|
||||
cksum2 = buffer +
|
||||
krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
|
||||
/* Calculate the MIC */
|
||||
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;
|
||||
}
|
||||
|
||||
crypto_shash_update_sg(desc, sg, data_offset, data_len);
|
||||
crypto_shash_final(desc, cksum);
|
||||
|
||||
ret = -EFAULT;
|
||||
done = sg_pcopy_to_buffer(sg, nr_sg, cksum2, krb5->cksum_len, offset);
|
||||
if (done != krb5->cksum_len)
|
||||
goto error;
|
||||
|
||||
if (memcmp(cksum, cksum2, krb5->cksum_len) != 0) {
|
||||
ret = -EBADMSG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
*_offset += krb5->cksum_len;
|
||||
*_len -= krb5->cksum_len;
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
kfree_sensitive(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct krb5_crypto_profile rfc3961_simplified_profile = {
|
||||
.calc_PRF = rfc3961_calc_PRF,
|
||||
.calc_Kc = rfc3961_calc_DK,
|
||||
.calc_Ke = rfc3961_calc_DK,
|
||||
.calc_Ki = rfc3961_calc_DK,
|
||||
.derive_encrypt_keys = authenc_derive_encrypt_keys,
|
||||
.load_encrypt_keys = authenc_load_encrypt_keys,
|
||||
.derive_checksum_key = rfc3961_derive_checksum_key,
|
||||
.load_checksum_key = rfc3961_load_checksum_key,
|
||||
.encrypt = krb5_aead_encrypt,
|
||||
.decrypt = krb5_aead_decrypt,
|
||||
.get_mic = rfc3961_get_mic,
|
||||
.verify_mic = rfc3961_verify_mic,
|
||||
};
|
||||
115
crypto/krb5/rfc3962_aes.c
Normal file
115
crypto/krb5/rfc3962_aes.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/* rfc3962 Advanced Encryption Standard (AES) Encryption for Kerberos 5
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
const struct krb5_enctype krb5_aes128_cts_hmac_sha1_96 = {
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
.ctype = KRB5_CKSUMTYPE_HMAC_SHA1_96_AES128,
|
||||
.name = "aes128-cts-hmac-sha1-96",
|
||||
.encrypt_name = "krb5enc(hmac(sha1),cts(cbc(aes)))",
|
||||
.cksum_name = "hmac(sha1)",
|
||||
.hash_name = "sha1",
|
||||
.derivation_enc = "cts(cbc(aes))",
|
||||
.key_bytes = 16,
|
||||
.key_len = 16,
|
||||
.Kc_len = 16,
|
||||
.Ke_len = 16,
|
||||
.Ki_len = 16,
|
||||
.block_len = 16,
|
||||
.conf_len = 16,
|
||||
.cksum_len = 12,
|
||||
.hash_len = 20,
|
||||
.prf_len = 16,
|
||||
.keyed_cksum = true,
|
||||
.random_to_key = NULL, /* Identity */
|
||||
.profile = &rfc3961_simplified_profile,
|
||||
};
|
||||
|
||||
const struct krb5_enctype krb5_aes256_cts_hmac_sha1_96 = {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
.ctype = KRB5_CKSUMTYPE_HMAC_SHA1_96_AES256,
|
||||
.name = "aes256-cts-hmac-sha1-96",
|
||||
.encrypt_name = "krb5enc(hmac(sha1),cts(cbc(aes)))",
|
||||
.cksum_name = "hmac(sha1)",
|
||||
.hash_name = "sha1",
|
||||
.derivation_enc = "cts(cbc(aes))",
|
||||
.key_bytes = 32,
|
||||
.key_len = 32,
|
||||
.Kc_len = 32,
|
||||
.Ke_len = 32,
|
||||
.Ki_len = 32,
|
||||
.block_len = 16,
|
||||
.conf_len = 16,
|
||||
.cksum_len = 12,
|
||||
.hash_len = 20,
|
||||
.prf_len = 16,
|
||||
.keyed_cksum = true,
|
||||
.random_to_key = NULL, /* Identity */
|
||||
.profile = &rfc3961_simplified_profile,
|
||||
};
|
||||
237
crypto/krb5/rfc6803_camellia.c
Normal file
237
crypto/krb5/rfc6803_camellia.c
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* rfc6803 Camellia Encryption for Kerberos 5
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Calculate the key derivation function KDF-FEEDBACK_CMAC(key, constant)
|
||||
*
|
||||
* n = ceiling(k / 128)
|
||||
* K(0) = zeros
|
||||
* K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
|
||||
* DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n))
|
||||
* KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant))
|
||||
*
|
||||
* [rfc6803 sec 3]
|
||||
*/
|
||||
static int 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)
|
||||
{
|
||||
struct crypto_shash *shash;
|
||||
struct krb5_buffer K, data;
|
||||
struct shash_desc *desc;
|
||||
__be32 tmp;
|
||||
size_t bsize, offset, seg;
|
||||
void *buffer;
|
||||
u32 i = 0, k = result->len * 8;
|
||||
u8 *p;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
|
||||
if (IS_ERR(shash))
|
||||
return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
|
||||
ret = crypto_shash_setkey(shash, key->data, key->len);
|
||||
if (ret < 0)
|
||||
goto error_shash;
|
||||
|
||||
ret = -ENOMEM;
|
||||
K.len = crypto_shash_digestsize(shash);
|
||||
data.len = K.len + 4 + constant->len + 1 + 4;
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash) +
|
||||
crypto_roundup(K.len) +
|
||||
crypto_roundup(data.len);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
goto error_shash;
|
||||
|
||||
desc = buffer;
|
||||
desc->tfm = shash;
|
||||
|
||||
K.data = buffer +
|
||||
krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
data.data = buffer +
|
||||
krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash) +
|
||||
crypto_roundup(K.len);
|
||||
|
||||
p = data.data + K.len + 4;
|
||||
memcpy(p, constant->data, constant->len);
|
||||
p += constant->len;
|
||||
*p++ = 0x00;
|
||||
tmp = htonl(k);
|
||||
memcpy(p, &tmp, 4);
|
||||
p += 4;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (WARN_ON(p - (u8 *)data.data != data.len))
|
||||
goto error;
|
||||
|
||||
offset = 0;
|
||||
do {
|
||||
i++;
|
||||
p = data.data;
|
||||
memcpy(p, K.data, K.len);
|
||||
p += K.len;
|
||||
*(__be32 *)p = htonl(i);
|
||||
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
ret = crypto_shash_finup(desc, data.data, data.len, K.data);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
seg = min_t(size_t, result->len - offset, K.len);
|
||||
memcpy(result->data + offset, K.data, seg);
|
||||
offset += seg;
|
||||
} while (offset < result->len);
|
||||
|
||||
error:
|
||||
kfree_sensitive(buffer);
|
||||
error_shash:
|
||||
crypto_free_shash(shash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the pseudo-random function, PRF().
|
||||
*
|
||||
* Kp = KDF-FEEDBACK-CMAC(protocol-key, "prf")
|
||||
* PRF = CMAC(Kp, octet-string)
|
||||
* [rfc6803 sec 6]
|
||||
*/
|
||||
static int 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)
|
||||
{
|
||||
static const struct krb5_buffer prfconstant = { 3, "prf" };
|
||||
struct crypto_shash *shash;
|
||||
struct krb5_buffer Kp;
|
||||
struct shash_desc *desc;
|
||||
size_t bsize;
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
Kp.len = krb5->prf_len;
|
||||
|
||||
shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
|
||||
if (IS_ERR(shash))
|
||||
return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
|
||||
|
||||
ret = -EINVAL;
|
||||
if (result->len != crypto_shash_digestsize(shash))
|
||||
goto out_shash;
|
||||
|
||||
ret = -ENOMEM;
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash) +
|
||||
crypto_roundup(Kp.len);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
goto out_shash;
|
||||
|
||||
Kp.data = buffer +
|
||||
krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
|
||||
ret = rfc6803_calc_KDF_FEEDBACK_CMAC(krb5, protocol_key, &prfconstant,
|
||||
&Kp, gfp);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = crypto_shash_setkey(shash, Kp.data, Kp.len);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
desc = buffer;
|
||||
desc->tfm = shash;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = crypto_shash_finup(desc, octet_string->data, octet_string->len, result->data);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
kfree_sensitive(buffer);
|
||||
out_shash:
|
||||
crypto_free_shash(shash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const struct krb5_crypto_profile rfc6803_crypto_profile = {
|
||||
.calc_PRF = rfc6803_calc_PRF,
|
||||
.calc_Kc = rfc6803_calc_KDF_FEEDBACK_CMAC,
|
||||
.calc_Ke = rfc6803_calc_KDF_FEEDBACK_CMAC,
|
||||
.calc_Ki = rfc6803_calc_KDF_FEEDBACK_CMAC,
|
||||
.derive_encrypt_keys = authenc_derive_encrypt_keys,
|
||||
.load_encrypt_keys = authenc_load_encrypt_keys,
|
||||
.derive_checksum_key = rfc3961_derive_checksum_key,
|
||||
.load_checksum_key = rfc3961_load_checksum_key,
|
||||
.encrypt = krb5_aead_encrypt,
|
||||
.decrypt = krb5_aead_decrypt,
|
||||
.get_mic = rfc3961_get_mic,
|
||||
.verify_mic = rfc3961_verify_mic,
|
||||
};
|
||||
|
||||
const struct krb5_enctype krb5_camellia128_cts_cmac = {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.ctype = KRB5_CKSUMTYPE_CMAC_CAMELLIA128,
|
||||
.name = "camellia128-cts-cmac",
|
||||
.encrypt_name = "krb5enc(cmac(camellia),cts(cbc(camellia)))",
|
||||
.cksum_name = "cmac(camellia)",
|
||||
.hash_name = NULL,
|
||||
.derivation_enc = "cts(cbc(camellia))",
|
||||
.key_bytes = 16,
|
||||
.key_len = 16,
|
||||
.Kc_len = 16,
|
||||
.Ke_len = 16,
|
||||
.Ki_len = 16,
|
||||
.block_len = 16,
|
||||
.conf_len = 16,
|
||||
.cksum_len = 16,
|
||||
.hash_len = 16,
|
||||
.prf_len = 16,
|
||||
.keyed_cksum = true,
|
||||
.random_to_key = NULL, /* Identity */
|
||||
.profile = &rfc6803_crypto_profile,
|
||||
};
|
||||
|
||||
const struct krb5_enctype krb5_camellia256_cts_cmac = {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.ctype = KRB5_CKSUMTYPE_CMAC_CAMELLIA256,
|
||||
.name = "camellia256-cts-cmac",
|
||||
.encrypt_name = "krb5enc(cmac(camellia),cts(cbc(camellia)))",
|
||||
.cksum_name = "cmac(camellia)",
|
||||
.hash_name = NULL,
|
||||
.derivation_enc = "cts(cbc(camellia))",
|
||||
.key_bytes = 32,
|
||||
.key_len = 32,
|
||||
.Kc_len = 32,
|
||||
.Ke_len = 32,
|
||||
.Ki_len = 32,
|
||||
.block_len = 16,
|
||||
.conf_len = 16,
|
||||
.cksum_len = 16,
|
||||
.hash_len = 16,
|
||||
.prf_len = 16,
|
||||
.keyed_cksum = true,
|
||||
.random_to_key = NULL, /* Identity */
|
||||
.profile = &rfc6803_crypto_profile,
|
||||
};
|
||||
362
crypto/krb5/rfc8009_aes2.c
Normal file
362
crypto/krb5/rfc8009_aes2.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* rfc8009 AES Encryption with HMAC-SHA2 for Kerberos 5
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <crypto/authenc.h>
|
||||
#include "internal.h"
|
||||
|
||||
static const struct krb5_buffer rfc8009_no_context = { .len = 0, .data = "" };
|
||||
|
||||
/*
|
||||
* Calculate the key derivation function KDF-HMAC-SHA2(key, label, [context,] k)
|
||||
*
|
||||
* KDF-HMAC-SHA2(key, label, [context,] k) = k-truncate(K1)
|
||||
*
|
||||
* Using the appropriate one of:
|
||||
* K1 = HMAC-SHA-256(key, 0x00000001 | label | 0x00 | k)
|
||||
* K1 = HMAC-SHA-384(key, 0x00000001 | label | 0x00 | k)
|
||||
* K1 = HMAC-SHA-256(key, 0x00000001 | label | 0x00 | context | k)
|
||||
* K1 = HMAC-SHA-384(key, 0x00000001 | label | 0x00 | context | k)
|
||||
* [rfc8009 sec 3]
|
||||
*/
|
||||
static int rfc8009_calc_KDF_HMAC_SHA2(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *key,
|
||||
const struct krb5_buffer *label,
|
||||
const struct krb5_buffer *context,
|
||||
unsigned int k,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct crypto_shash *shash;
|
||||
struct krb5_buffer K1, data;
|
||||
struct shash_desc *desc;
|
||||
__be32 tmp;
|
||||
size_t bsize;
|
||||
void *buffer;
|
||||
u8 *p;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (WARN_ON(result->len != k / 8))
|
||||
return -EINVAL;
|
||||
|
||||
shash = crypto_alloc_shash(krb5->cksum_name, 0, 0);
|
||||
if (IS_ERR(shash))
|
||||
return (PTR_ERR(shash) == -ENOENT) ? -ENOPKG : PTR_ERR(shash);
|
||||
ret = crypto_shash_setkey(shash, key->data, key->len);
|
||||
if (ret < 0)
|
||||
goto error_shash;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (WARN_ON(crypto_shash_digestsize(shash) * 8 < k))
|
||||
goto error_shash;
|
||||
|
||||
ret = -ENOMEM;
|
||||
data.len = 4 + label->len + 1 + context->len + 4;
|
||||
bsize = krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash) +
|
||||
crypto_roundup(data.len);
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
goto error_shash;
|
||||
|
||||
desc = buffer;
|
||||
desc->tfm = shash;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
p = data.data = buffer +
|
||||
krb5_shash_size(shash) +
|
||||
krb5_digest_size(shash);
|
||||
*(__be32 *)p = htonl(0x00000001);
|
||||
p += 4;
|
||||
memcpy(p, label->data, label->len);
|
||||
p += label->len;
|
||||
*p++ = 0;
|
||||
memcpy(p, context->data, context->len);
|
||||
p += context->len;
|
||||
tmp = htonl(k);
|
||||
memcpy(p, &tmp, 4);
|
||||
p += 4;
|
||||
|
||||
ret = -EINVAL;
|
||||
if (WARN_ON(p - (u8 *)data.data != data.len))
|
||||
goto error;
|
||||
|
||||
K1.len = crypto_shash_digestsize(shash);
|
||||
K1.data = buffer +
|
||||
krb5_shash_size(shash);
|
||||
|
||||
ret = crypto_shash_finup(desc, data.data, data.len, K1.data);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
memcpy(result->data, K1.data, result->len);
|
||||
|
||||
error:
|
||||
kfree_sensitive(buffer);
|
||||
error_shash:
|
||||
crypto_free_shash(shash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the pseudo-random function, PRF().
|
||||
*
|
||||
* PRF = KDF-HMAC-SHA2(input-key, "prf", octet-string, 256)
|
||||
* PRF = KDF-HMAC-SHA2(input-key, "prf", octet-string, 384)
|
||||
*
|
||||
* The "prfconstant" used in the PRF operation is the three-octet string
|
||||
* "prf".
|
||||
* [rfc8009 sec 5]
|
||||
*/
|
||||
static int rfc8009_calc_PRF(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *input_key,
|
||||
const struct krb5_buffer *octet_string,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
static const struct krb5_buffer prfconstant = { 3, "prf" };
|
||||
|
||||
return rfc8009_calc_KDF_HMAC_SHA2(krb5, input_key, &prfconstant,
|
||||
octet_string, krb5->prf_len * 8,
|
||||
result, gfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Derive Ke.
|
||||
* Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 128)
|
||||
* Ke = KDF-HMAC-SHA2(base-key, usage | 0xAA, 256)
|
||||
* [rfc8009 sec 5]
|
||||
*/
|
||||
static int rfc8009_calc_Ke(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *base_key,
|
||||
const struct krb5_buffer *usage_constant,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
return rfc8009_calc_KDF_HMAC_SHA2(krb5, base_key, usage_constant,
|
||||
&rfc8009_no_context, krb5->key_bytes * 8,
|
||||
result, gfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Derive Kc/Ki
|
||||
* Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 128)
|
||||
* Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 128)
|
||||
* Kc = KDF-HMAC-SHA2(base-key, usage | 0x99, 192)
|
||||
* Ki = KDF-HMAC-SHA2(base-key, usage | 0x55, 192)
|
||||
* [rfc8009 sec 5]
|
||||
*/
|
||||
static int rfc8009_calc_Ki(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *base_key,
|
||||
const struct krb5_buffer *usage_constant,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp)
|
||||
{
|
||||
return rfc8009_calc_KDF_HMAC_SHA2(krb5, base_key, usage_constant,
|
||||
&rfc8009_no_context, krb5->cksum_len * 8,
|
||||
result, gfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply encryption and checksumming functions to a message. Unlike for
|
||||
* RFC3961, for RFC8009, we have to chuck the starting IV into the hash first.
|
||||
*/
|
||||
static ssize_t rfc8009_encrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg, size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded)
|
||||
{
|
||||
struct aead_request *req;
|
||||
struct scatterlist bsg[2];
|
||||
ssize_t ret, done;
|
||||
size_t bsize, base_len, secure_offset, secure_len, pad_len, cksum_offset;
|
||||
void *buffer;
|
||||
u8 *iv, *ad;
|
||||
|
||||
if (WARN_ON(data_offset != krb5->conf_len))
|
||||
return -EINVAL; /* Data is in wrong place */
|
||||
|
||||
secure_offset = 0;
|
||||
base_len = krb5->conf_len + data_len;
|
||||
pad_len = 0;
|
||||
secure_len = base_len + pad_len;
|
||||
cksum_offset = secure_len;
|
||||
if (WARN_ON(cksum_offset + krb5->cksum_len > sg_len))
|
||||
return -EFAULT;
|
||||
|
||||
bsize = krb5_aead_size(aead) +
|
||||
krb5_aead_ivsize(aead) * 2;
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
req = buffer;
|
||||
iv = buffer + krb5_aead_size(aead);
|
||||
ad = buffer + krb5_aead_size(aead) + krb5_aead_ivsize(aead);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* We need to include the starting IV in the hash. */
|
||||
sg_init_table(bsg, 2);
|
||||
sg_set_buf(&bsg[0], ad, krb5_aead_ivsize(aead));
|
||||
sg_chain(bsg, 2, sg);
|
||||
|
||||
/* Hash and encrypt the message. */
|
||||
aead_request_set_tfm(req, aead);
|
||||
aead_request_set_callback(req, 0, NULL, NULL);
|
||||
aead_request_set_ad(req, krb5_aead_ivsize(aead));
|
||||
aead_request_set_crypt(req, bsg, bsg, 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. Unlike for
|
||||
* RFC3961, for RFC8009, we have to chuck the starting IV into the hash first.
|
||||
*
|
||||
* The offset and length are updated to reflect the actual content of the
|
||||
* encrypted region.
|
||||
*/
|
||||
static int rfc8009_decrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len)
|
||||
{
|
||||
struct aead_request *req;
|
||||
struct scatterlist bsg[2];
|
||||
size_t bsize;
|
||||
void *buffer;
|
||||
int ret;
|
||||
u8 *iv, *ad;
|
||||
|
||||
if (WARN_ON(*_offset != 0))
|
||||
return -EINVAL; /* Can't set offset on aead */
|
||||
|
||||
if (*_len < krb5->conf_len + krb5->cksum_len)
|
||||
return -EPROTO;
|
||||
|
||||
bsize = krb5_aead_size(aead) +
|
||||
krb5_aead_ivsize(aead) * 2;
|
||||
buffer = kzalloc(bsize, GFP_NOFS);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
req = buffer;
|
||||
iv = buffer + krb5_aead_size(aead);
|
||||
ad = buffer + krb5_aead_size(aead) + krb5_aead_ivsize(aead);
|
||||
|
||||
/* We need to include the starting IV in the hash. */
|
||||
sg_init_table(bsg, 2);
|
||||
sg_set_buf(&bsg[0], ad, krb5_aead_ivsize(aead));
|
||||
sg_chain(bsg, 2, sg);
|
||||
|
||||
/* Decrypt the message and verify its checksum. */
|
||||
aead_request_set_tfm(req, aead);
|
||||
aead_request_set_callback(req, 0, NULL, NULL);
|
||||
aead_request_set_ad(req, krb5_aead_ivsize(aead));
|
||||
aead_request_set_crypt(req, bsg, bsg, *_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;
|
||||
}
|
||||
|
||||
static const struct krb5_crypto_profile rfc8009_crypto_profile = {
|
||||
.calc_PRF = rfc8009_calc_PRF,
|
||||
.calc_Kc = rfc8009_calc_Ki,
|
||||
.calc_Ke = rfc8009_calc_Ke,
|
||||
.calc_Ki = rfc8009_calc_Ki,
|
||||
.derive_encrypt_keys = authenc_derive_encrypt_keys,
|
||||
.load_encrypt_keys = authenc_load_encrypt_keys,
|
||||
.derive_checksum_key = rfc3961_derive_checksum_key,
|
||||
.load_checksum_key = rfc3961_load_checksum_key,
|
||||
.encrypt = rfc8009_encrypt,
|
||||
.decrypt = rfc8009_decrypt,
|
||||
.get_mic = rfc3961_get_mic,
|
||||
.verify_mic = rfc3961_verify_mic,
|
||||
};
|
||||
|
||||
const struct krb5_enctype krb5_aes128_cts_hmac_sha256_128 = {
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.ctype = KRB5_CKSUMTYPE_HMAC_SHA256_128_AES128,
|
||||
.name = "aes128-cts-hmac-sha256-128",
|
||||
.encrypt_name = "authenc(hmac(sha256),cts(cbc(aes)))",
|
||||
.cksum_name = "hmac(sha256)",
|
||||
.hash_name = "sha256",
|
||||
.derivation_enc = "cts(cbc(aes))",
|
||||
.key_bytes = 16,
|
||||
.key_len = 16,
|
||||
.Kc_len = 16,
|
||||
.Ke_len = 16,
|
||||
.Ki_len = 16,
|
||||
.block_len = 16,
|
||||
.conf_len = 16,
|
||||
.cksum_len = 16,
|
||||
.hash_len = 20,
|
||||
.prf_len = 32,
|
||||
.keyed_cksum = true,
|
||||
.random_to_key = NULL, /* Identity */
|
||||
.profile = &rfc8009_crypto_profile,
|
||||
};
|
||||
|
||||
const struct krb5_enctype krb5_aes256_cts_hmac_sha384_192 = {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.ctype = KRB5_CKSUMTYPE_HMAC_SHA384_192_AES256,
|
||||
.name = "aes256-cts-hmac-sha384-192",
|
||||
.encrypt_name = "authenc(hmac(sha384),cts(cbc(aes)))",
|
||||
.cksum_name = "hmac(sha384)",
|
||||
.hash_name = "sha384",
|
||||
.derivation_enc = "cts(cbc(aes))",
|
||||
.key_bytes = 32,
|
||||
.key_len = 32,
|
||||
.Kc_len = 24,
|
||||
.Ke_len = 32,
|
||||
.Ki_len = 24,
|
||||
.block_len = 16,
|
||||
.conf_len = 16,
|
||||
.cksum_len = 24,
|
||||
.hash_len = 20,
|
||||
.prf_len = 48,
|
||||
.keyed_cksum = true,
|
||||
.random_to_key = NULL, /* Identity */
|
||||
.profile = &rfc8009_crypto_profile,
|
||||
};
|
||||
544
crypto/krb5/selftest.c
Normal file
544
crypto/krb5/selftest.c
Normal file
|
|
@ -0,0 +1,544 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Kerberos library self-testing
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <crypto/hash.h>
|
||||
#include "internal.h"
|
||||
|
||||
#define VALID(X) \
|
||||
({ \
|
||||
bool __x = (X); \
|
||||
if (__x) { \
|
||||
pr_warn("!!! TESTINVAL %s:%u\n", __FILE__, __LINE__); \
|
||||
ret = -EBADMSG; \
|
||||
} \
|
||||
__x; \
|
||||
})
|
||||
|
||||
#define CHECK(X) \
|
||||
({ \
|
||||
bool __x = (X); \
|
||||
if (__x) { \
|
||||
pr_warn("!!! TESTFAIL %s:%u\n", __FILE__, __LINE__); \
|
||||
ret = -EBADMSG; \
|
||||
} \
|
||||
__x; \
|
||||
})
|
||||
|
||||
enum which_key {
|
||||
TEST_KC, TEST_KE, TEST_KI,
|
||||
};
|
||||
|
||||
#if 0
|
||||
static void dump_sg(struct scatterlist *sg, unsigned int limit)
|
||||
{
|
||||
unsigned int index = 0, n = 0;
|
||||
|
||||
for (; sg && limit > 0; sg = sg_next(sg)) {
|
||||
unsigned int off = sg->offset, len = umin(sg->length, limit);
|
||||
const void *p = kmap_local_page(sg_page(sg));
|
||||
|
||||
limit -= len;
|
||||
while (len > 0) {
|
||||
unsigned int part = umin(len, 32);
|
||||
|
||||
pr_notice("[%x] %04x: %*phN\n", n, index, part, p + off);
|
||||
index += part;
|
||||
off += part;
|
||||
len -= part;
|
||||
}
|
||||
|
||||
kunmap_local(p);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int prep_buf(struct krb5_buffer *buf)
|
||||
{
|
||||
buf->data = kmalloc(buf->len, GFP_KERNEL);
|
||||
if (!buf->data)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PREP_BUF(BUF, LEN) \
|
||||
do { \
|
||||
(BUF)->len = (LEN); \
|
||||
ret = prep_buf((BUF)); \
|
||||
if (ret < 0) \
|
||||
goto out; \
|
||||
} while (0)
|
||||
|
||||
static int load_buf(struct krb5_buffer *buf, const char *from)
|
||||
{
|
||||
size_t len = strlen(from);
|
||||
int ret;
|
||||
|
||||
if (len > 1 && from[0] == '\'') {
|
||||
PREP_BUF(buf, len - 1);
|
||||
memcpy(buf->data, from + 1, len - 1);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (VALID(len & 1))
|
||||
return -EINVAL;
|
||||
|
||||
PREP_BUF(buf, len / 2);
|
||||
ret = hex2bin(buf->data, from, buf->len);
|
||||
if (ret < 0) {
|
||||
VALID(1);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define LOAD_BUF(BUF, FROM) do { ret = load_buf(BUF, FROM); if (ret < 0) goto out; } while (0)
|
||||
|
||||
static void clear_buf(struct krb5_buffer *buf)
|
||||
{
|
||||
kfree(buf->data);
|
||||
buf->len = 0;
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a pseudo-random function check.
|
||||
*/
|
||||
static int krb5_test_one_prf(const struct krb5_prf_test *test)
|
||||
{
|
||||
const struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test->etype);
|
||||
struct krb5_buffer key = {}, octet = {}, result = {}, prf = {};
|
||||
int ret;
|
||||
|
||||
if (!krb5)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pr_notice("Running %s %s\n", krb5->name, test->name);
|
||||
|
||||
LOAD_BUF(&key, test->key);
|
||||
LOAD_BUF(&octet, test->octet);
|
||||
LOAD_BUF(&prf, test->prf);
|
||||
PREP_BUF(&result, krb5->prf_len);
|
||||
|
||||
if (VALID(result.len != prf.len)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = krb5->profile->calc_PRF(krb5, &key, &octet, &result, GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
CHECK(1);
|
||||
pr_warn("PRF calculation failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(result.data, prf.data, result.len) != 0) {
|
||||
CHECK(1);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
clear_buf(&result);
|
||||
clear_buf(&octet);
|
||||
clear_buf(&key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a key derivation check.
|
||||
*/
|
||||
static int krb5_test_key(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *base_key,
|
||||
const struct krb5_key_test_one *test,
|
||||
enum which_key which)
|
||||
{
|
||||
struct krb5_buffer key = {}, result = {};
|
||||
int ret;
|
||||
|
||||
LOAD_BUF(&key, test->key);
|
||||
PREP_BUF(&result, key.len);
|
||||
|
||||
switch (which) {
|
||||
case TEST_KC:
|
||||
ret = krb5_derive_Kc(krb5, base_key, test->use, &result, GFP_KERNEL);
|
||||
break;
|
||||
case TEST_KE:
|
||||
ret = krb5_derive_Ke(krb5, base_key, test->use, &result, GFP_KERNEL);
|
||||
break;
|
||||
case TEST_KI:
|
||||
ret = krb5_derive_Ki(krb5, base_key, test->use, &result, GFP_KERNEL);
|
||||
break;
|
||||
default:
|
||||
VALID(1);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Key derivation failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(result.data, key.data, result.len) != 0) {
|
||||
CHECK(1);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
clear_buf(&key);
|
||||
clear_buf(&result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int krb5_test_one_key(const struct krb5_key_test *test)
|
||||
{
|
||||
const struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test->etype);
|
||||
struct krb5_buffer base_key = {};
|
||||
int ret;
|
||||
|
||||
if (!krb5)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pr_notice("Running %s %s\n", krb5->name, test->name);
|
||||
|
||||
LOAD_BUF(&base_key, test->key);
|
||||
|
||||
ret = krb5_test_key(krb5, &base_key, &test->Kc, TEST_KC);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = krb5_test_key(krb5, &base_key, &test->Ke, TEST_KE);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = krb5_test_key(krb5, &base_key, &test->Ki, TEST_KI);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
clear_buf(&base_key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform an encryption test.
|
||||
*/
|
||||
static int krb5_test_one_enc(const struct krb5_enc_test *test, void *buf)
|
||||
{
|
||||
const struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test->etype);
|
||||
struct crypto_aead *ci = NULL;
|
||||
struct krb5_buffer K0 = {}, Ke = {}, Ki = {}, keys = {};
|
||||
struct krb5_buffer conf = {}, plain = {}, ct = {};
|
||||
struct scatterlist sg[1];
|
||||
size_t data_len, data_offset, message_len;
|
||||
int ret;
|
||||
|
||||
if (!krb5)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pr_notice("Running %s %s\n", krb5->name, test->name);
|
||||
|
||||
/* Load the test data into binary buffers. */
|
||||
LOAD_BUF(&conf, test->conf);
|
||||
LOAD_BUF(&plain, test->plain);
|
||||
LOAD_BUF(&ct, test->ct);
|
||||
|
||||
if (test->K0) {
|
||||
LOAD_BUF(&K0, test->K0);
|
||||
} else {
|
||||
LOAD_BUF(&Ke, test->Ke);
|
||||
LOAD_BUF(&Ki, test->Ki);
|
||||
|
||||
ret = krb5->profile->load_encrypt_keys(krb5, &Ke, &Ki, &keys, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (VALID(conf.len != krb5->conf_len) ||
|
||||
VALID(ct.len != krb5->conf_len + plain.len + krb5->cksum_len))
|
||||
goto out;
|
||||
|
||||
data_len = plain.len;
|
||||
message_len = crypto_krb5_how_much_buffer(krb5, KRB5_ENCRYPT_MODE,
|
||||
data_len, &data_offset);
|
||||
|
||||
if (CHECK(message_len != ct.len)) {
|
||||
pr_warn("Encrypted length mismatch %zu != %u\n", message_len, ct.len);
|
||||
goto out;
|
||||
}
|
||||
if (CHECK(data_offset != conf.len)) {
|
||||
pr_warn("Data offset mismatch %zu != %u\n", data_offset, conf.len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(buf, conf.data, conf.len);
|
||||
memcpy(buf + data_offset, plain.data, plain.len);
|
||||
|
||||
/* Allocate a crypto object and set its key. */
|
||||
if (test->K0)
|
||||
ci = crypto_krb5_prepare_encryption(krb5, &K0, test->usage, GFP_KERNEL);
|
||||
else
|
||||
ci = krb5_prepare_encryption(krb5, &keys, GFP_KERNEL);
|
||||
|
||||
if (IS_ERR(ci)) {
|
||||
ret = PTR_ERR(ci);
|
||||
ci = NULL;
|
||||
pr_err("Couldn't alloc AEAD %s: %d\n", krb5->encrypt_name, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Encrypt the message. */
|
||||
sg_init_one(sg, buf, message_len);
|
||||
ret = crypto_krb5_encrypt(krb5, ci, sg, 1, message_len,
|
||||
data_offset, data_len, true);
|
||||
if (ret < 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Encryption failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
if (ret != message_len) {
|
||||
CHECK(1);
|
||||
pr_warn("Encrypted message wrong size %x != %zx\n", ret, message_len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(buf, ct.data, ct.len) != 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Ciphertext mismatch\n");
|
||||
pr_warn("BUF %*phN\n", ct.len, buf);
|
||||
pr_warn("CT %*phN\n", ct.len, ct.data);
|
||||
pr_warn("PT %*phN%*phN\n", conf.len, conf.data, plain.len, plain.data);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Decrypt the encrypted message. */
|
||||
data_offset = 0;
|
||||
data_len = message_len;
|
||||
ret = crypto_krb5_decrypt(krb5, ci, sg, 1, &data_offset, &data_len);
|
||||
if (ret < 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Decryption failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (CHECK(data_offset != conf.len) ||
|
||||
CHECK(data_len != plain.len))
|
||||
goto out;
|
||||
|
||||
if (memcmp(buf, conf.data, conf.len) != 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Confounder mismatch\n");
|
||||
pr_warn("ENC %*phN\n", conf.len, buf);
|
||||
pr_warn("DEC %*phN\n", conf.len, conf.data);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(buf + conf.len, plain.data, plain.len) != 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Plaintext mismatch\n");
|
||||
pr_warn("BUF %*phN\n", plain.len, buf + conf.len);
|
||||
pr_warn("PT %*phN\n", plain.len, plain.data);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
clear_buf(&ct);
|
||||
clear_buf(&plain);
|
||||
clear_buf(&conf);
|
||||
clear_buf(&keys);
|
||||
clear_buf(&Ki);
|
||||
clear_buf(&Ke);
|
||||
clear_buf(&K0);
|
||||
if (ci)
|
||||
crypto_free_aead(ci);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a checksum test.
|
||||
*/
|
||||
static int krb5_test_one_mic(const struct krb5_mic_test *test, void *buf)
|
||||
{
|
||||
const struct krb5_enctype *krb5 = crypto_krb5_find_enctype(test->etype);
|
||||
struct crypto_shash *ci = NULL;
|
||||
struct scatterlist sg[1];
|
||||
struct krb5_buffer K0 = {}, Kc = {}, keys = {}, plain = {}, mic = {};
|
||||
size_t offset, len, message_len;
|
||||
int ret;
|
||||
|
||||
if (!krb5)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pr_notice("Running %s %s\n", krb5->name, test->name);
|
||||
|
||||
/* Allocate a crypto object and set its key. */
|
||||
if (test->K0) {
|
||||
LOAD_BUF(&K0, test->K0);
|
||||
ci = crypto_krb5_prepare_checksum(krb5, &K0, test->usage, GFP_KERNEL);
|
||||
} else {
|
||||
LOAD_BUF(&Kc, test->Kc);
|
||||
|
||||
ret = krb5->profile->load_checksum_key(krb5, &Kc, &keys, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ci = krb5_prepare_checksum(krb5, &Kc, GFP_KERNEL);
|
||||
}
|
||||
if (IS_ERR(ci)) {
|
||||
ret = PTR_ERR(ci);
|
||||
ci = NULL;
|
||||
pr_err("Couldn't alloc shash %s: %d\n", krb5->cksum_name, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Load the test data into binary buffers. */
|
||||
LOAD_BUF(&plain, test->plain);
|
||||
LOAD_BUF(&mic, test->mic);
|
||||
|
||||
len = plain.len;
|
||||
message_len = crypto_krb5_how_much_buffer(krb5, KRB5_CHECKSUM_MODE,
|
||||
len, &offset);
|
||||
|
||||
if (CHECK(message_len != mic.len + plain.len)) {
|
||||
pr_warn("MIC length mismatch %zu != %u\n",
|
||||
message_len, mic.len + plain.len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(buf + offset, plain.data, plain.len);
|
||||
|
||||
/* Generate a MIC generation request. */
|
||||
sg_init_one(sg, buf, 1024);
|
||||
|
||||
ret = crypto_krb5_get_mic(krb5, ci, NULL, sg, 1, 1024,
|
||||
krb5->cksum_len, plain.len);
|
||||
if (ret < 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Get MIC failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
len = ret;
|
||||
|
||||
if (CHECK(len != plain.len + mic.len)) {
|
||||
pr_warn("MIC length mismatch %zu != %u\n", len, plain.len + mic.len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(buf, mic.data, mic.len) != 0) {
|
||||
CHECK(1);
|
||||
pr_warn("MIC mismatch\n");
|
||||
pr_warn("BUF %*phN\n", mic.len, buf);
|
||||
pr_warn("MIC %*phN\n", mic.len, mic.data);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Generate a verification request. */
|
||||
offset = 0;
|
||||
ret = crypto_krb5_verify_mic(krb5, ci, NULL, sg, 1, &offset, &len);
|
||||
if (ret < 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Verify MIC failed %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (CHECK(offset != mic.len) ||
|
||||
CHECK(len != plain.len))
|
||||
goto out;
|
||||
|
||||
if (memcmp(buf + offset, plain.data, plain.len) != 0) {
|
||||
CHECK(1);
|
||||
pr_warn("Plaintext mismatch\n");
|
||||
pr_warn("BUF %*phN\n", plain.len, buf + offset);
|
||||
pr_warn("PT %*phN\n", plain.len, plain.data);
|
||||
ret = -EKEYREJECTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
clear_buf(&mic);
|
||||
clear_buf(&plain);
|
||||
clear_buf(&keys);
|
||||
clear_buf(&K0);
|
||||
clear_buf(&Kc);
|
||||
if (ci)
|
||||
crypto_free_shash(ci);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int krb5_selftest(void)
|
||||
{
|
||||
void *buf;
|
||||
int ret = 0, i;
|
||||
|
||||
buf = kmalloc(4096, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
pr_notice("\n");
|
||||
pr_notice("Running selftests\n");
|
||||
|
||||
for (i = 0; krb5_prf_tests[i].name; i++) {
|
||||
ret = krb5_test_one_prf(&krb5_prf_tests[i]);
|
||||
if (ret < 0) {
|
||||
if (ret != -EOPNOTSUPP)
|
||||
goto out;
|
||||
pr_notice("Skipping %s\n", krb5_prf_tests[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; krb5_key_tests[i].name; i++) {
|
||||
ret = krb5_test_one_key(&krb5_key_tests[i]);
|
||||
if (ret < 0) {
|
||||
if (ret != -EOPNOTSUPP)
|
||||
goto out;
|
||||
pr_notice("Skipping %s\n", krb5_key_tests[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; krb5_enc_tests[i].name; i++) {
|
||||
memset(buf, 0x5a, 4096);
|
||||
ret = krb5_test_one_enc(&krb5_enc_tests[i], buf);
|
||||
if (ret < 0) {
|
||||
if (ret != -EOPNOTSUPP)
|
||||
goto out;
|
||||
pr_notice("Skipping %s\n", krb5_enc_tests[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; krb5_mic_tests[i].name; i++) {
|
||||
memset(buf, 0x5a, 4096);
|
||||
ret = krb5_test_one_mic(&krb5_mic_tests[i], buf);
|
||||
if (ret < 0) {
|
||||
if (ret != -EOPNOTSUPP)
|
||||
goto out;
|
||||
pr_notice("Skipping %s\n", krb5_mic_tests[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
pr_notice("Selftests %s\n", ret == 0 ? "succeeded" : "failed");
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
291
crypto/krb5/selftest_data.c
Normal file
291
crypto/krb5/selftest_data.c
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Data for Kerberos library self-testing
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Pseudo-random function tests.
|
||||
*/
|
||||
const struct krb5_prf_test krb5_prf_tests[] = {
|
||||
/* rfc8009 Appendix A */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "prf",
|
||||
.key = "3705D96080C17728A0E800EAB6E0D23C",
|
||||
.octet = "74657374",
|
||||
.prf = "9D188616F63852FE86915BB840B4A886FF3E6BB0F819B49B893393D393854295",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "prf",
|
||||
.key = "6D404D37FAF79F9DF0D33568D320669800EB4836472EA8A026D16B7182460C52",
|
||||
.octet = "74657374",
|
||||
.prf =
|
||||
"9801F69A368C2BF675E59521E177D9A07F67EFE1CFDE8D3C8D6F6A0256E3B17D"
|
||||
"B3C1B62AD1B8553360D17367EB1514D2",
|
||||
},
|
||||
{/* END */}
|
||||
};
|
||||
|
||||
/*
|
||||
* Key derivation tests.
|
||||
*/
|
||||
const struct krb5_key_test krb5_key_tests[] = {
|
||||
/* rfc8009 Appendix A */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "key",
|
||||
.key = "3705D96080C17728A0E800EAB6E0D23C",
|
||||
.Kc.use = 0x00000002,
|
||||
.Kc.key = "B31A018A48F54776F403E9A396325DC3",
|
||||
.Ke.use = 0x00000002,
|
||||
.Ke.key = "9B197DD1E8C5609D6E67C3E37C62C72E",
|
||||
.Ki.use = 0x00000002,
|
||||
.Ki.key = "9FDA0E56AB2D85E1569A688696C26A6C",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "key",
|
||||
.key = "6D404D37FAF79F9DF0D33568D320669800EB4836472EA8A026D16B7182460C52",
|
||||
.Kc.use = 0x00000002,
|
||||
.Kc.key = "EF5718BE86CC84963D8BBB5031E9F5C4BA41F28FAF69E73D",
|
||||
.Ke.use = 0x00000002,
|
||||
.Ke.key = "56AB22BEE63D82D7BC5227F6773F8EA7A5EB1C825160C38312980C442E5C7E49",
|
||||
.Ki.use = 0x00000002,
|
||||
.Ki.key = "69B16514E3CD8E56B82010D5C73012B622C4D00FFC23ED1F",
|
||||
},
|
||||
/* rfc6803 sec 10 */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "key",
|
||||
.key = "57D0297298FFD9D35DE5A47FB4BDE24B",
|
||||
.Kc.use = 0x00000002,
|
||||
.Kc.key = "D155775A209D05F02B38D42A389E5A56",
|
||||
.Ke.use = 0x00000002,
|
||||
.Ke.key = "64DF83F85A532F17577D8C37035796AB",
|
||||
.Ki.use = 0x00000002,
|
||||
.Ki.key = "3E4FBDF30FB8259C425CB6C96F1F4635",
|
||||
},
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "key",
|
||||
.key = "B9D6828B2056B7BE656D88A123B1FAC68214AC2B727ECF5F69AFE0C4DF2A6D2C",
|
||||
.Kc.use = 0x00000002,
|
||||
.Kc.key = "E467F9A9552BC7D3155A6220AF9C19220EEED4FF78B0D1E6A1544991461A9E50",
|
||||
.Ke.use = 0x00000002,
|
||||
.Ke.key = "412AEFC362A7285FC3966C6A5181E7605AE675235B6D549FBFC9AB6630A4C604",
|
||||
.Ki.use = 0x00000002,
|
||||
.Ki.key = "FA624FA0E523993FA388AEFDC67E67EBCD8C08E8A0246B1D73B0D1DD9FC582B0",
|
||||
},
|
||||
{/* END */}
|
||||
};
|
||||
|
||||
/*
|
||||
* Encryption tests.
|
||||
*/
|
||||
const struct krb5_enc_test krb5_enc_tests[] = {
|
||||
/* rfc8009 Appendix A */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "enc no plain",
|
||||
.plain = "",
|
||||
.conf = "7E5895EAF2672435BAD817F545A37148",
|
||||
.Ke = "9B197DD1E8C5609D6E67C3E37C62C72E",
|
||||
.Ki = "9FDA0E56AB2D85E1569A688696C26A6C",
|
||||
.ct = "EF85FB890BB8472F4DAB20394DCA781DAD877EDA39D50C870C0D5A0A8E48C718",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "enc plain<block",
|
||||
.plain = "000102030405",
|
||||
.conf = "7BCA285E2FD4130FB55B1A5C83BC5B24",
|
||||
.Ke = "9B197DD1E8C5609D6E67C3E37C62C72E",
|
||||
.Ki = "9FDA0E56AB2D85E1569A688696C26A6C",
|
||||
.ct = "84D7F30754ED987BAB0BF3506BEB09CFB55402CEF7E6877CE99E247E52D16ED4421DFDF8976C",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "enc plain==block",
|
||||
.plain = "000102030405060708090A0B0C0D0E0F",
|
||||
.conf = "56AB21713FF62C0A1457200F6FA9948F",
|
||||
.Ke = "9B197DD1E8C5609D6E67C3E37C62C72E",
|
||||
.Ki = "9FDA0E56AB2D85E1569A688696C26A6C",
|
||||
.ct = "3517D640F50DDC8AD3628722B3569D2AE07493FA8263254080EA65C1008E8FC295FB4852E7D83E1E7C48C37EEBE6B0D3",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "enc plain>block",
|
||||
.plain = "000102030405060708090A0B0C0D0E0F1011121314",
|
||||
.conf = "A7A4E29A4728CE10664FB64E49AD3FAC",
|
||||
.Ke = "9B197DD1E8C5609D6E67C3E37C62C72E",
|
||||
.Ki = "9FDA0E56AB2D85E1569A688696C26A6C",
|
||||
.ct = "720F73B18D9859CD6CCB4346115CD336C70F58EDC0C4437C5573544C31C813BCE1E6D072C186B39A413C2F92CA9B8334A287FFCBFC",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "enc no plain",
|
||||
.plain = "",
|
||||
.conf = "F764E9FA15C276478B2C7D0C4E5F58E4",
|
||||
.Ke = "56AB22BEE63D82D7BC5227F6773F8EA7A5EB1C825160C38312980C442E5C7E49",
|
||||
.Ki = "69B16514E3CD8E56B82010D5C73012B622C4D00FFC23ED1F",
|
||||
.ct = "41F53FA5BFE7026D91FAF9BE959195A058707273A96A40F0A01960621AC612748B9BBFBE7EB4CE3C",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "enc plain<block",
|
||||
.plain = "000102030405",
|
||||
.conf = "B80D3251C1F6471494256FFE712D0B9A",
|
||||
.Ke = "56AB22BEE63D82D7BC5227F6773F8EA7A5EB1C825160C38312980C442E5C7E49",
|
||||
.Ki = "69B16514E3CD8E56B82010D5C73012B622C4D00FFC23ED1F",
|
||||
.ct = "4ED7B37C2BCAC8F74F23C1CF07E62BC7B75FB3F637B9F559C7F664F69EAB7B6092237526EA0D1F61CB20D69D10F2",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "enc plain==block",
|
||||
.plain = "000102030405060708090A0B0C0D0E0F",
|
||||
.conf = "53BF8A0D105265D4E276428624CE5E63",
|
||||
.Ke = "56AB22BEE63D82D7BC5227F6773F8EA7A5EB1C825160C38312980C442E5C7E49",
|
||||
.Ki = "69B16514E3CD8E56B82010D5C73012B622C4D00FFC23ED1F",
|
||||
.ct = "BC47FFEC7998EB91E8115CF8D19DAC4BBBE2E163E87DD37F49BECA92027764F68CF51F14D798C2273F35DF574D1F932E40C4FF255B36A266",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "enc plain>block",
|
||||
.plain = "000102030405060708090A0B0C0D0E0F1011121314",
|
||||
.conf = "763E65367E864F02F55153C7E3B58AF1",
|
||||
.Ke = "56AB22BEE63D82D7BC5227F6773F8EA7A5EB1C825160C38312980C442E5C7E49",
|
||||
.Ki = "69B16514E3CD8E56B82010D5C73012B622C4D00FFC23ED1F",
|
||||
.ct = "40013E2DF58E8751957D2878BCD2D6FE101CCFD556CB1EAE79DB3C3EE86429F2B2A602AC86FEF6ECB647D6295FAE077A1FEB517508D2C16B4192E01F62",
|
||||
},
|
||||
/* rfc6803 sec 10 */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "enc no plain",
|
||||
.plain = "",
|
||||
.conf = "B69822A19A6B09C0EBC8557D1F1B6C0A",
|
||||
.K0 = "1DC46A8D763F4F93742BCBA3387576C3",
|
||||
.usage = 0,
|
||||
.ct = "C466F1871069921EDB7C6FDE244A52DB0BA10EDC197BDB8006658CA3CCCE6EB8",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "enc 1 plain",
|
||||
.plain = "'1",
|
||||
.conf = "6F2FC3C2A166FD8898967A83DE9596D9",
|
||||
.K0 = "5027BC231D0F3A9D23333F1CA6FDBE7C",
|
||||
.usage = 1,
|
||||
.ct = "842D21FD950311C0DD464A3F4BE8D6DA88A56D559C9B47D3F9A85067AF661559B8",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "enc 9 plain",
|
||||
.plain = "'9 bytesss",
|
||||
.conf = "A5B4A71E077AEEF93C8763C18FDB1F10",
|
||||
.K0 = "A1BB61E805F9BA6DDE8FDBDDC05CDEA0",
|
||||
.usage = 2,
|
||||
.ct = "619FF072E36286FF0A28DEB3A352EC0D0EDF5C5160D663C901758CCF9D1ED33D71DB8F23AABF8348A0",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "enc 13 plain",
|
||||
.plain = "'13 bytes byte",
|
||||
.conf = "19FEE40D810C524B5B22F01874C693DA",
|
||||
.K0 = "2CA27A5FAF5532244506434E1CEF6676",
|
||||
.usage = 3,
|
||||
.ct = "B8ECA3167AE6315512E59F98A7C500205E5F63FF3BB389AF1C41A21D640D8615C9ED3FBEB05AB6ACB67689B5EA",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "enc 30 plain",
|
||||
.plain = "'30 bytes bytes bytes bytes byt",
|
||||
.conf = "CA7A7AB4BE192DABD603506DB19C39E2",
|
||||
.K0 = "7824F8C16F83FF354C6BF7515B973F43",
|
||||
.usage = 4,
|
||||
.ct = "A26A3905A4FFD5816B7B1E27380D08090C8EC1F304496E1ABDCD2BDCD1DFFC660989E117A713DDBB57A4146C1587CBA4356665591D2240282F5842B105A5",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "enc no plain",
|
||||
.plain = "",
|
||||
.conf = "3CBBD2B45917941067F96599BB98926C",
|
||||
.K0 = "B61C86CC4E5D2757545AD423399FB7031ECAB913CBB900BD7A3C6DD8BF92015B",
|
||||
.usage = 0,
|
||||
.ct = "03886D03310B47A6D8F06D7B94D1DD837ECCE315EF652AFF620859D94A259266",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "enc 1 plain",
|
||||
.plain = "'1",
|
||||
.conf = "DEF487FCEBE6DE6346D4DA4521BBA2D2",
|
||||
.K0 = "1B97FE0A190E2021EB30753E1B6E1E77B0754B1D684610355864104963463833",
|
||||
.usage = 1,
|
||||
.ct = "2C9C1570133C99BF6A34BC1B0212002FD194338749DB4135497A347CFCD9D18A12",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "enc 9 plain",
|
||||
.plain = "'9 bytesss",
|
||||
.conf = "AD4FF904D34E555384B14100FC465F88",
|
||||
.K0 = "32164C5B434D1D1538E4CFD9BE8040FE8C4AC7ACC4B93D3314D2133668147A05",
|
||||
.usage = 2,
|
||||
.ct = "9C6DE75F812DE7ED0D28B2963557A115640998275B0AF5152709913FF52A2A9C8E63B872F92E64C839",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "enc 13 plain",
|
||||
.plain = "'13 bytes byte",
|
||||
.conf = "CF9BCA6DF1144E0C0AF9B8F34C90D514",
|
||||
.K0 = "B038B132CD8E06612267FAB7170066D88AECCBA0B744BFC60DC89BCA182D0715",
|
||||
.usage = 3,
|
||||
.ct = "EEEC85A9813CDC536772AB9B42DEFC5706F726E975DDE05A87EB5406EA324CA185C9986B42AABE794B84821BEE",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "enc 30 plain",
|
||||
.plain = "'30 bytes bytes bytes bytes byt",
|
||||
.conf = "644DEF38DA35007275878D216855E228",
|
||||
.K0 = "CCFCD349BF4C6677E86E4B02B8EAB924A546AC731CF9BF6989B996E7D6BFBBA7",
|
||||
.usage = 4,
|
||||
.ct = "0E44680985855F2D1F1812529CA83BFD8E349DE6FD9ADA0BAAA048D68E265FEBF34AD1255A344999AD37146887A6C6845731AC7F46376A0504CD06571474",
|
||||
},
|
||||
{/* END */}
|
||||
};
|
||||
|
||||
/*
|
||||
* Checksum generation tests.
|
||||
*/
|
||||
const struct krb5_mic_test krb5_mic_tests[] = {
|
||||
/* rfc8009 Appendix A */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.name = "mic",
|
||||
.plain = "000102030405060708090A0B0C0D0E0F1011121314",
|
||||
.Kc = "B31A018A48F54776F403E9A396325DC3",
|
||||
.mic = "D78367186643D67B411CBA9139FC1DEE",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.name = "mic",
|
||||
.plain = "000102030405060708090A0B0C0D0E0F1011121314",
|
||||
.Kc = "EF5718BE86CC84963D8BBB5031E9F5C4BA41F28FAF69E73D",
|
||||
.mic = "45EE791567EEFCA37F4AC1E0222DE80D43C3BFA06699672A",
|
||||
},
|
||||
/* rfc6803 sec 10 */
|
||||
{
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "mic abc",
|
||||
.plain = "'abcdefghijk",
|
||||
.K0 = "1DC46A8D763F4F93742BCBA3387576C3",
|
||||
.usage = 7,
|
||||
.mic = "1178E6C5C47A8C1AE0C4B9C7D4EB7B6B",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.name = "mic ABC",
|
||||
.plain = "'ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
.K0 = "5027BC231D0F3A9D23333F1CA6FDBE7C",
|
||||
.usage = 8,
|
||||
.mic = "D1B34F7004A731F23A0C00BF6C3F753A",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "mic 123",
|
||||
.plain = "'123456789",
|
||||
.K0 = "B61C86CC4E5D2757545AD423399FB7031ECAB913CBB900BD7A3C6DD8BF92015B",
|
||||
.usage = 9,
|
||||
.mic = "87A12CFD2B96214810F01C826E7744B1",
|
||||
}, {
|
||||
.etype = KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.name = "mic !@#",
|
||||
.plain = "'!@#$%^&*()!@#$%^&*()!@#$%^&*()",
|
||||
.K0 = "32164C5B434D1D1538E4CFD9BE8040FE8C4AC7ACC4B93D3314D2133668147A05",
|
||||
.usage = 10,
|
||||
.mic = "3FA0B42355E52B189187294AA252AB64",
|
||||
},
|
||||
{/* END */}
|
||||
};
|
||||
504
crypto/krb5enc.c
Normal file
504
crypto/krb5enc.c
Normal file
|
|
@ -0,0 +1,504 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* AEAD wrapper for Kerberos 5 RFC3961 simplified profile.
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* Derived from authenc:
|
||||
* Copyright (c) 2007-2015 Herbert Xu <herbert@gondor.apana.org.au>
|
||||
*/
|
||||
|
||||
#include <crypto/internal/aead.h>
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <crypto/internal/skcipher.h>
|
||||
#include <crypto/authenc.h>
|
||||
#include <crypto/scatterwalk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
struct krb5enc_instance_ctx {
|
||||
struct crypto_ahash_spawn auth;
|
||||
struct crypto_skcipher_spawn enc;
|
||||
unsigned int reqoff;
|
||||
};
|
||||
|
||||
struct krb5enc_ctx {
|
||||
struct crypto_ahash *auth;
|
||||
struct crypto_skcipher *enc;
|
||||
};
|
||||
|
||||
struct krb5enc_request_ctx {
|
||||
struct scatterlist src[2];
|
||||
struct scatterlist dst[2];
|
||||
char tail[];
|
||||
};
|
||||
|
||||
static void krb5enc_request_complete(struct aead_request *req, int err)
|
||||
{
|
||||
if (err != -EINPROGRESS)
|
||||
aead_request_complete(req, err);
|
||||
}
|
||||
|
||||
/**
|
||||
* crypto_krb5enc_extractkeys - Extract Ke and Ki keys from the key blob.
|
||||
* @keys: Where to put the key sizes and pointers
|
||||
* @key: Encoded key material
|
||||
* @keylen: Amount of key material
|
||||
*
|
||||
* Decode the key blob we're given. It starts with an rtattr that indicates
|
||||
* the format and the length. Format CRYPTO_AUTHENC_KEYA_PARAM is:
|
||||
*
|
||||
* rtattr || __be32 enckeylen || authkey || enckey
|
||||
*
|
||||
* Note that the rtattr is in cpu-endian form, unlike enckeylen. This must be
|
||||
* handled correctly in static testmgr data.
|
||||
*/
|
||||
int crypto_krb5enc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
struct rtattr *rta = (struct rtattr *)key;
|
||||
struct crypto_authenc_key_param *param;
|
||||
|
||||
if (!RTA_OK(rta, keylen))
|
||||
return -EINVAL;
|
||||
if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* RTA_OK() didn't align the rtattr's payload when validating that it
|
||||
* fits in the buffer. Yet, the keys should start on the next 4-byte
|
||||
* aligned boundary. To avoid confusion, require that the rtattr
|
||||
* payload be exactly the param struct, which has a 4-byte aligned size.
|
||||
*/
|
||||
if (RTA_PAYLOAD(rta) != sizeof(*param))
|
||||
return -EINVAL;
|
||||
BUILD_BUG_ON(sizeof(*param) % RTA_ALIGNTO);
|
||||
|
||||
param = RTA_DATA(rta);
|
||||
keys->enckeylen = be32_to_cpu(param->enckeylen);
|
||||
|
||||
key += rta->rta_len;
|
||||
keylen -= rta->rta_len;
|
||||
|
||||
if (keylen < keys->enckeylen)
|
||||
return -EINVAL;
|
||||
|
||||
keys->authkeylen = keylen - keys->enckeylen;
|
||||
keys->authkey = key;
|
||||
keys->enckey = key + keys->authkeylen;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(crypto_krb5enc_extractkeys);
|
||||
|
||||
static int krb5enc_setkey(struct crypto_aead *krb5enc, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
struct crypto_authenc_keys keys;
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
|
||||
struct crypto_skcipher *enc = ctx->enc;
|
||||
struct crypto_ahash *auth = ctx->auth;
|
||||
unsigned int flags = crypto_aead_get_flags(krb5enc);
|
||||
int err = -EINVAL;
|
||||
|
||||
if (crypto_krb5enc_extractkeys(&keys, key, keylen) != 0)
|
||||
goto out;
|
||||
|
||||
crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_ahash_set_flags(auth, flags & CRYPTO_TFM_REQ_MASK);
|
||||
err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK);
|
||||
crypto_skcipher_set_flags(enc, flags & CRYPTO_TFM_REQ_MASK);
|
||||
err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen);
|
||||
out:
|
||||
memzero_explicit(&keys, sizeof(keys));
|
||||
return err;
|
||||
}
|
||||
|
||||
static void krb5enc_encrypt_done(void *data, int err)
|
||||
{
|
||||
struct aead_request *req = data;
|
||||
|
||||
krb5enc_request_complete(req, err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the encryption of the plaintext. We skip over the associated data as
|
||||
* that only gets included in the hash.
|
||||
*/
|
||||
static int krb5enc_dispatch_encrypt(struct aead_request *req,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
struct aead_instance *inst = aead_alg_instance(krb5enc);
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
|
||||
struct crypto_skcipher *enc = ctx->enc;
|
||||
struct skcipher_request *skreq = (void *)(areq_ctx->tail +
|
||||
ictx->reqoff);
|
||||
struct scatterlist *src, *dst;
|
||||
|
||||
src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen);
|
||||
if (req->src == req->dst)
|
||||
dst = src;
|
||||
else
|
||||
dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
|
||||
|
||||
skcipher_request_set_tfm(skreq, enc);
|
||||
skcipher_request_set_callback(skreq, aead_request_flags(req),
|
||||
krb5enc_encrypt_done, req);
|
||||
skcipher_request_set_crypt(skreq, src, dst, req->cryptlen, req->iv);
|
||||
|
||||
return crypto_skcipher_encrypt(skreq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the hash into the checksum field in the destination buffer directly
|
||||
* after the encrypted region.
|
||||
*/
|
||||
static void krb5enc_insert_checksum(struct aead_request *req, u8 *hash)
|
||||
{
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
|
||||
scatterwalk_map_and_copy(hash, req->dst,
|
||||
req->assoclen + req->cryptlen,
|
||||
crypto_aead_authsize(krb5enc), 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Upon completion of an asynchronous digest, transfer the hash to the checksum
|
||||
* field.
|
||||
*/
|
||||
static void krb5enc_encrypt_ahash_done(void *data, int err)
|
||||
{
|
||||
struct aead_request *req = data;
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
struct aead_instance *inst = aead_alg_instance(krb5enc);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
|
||||
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
|
||||
|
||||
if (err)
|
||||
return krb5enc_request_complete(req, err);
|
||||
|
||||
krb5enc_insert_checksum(req, ahreq->result);
|
||||
|
||||
err = krb5enc_dispatch_encrypt(req, 0);
|
||||
if (err != -EINPROGRESS)
|
||||
aead_request_complete(req, err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the digest of the plaintext for encryption. In theory, this could be
|
||||
* run in parallel with the encryption, provided the src and dst buffers don't
|
||||
* overlap.
|
||||
*/
|
||||
static int krb5enc_dispatch_encrypt_hash(struct aead_request *req)
|
||||
{
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
struct aead_instance *inst = aead_alg_instance(krb5enc);
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct crypto_ahash *auth = ctx->auth;
|
||||
struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
|
||||
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
|
||||
u8 *hash = areq_ctx->tail;
|
||||
int err;
|
||||
|
||||
ahash_request_set_callback(ahreq, aead_request_flags(req),
|
||||
krb5enc_encrypt_ahash_done, req);
|
||||
ahash_request_set_tfm(ahreq, auth);
|
||||
ahash_request_set_crypt(ahreq, req->src, hash, req->assoclen + req->cryptlen);
|
||||
|
||||
err = crypto_ahash_digest(ahreq);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
krb5enc_insert_checksum(req, hash);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process an encryption operation. We can perform the cipher and the hash in
|
||||
* parallel, provided the src and dst buffers are separate.
|
||||
*/
|
||||
static int krb5enc_encrypt(struct aead_request *req)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = krb5enc_dispatch_encrypt_hash(req);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return krb5enc_dispatch_encrypt(req, aead_request_flags(req));
|
||||
}
|
||||
|
||||
static int krb5enc_verify_hash(struct aead_request *req)
|
||||
{
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
struct aead_instance *inst = aead_alg_instance(krb5enc);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
|
||||
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
|
||||
unsigned int authsize = crypto_aead_authsize(krb5enc);
|
||||
u8 *calc_hash = areq_ctx->tail;
|
||||
u8 *msg_hash = areq_ctx->tail + authsize;
|
||||
|
||||
scatterwalk_map_and_copy(msg_hash, req->src, ahreq->nbytes, authsize, 0);
|
||||
|
||||
if (crypto_memneq(msg_hash, calc_hash, authsize))
|
||||
return -EBADMSG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void krb5enc_decrypt_hash_done(void *data, int err)
|
||||
{
|
||||
struct aead_request *req = data;
|
||||
|
||||
if (err)
|
||||
return krb5enc_request_complete(req, err);
|
||||
|
||||
err = krb5enc_verify_hash(req);
|
||||
krb5enc_request_complete(req, err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch the hashing of the plaintext after we've done the decryption.
|
||||
*/
|
||||
static int krb5enc_dispatch_decrypt_hash(struct aead_request *req)
|
||||
{
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
struct aead_instance *inst = aead_alg_instance(krb5enc);
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
|
||||
struct ahash_request *ahreq = (void *)(areq_ctx->tail + ictx->reqoff);
|
||||
struct crypto_ahash *auth = ctx->auth;
|
||||
unsigned int authsize = crypto_aead_authsize(krb5enc);
|
||||
u8 *hash = areq_ctx->tail;
|
||||
int err;
|
||||
|
||||
ahash_request_set_tfm(ahreq, auth);
|
||||
ahash_request_set_crypt(ahreq, req->dst, hash,
|
||||
req->assoclen + req->cryptlen - authsize);
|
||||
ahash_request_set_callback(ahreq, aead_request_flags(req),
|
||||
krb5enc_decrypt_hash_done, req);
|
||||
|
||||
err = crypto_ahash_digest(ahreq);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return krb5enc_verify_hash(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch the decryption of the ciphertext.
|
||||
*/
|
||||
static int krb5enc_dispatch_decrypt(struct aead_request *req)
|
||||
{
|
||||
struct crypto_aead *krb5enc = crypto_aead_reqtfm(req);
|
||||
struct aead_instance *inst = aead_alg_instance(krb5enc);
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(krb5enc);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct krb5enc_request_ctx *areq_ctx = aead_request_ctx(req);
|
||||
struct skcipher_request *skreq = (void *)(areq_ctx->tail +
|
||||
ictx->reqoff);
|
||||
unsigned int authsize = crypto_aead_authsize(krb5enc);
|
||||
struct scatterlist *src, *dst;
|
||||
|
||||
src = scatterwalk_ffwd(areq_ctx->src, req->src, req->assoclen);
|
||||
dst = src;
|
||||
|
||||
if (req->src != req->dst)
|
||||
dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen);
|
||||
|
||||
skcipher_request_set_tfm(skreq, ctx->enc);
|
||||
skcipher_request_set_callback(skreq, aead_request_flags(req),
|
||||
req->base.complete, req->base.data);
|
||||
skcipher_request_set_crypt(skreq, src, dst,
|
||||
req->cryptlen - authsize, req->iv);
|
||||
|
||||
return crypto_skcipher_decrypt(skreq);
|
||||
}
|
||||
|
||||
static int krb5enc_decrypt(struct aead_request *req)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = krb5enc_dispatch_decrypt(req);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return krb5enc_dispatch_decrypt_hash(req);
|
||||
}
|
||||
|
||||
static int krb5enc_init_tfm(struct crypto_aead *tfm)
|
||||
{
|
||||
struct aead_instance *inst = aead_alg_instance(tfm);
|
||||
struct krb5enc_instance_ctx *ictx = aead_instance_ctx(inst);
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
struct crypto_ahash *auth;
|
||||
struct crypto_skcipher *enc;
|
||||
int err;
|
||||
|
||||
auth = crypto_spawn_ahash(&ictx->auth);
|
||||
if (IS_ERR(auth))
|
||||
return PTR_ERR(auth);
|
||||
|
||||
enc = crypto_spawn_skcipher(&ictx->enc);
|
||||
err = PTR_ERR(enc);
|
||||
if (IS_ERR(enc))
|
||||
goto err_free_ahash;
|
||||
|
||||
ctx->auth = auth;
|
||||
ctx->enc = enc;
|
||||
|
||||
crypto_aead_set_reqsize(
|
||||
tfm,
|
||||
sizeof(struct krb5enc_request_ctx) +
|
||||
ictx->reqoff + /* Space for two checksums */
|
||||
umax(sizeof(struct ahash_request) + crypto_ahash_reqsize(auth),
|
||||
sizeof(struct skcipher_request) + crypto_skcipher_reqsize(enc)));
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_ahash:
|
||||
crypto_free_ahash(auth);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void krb5enc_exit_tfm(struct crypto_aead *tfm)
|
||||
{
|
||||
struct krb5enc_ctx *ctx = crypto_aead_ctx(tfm);
|
||||
|
||||
crypto_free_ahash(ctx->auth);
|
||||
crypto_free_skcipher(ctx->enc);
|
||||
}
|
||||
|
||||
static void krb5enc_free(struct aead_instance *inst)
|
||||
{
|
||||
struct krb5enc_instance_ctx *ctx = aead_instance_ctx(inst);
|
||||
|
||||
crypto_drop_skcipher(&ctx->enc);
|
||||
crypto_drop_ahash(&ctx->auth);
|
||||
kfree(inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an instance of a template for a specific hash and cipher pair.
|
||||
*/
|
||||
static int krb5enc_create(struct crypto_template *tmpl, struct rtattr **tb)
|
||||
{
|
||||
struct krb5enc_instance_ctx *ictx;
|
||||
struct skcipher_alg_common *enc;
|
||||
struct hash_alg_common *auth;
|
||||
struct aead_instance *inst;
|
||||
struct crypto_alg *auth_base;
|
||||
u32 mask;
|
||||
int err;
|
||||
|
||||
err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_AEAD, &mask);
|
||||
if (err) {
|
||||
pr_err("attr_type failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL);
|
||||
if (!inst)
|
||||
return -ENOMEM;
|
||||
ictx = aead_instance_ctx(inst);
|
||||
|
||||
err = crypto_grab_ahash(&ictx->auth, aead_crypto_instance(inst),
|
||||
crypto_attr_alg_name(tb[1]), 0, mask);
|
||||
if (err) {
|
||||
pr_err("grab ahash failed\n");
|
||||
goto err_free_inst;
|
||||
}
|
||||
auth = crypto_spawn_ahash_alg(&ictx->auth);
|
||||
auth_base = &auth->base;
|
||||
|
||||
err = crypto_grab_skcipher(&ictx->enc, aead_crypto_instance(inst),
|
||||
crypto_attr_alg_name(tb[2]), 0, mask);
|
||||
if (err) {
|
||||
pr_err("grab skcipher failed\n");
|
||||
goto err_free_inst;
|
||||
}
|
||||
enc = crypto_spawn_skcipher_alg_common(&ictx->enc);
|
||||
|
||||
ictx->reqoff = 2 * auth->digestsize;
|
||||
|
||||
err = -ENAMETOOLONG;
|
||||
if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
|
||||
"krb5enc(%s,%s)", auth_base->cra_name,
|
||||
enc->base.cra_name) >=
|
||||
CRYPTO_MAX_ALG_NAME)
|
||||
goto err_free_inst;
|
||||
|
||||
if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
|
||||
"krb5enc(%s,%s)", auth_base->cra_driver_name,
|
||||
enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
|
||||
goto err_free_inst;
|
||||
|
||||
inst->alg.base.cra_priority = enc->base.cra_priority * 10 +
|
||||
auth_base->cra_priority;
|
||||
inst->alg.base.cra_blocksize = enc->base.cra_blocksize;
|
||||
inst->alg.base.cra_alignmask = enc->base.cra_alignmask;
|
||||
inst->alg.base.cra_ctxsize = sizeof(struct krb5enc_ctx);
|
||||
|
||||
inst->alg.ivsize = enc->ivsize;
|
||||
inst->alg.chunksize = enc->chunksize;
|
||||
inst->alg.maxauthsize = auth->digestsize;
|
||||
|
||||
inst->alg.init = krb5enc_init_tfm;
|
||||
inst->alg.exit = krb5enc_exit_tfm;
|
||||
|
||||
inst->alg.setkey = krb5enc_setkey;
|
||||
inst->alg.encrypt = krb5enc_encrypt;
|
||||
inst->alg.decrypt = krb5enc_decrypt;
|
||||
|
||||
inst->free = krb5enc_free;
|
||||
|
||||
err = aead_register_instance(tmpl, inst);
|
||||
if (err) {
|
||||
pr_err("ref failed\n");
|
||||
goto err_free_inst;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_inst:
|
||||
krb5enc_free(inst);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct crypto_template crypto_krb5enc_tmpl = {
|
||||
.name = "krb5enc",
|
||||
.create = krb5enc_create,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init crypto_krb5enc_module_init(void)
|
||||
{
|
||||
return crypto_register_template(&crypto_krb5enc_tmpl);
|
||||
}
|
||||
|
||||
static void __exit crypto_krb5enc_module_exit(void)
|
||||
{
|
||||
crypto_unregister_template(&crypto_krb5enc_tmpl);
|
||||
}
|
||||
|
||||
subsys_initcall(crypto_krb5enc_module_init);
|
||||
module_exit(crypto_krb5enc_module_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Simple AEAD wrapper for Kerberos 5 RFC3961");
|
||||
MODULE_ALIAS_CRYPTO("krb5enc");
|
||||
|
|
@ -4505,6 +4505,12 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.alg = "authenc(hmac(sha256),ctr(aes))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha256),cts(cbc(aes)))",
|
||||
.test = alg_test_aead,
|
||||
.suite = {
|
||||
.aead = __VECS(krb5_test_aes128_cts_hmac_sha256_128)
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha256),rfc3686(ctr(aes)))",
|
||||
.test = alg_test_null,
|
||||
|
|
@ -4525,6 +4531,12 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.alg = "authenc(hmac(sha384),ctr(aes))",
|
||||
.test = alg_test_null,
|
||||
.fips_allowed = 1,
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha384),cts(cbc(aes)))",
|
||||
.test = alg_test_aead,
|
||||
.suite = {
|
||||
.aead = __VECS(krb5_test_aes256_cts_hmac_sha384_192)
|
||||
}
|
||||
}, {
|
||||
.alg = "authenc(hmac(sha384),rfc3686(ctr(aes)))",
|
||||
.test = alg_test_null,
|
||||
|
|
@ -5398,6 +5410,10 @@ static const struct alg_test_desc alg_test_descs[] = {
|
|||
.alg = "jitterentropy_rng",
|
||||
.fips_allowed = 1,
|
||||
.test = alg_test_null,
|
||||
}, {
|
||||
.alg = "krb5enc(cmac(camellia),cts(cbc(camellia)))",
|
||||
.test = alg_test_aead,
|
||||
.suite.aead = __VECS(krb5_test_camellia_cts_cmac)
|
||||
}, {
|
||||
.alg = "lrw(aes)",
|
||||
.generic_driver = "lrw(ecb(aes-generic))",
|
||||
|
|
|
|||
351
crypto/testmgr.h
351
crypto/testmgr.h
|
|
@ -38894,4 +38894,355 @@ static const struct cipher_testvec aes_hctr2_tv_template[] = {
|
|||
|
||||
};
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
#define AUTHENC_KEY_HEADER(enckeylen) \
|
||||
"\x08\x00\x01\x00" /* LE rtattr */ \
|
||||
enckeylen /* crypto_authenc_key_param */
|
||||
#else
|
||||
#define AUTHENC_KEY_HEADER(enckeylen) \
|
||||
"\x00\x08\x00\x01" /* BE rtattr */ \
|
||||
enckeylen /* crypto_authenc_key_param */
|
||||
#endif
|
||||
|
||||
static const struct aead_testvec krb5_test_aes128_cts_hmac_sha256_128[] = {
|
||||
/* rfc8009 Appendix A */
|
||||
{
|
||||
/* "enc no plain" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x9F\xDA\x0E\x56\xAB\x2D\x85\xE1\x56\x9A\x68\x86\x96\xC2\x6A\x6C" // Ki
|
||||
"\x9B\x19\x7D\xD1\xE8\xC5\x60\x9D\x6E\x67\xC3\xE3\x7C\x62\xC7\x2E", // Ke
|
||||
.klen = 4 + 4 + 16 + 16,
|
||||
.ptext =
|
||||
"\x7E\x58\x95\xEA\xF2\x67\x24\x35\xBA\xD8\x17\xF5\x45\xA3\x71\x48" // Confounder
|
||||
"", // Plain
|
||||
.plen = 16 + 0,
|
||||
.ctext =
|
||||
"\xEF\x85\xFB\x89\x0B\xB8\x47\x2F\x4D\xAB\x20\x39\x4D\xCA\x78\x1D"
|
||||
"\xAD\x87\x7E\xDA\x39\xD5\x0C\x87\x0C\x0D\x5A\x0A\x8E\x48\xC7\x18",
|
||||
.clen = 16 + 0 + 16,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
}, {
|
||||
/* "enc plain<block" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x9F\xDA\x0E\x56\xAB\x2D\x85\xE1\x56\x9A\x68\x86\x96\xC2\x6A\x6C" // Ki
|
||||
"\x9B\x19\x7D\xD1\xE8\xC5\x60\x9D\x6E\x67\xC3\xE3\x7C\x62\xC7\x2E", // Ke
|
||||
.klen = 4 + 4 + 16 + 16,
|
||||
.ptext =
|
||||
"\x7B\xCA\x28\x5E\x2F\xD4\x13\x0F\xB5\x5B\x1A\x5C\x83\xBC\x5B\x24" // Confounder
|
||||
"\x00\x01\x02\x03\x04\x05", // Plain
|
||||
.plen = 16 + 6,
|
||||
.ctext =
|
||||
"\x84\xD7\xF3\x07\x54\xED\x98\x7B\xAB\x0B\xF3\x50\x6B\xEB\x09\xCF"
|
||||
"\xB5\x54\x02\xCE\xF7\xE6\x87\x7C\xE9\x9E\x24\x7E\x52\xD1\x6E\xD4"
|
||||
"\x42\x1D\xFD\xF8\x97\x6C",
|
||||
.clen = 16 + 6 + 16,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
}, {
|
||||
/* "enc plain==block" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x9F\xDA\x0E\x56\xAB\x2D\x85\xE1\x56\x9A\x68\x86\x96\xC2\x6A\x6C" // Ki
|
||||
"\x9B\x19\x7D\xD1\xE8\xC5\x60\x9D\x6E\x67\xC3\xE3\x7C\x62\xC7\x2E", // Ke
|
||||
.klen = 4 + 4 + 16 + 16,
|
||||
.ptext =
|
||||
"\x56\xAB\x21\x71\x3F\xF6\x2C\x0A\x14\x57\x20\x0F\x6F\xA9\x94\x8F" // Confounder
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", // Plain
|
||||
.plen = 16 + 16,
|
||||
.ctext =
|
||||
"\x35\x17\xD6\x40\xF5\x0D\xDC\x8A\xD3\x62\x87\x22\xB3\x56\x9D\x2A"
|
||||
"\xE0\x74\x93\xFA\x82\x63\x25\x40\x80\xEA\x65\xC1\x00\x8E\x8F\xC2"
|
||||
"\x95\xFB\x48\x52\xE7\xD8\x3E\x1E\x7C\x48\xC3\x7E\xEB\xE6\xB0\xD3",
|
||||
.clen = 16 + 16 + 16,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
}, {
|
||||
/* "enc plain>block" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x9F\xDA\x0E\x56\xAB\x2D\x85\xE1\x56\x9A\x68\x86\x96\xC2\x6A\x6C" // Ki
|
||||
"\x9B\x19\x7D\xD1\xE8\xC5\x60\x9D\x6E\x67\xC3\xE3\x7C\x62\xC7\x2E", // Ke
|
||||
.klen = 4 + 4 + 16 + 16,
|
||||
.ptext =
|
||||
"\xA7\xA4\xE2\x9A\x47\x28\xCE\x10\x66\x4F\xB6\x4E\x49\xAD\x3F\xAC" // Confounder
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
|
||||
"\x10\x11\x12\x13\x14", // Plain
|
||||
.plen = 16 + 21,
|
||||
.ctext =
|
||||
"\x72\x0F\x73\xB1\x8D\x98\x59\xCD\x6C\xCB\x43\x46\x11\x5C\xD3\x36"
|
||||
"\xC7\x0F\x58\xED\xC0\xC4\x43\x7C\x55\x73\x54\x4C\x31\xC8\x13\xBC"
|
||||
"\xE1\xE6\xD0\x72\xC1\x86\xB3\x9A\x41\x3C\x2F\x92\xCA\x9B\x83\x34"
|
||||
"\xA2\x87\xFF\xCB\xFC",
|
||||
.clen = 16 + 21 + 16,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct aead_testvec krb5_test_aes256_cts_hmac_sha384_192[] = {
|
||||
/* rfc8009 Appendix A */
|
||||
{
|
||||
/* "enc no plain" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x69\xB1\x65\x14\xE3\xCD\x8E\x56\xB8\x20\x10\xD5\xC7\x30\x12\xB6"
|
||||
"\x22\xC4\xD0\x0F\xFC\x23\xED\x1F" // Ki
|
||||
"\x56\xAB\x22\xBE\xE6\x3D\x82\xD7\xBC\x52\x27\xF6\x77\x3F\x8E\xA7"
|
||||
"\xA5\xEB\x1C\x82\x51\x60\xC3\x83\x12\x98\x0C\x44\x2E\x5C\x7E\x49", // Ke
|
||||
.klen = 4 + 4 + 32 + 24,
|
||||
.ptext =
|
||||
"\xF7\x64\xE9\xFA\x15\xC2\x76\x47\x8B\x2C\x7D\x0C\x4E\x5F\x58\xE4" // Confounder
|
||||
"", // Plain
|
||||
.plen = 16 + 0,
|
||||
.ctext =
|
||||
"\x41\xF5\x3F\xA5\xBF\xE7\x02\x6D\x91\xFA\xF9\xBE\x95\x91\x95\xA0"
|
||||
"\x58\x70\x72\x73\xA9\x6A\x40\xF0\xA0\x19\x60\x62\x1A\xC6\x12\x74"
|
||||
"\x8B\x9B\xBF\xBE\x7E\xB4\xCE\x3C",
|
||||
.clen = 16 + 0 + 24,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
}, {
|
||||
/* "enc plain<block" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x69\xB1\x65\x14\xE3\xCD\x8E\x56\xB8\x20\x10\xD5\xC7\x30\x12\xB6"
|
||||
"\x22\xC4\xD0\x0F\xFC\x23\xED\x1F" // Ki
|
||||
"\x56\xAB\x22\xBE\xE6\x3D\x82\xD7\xBC\x52\x27\xF6\x77\x3F\x8E\xA7"
|
||||
"\xA5\xEB\x1C\x82\x51\x60\xC3\x83\x12\x98\x0C\x44\x2E\x5C\x7E\x49", // Ke
|
||||
.klen = 4 + 4 + 32 + 24,
|
||||
.ptext =
|
||||
"\xB8\x0D\x32\x51\xC1\xF6\x47\x14\x94\x25\x6F\xFE\x71\x2D\x0B\x9A" // Confounder
|
||||
"\x00\x01\x02\x03\x04\x05", // Plain
|
||||
.plen = 16 + 6,
|
||||
.ctext =
|
||||
"\x4E\xD7\xB3\x7C\x2B\xCA\xC8\xF7\x4F\x23\xC1\xCF\x07\xE6\x2B\xC7"
|
||||
"\xB7\x5F\xB3\xF6\x37\xB9\xF5\x59\xC7\xF6\x64\xF6\x9E\xAB\x7B\x60"
|
||||
"\x92\x23\x75\x26\xEA\x0D\x1F\x61\xCB\x20\xD6\x9D\x10\xF2",
|
||||
.clen = 16 + 6 + 24,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
}, {
|
||||
/* "enc plain==block" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x69\xB1\x65\x14\xE3\xCD\x8E\x56\xB8\x20\x10\xD5\xC7\x30\x12\xB6"
|
||||
"\x22\xC4\xD0\x0F\xFC\x23\xED\x1F" // Ki
|
||||
"\x56\xAB\x22\xBE\xE6\x3D\x82\xD7\xBC\x52\x27\xF6\x77\x3F\x8E\xA7"
|
||||
"\xA5\xEB\x1C\x82\x51\x60\xC3\x83\x12\x98\x0C\x44\x2E\x5C\x7E\x49", // Ke
|
||||
.klen = 4 + 4 + 32 + 24,
|
||||
.ptext =
|
||||
"\x53\xBF\x8A\x0D\x10\x52\x65\xD4\xE2\x76\x42\x86\x24\xCE\x5E\x63" // Confounder
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", // Plain
|
||||
.plen = 16 + 16,
|
||||
.ctext =
|
||||
"\xBC\x47\xFF\xEC\x79\x98\xEB\x91\xE8\x11\x5C\xF8\xD1\x9D\xAC\x4B"
|
||||
"\xBB\xE2\xE1\x63\xE8\x7D\xD3\x7F\x49\xBE\xCA\x92\x02\x77\x64\xF6"
|
||||
"\x8C\xF5\x1F\x14\xD7\x98\xC2\x27\x3F\x35\xDF\x57\x4D\x1F\x93\x2E"
|
||||
"\x40\xC4\xFF\x25\x5B\x36\xA2\x66",
|
||||
.clen = 16 + 16 + 24,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
}, {
|
||||
/* "enc plain>block" */
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x69\xB1\x65\x14\xE3\xCD\x8E\x56\xB8\x20\x10\xD5\xC7\x30\x12\xB6"
|
||||
"\x22\xC4\xD0\x0F\xFC\x23\xED\x1F" // Ki
|
||||
"\x56\xAB\x22\xBE\xE6\x3D\x82\xD7\xBC\x52\x27\xF6\x77\x3F\x8E\xA7"
|
||||
"\xA5\xEB\x1C\x82\x51\x60\xC3\x83\x12\x98\x0C\x44\x2E\x5C\x7E\x49", // Ke
|
||||
.klen = 4 + 4 + 32 + 24,
|
||||
.ptext =
|
||||
"\x76\x3E\x65\x36\x7E\x86\x4F\x02\xF5\x51\x53\xC7\xE3\xB5\x8A\xF1" // Confounder
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
|
||||
"\x10\x11\x12\x13\x14", // Plain
|
||||
.plen = 16 + 21,
|
||||
.ctext =
|
||||
"\x40\x01\x3E\x2D\xF5\x8E\x87\x51\x95\x7D\x28\x78\xBC\xD2\xD6\xFE"
|
||||
"\x10\x1C\xCF\xD5\x56\xCB\x1E\xAE\x79\xDB\x3C\x3E\xE8\x64\x29\xF2"
|
||||
"\xB2\xA6\x02\xAC\x86\xFE\xF6\xEC\xB6\x47\xD6\x29\x5F\xAE\x07\x7A"
|
||||
"\x1F\xEB\x51\x75\x08\xD2\xC1\x6B\x41\x92\xE0\x1F\x62",
|
||||
.clen = 16 + 21 + 24,
|
||||
.assoc = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", // IV
|
||||
.alen = 16,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct aead_testvec krb5_test_camellia_cts_cmac[] = {
|
||||
/* rfc6803 sec 10 */
|
||||
{
|
||||
// "enc no plain"
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x45\xeb\x66\xe2\xef\xa8\x77\x8f\x7d\xf1\x46\x54\x53\x05\x98\x06" // Ki
|
||||
"\xe9\x9b\x82\xb3\x6c\x4a\xe8\xea\x19\xe9\x5d\xfa\x9e\xde\x88\x2c", // Ke
|
||||
.klen = 4 + 4 + 16 * 2,
|
||||
.ptext =
|
||||
"\xB6\x98\x22\xA1\x9A\x6B\x09\xC0\xEB\xC8\x55\x7D\x1F\x1B\x6C\x0A" // Confounder
|
||||
"", // Plain
|
||||
.plen = 16 + 0,
|
||||
.ctext =
|
||||
"\xC4\x66\xF1\x87\x10\x69\x92\x1E\xDB\x7C\x6F\xDE\x24\x4A\x52\xDB"
|
||||
"\x0B\xA1\x0E\xDC\x19\x7B\xDB\x80\x06\x65\x8C\xA3\xCC\xCE\x6E\xB8",
|
||||
.clen = 16 + 0 + 16,
|
||||
}, {
|
||||
// "enc 1 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x13\x5f\xe7\x11\x6f\x53\xc2\xaa\x36\x12\xb7\xea\xe0\xf2\x84\xaa" // Ki
|
||||
"\xa7\xed\xcd\x53\x97\xea\x6d\x12\xb0\xaf\xf4\xcb\x8d\xaa\x57\xad", // Ke
|
||||
.klen = 4 + 4 + 16 * 2,
|
||||
.ptext =
|
||||
"\x6F\x2F\xC3\xC2\xA1\x66\xFD\x88\x98\x96\x7A\x83\xDE\x95\x96\xD9" // Confounder
|
||||
"1", // Plain
|
||||
.plen = 16 + 1,
|
||||
.ctext =
|
||||
"\x84\x2D\x21\xFD\x95\x03\x11\xC0\xDD\x46\x4A\x3F\x4B\xE8\xD6\xDA"
|
||||
"\x88\xA5\x6D\x55\x9C\x9B\x47\xD3\xF9\xA8\x50\x67\xAF\x66\x15\x59"
|
||||
"\xB8",
|
||||
.clen = 16 + 1 + 16,
|
||||
}, {
|
||||
// "enc 9 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x10\x2c\x34\xd0\x75\x74\x9f\x77\x8a\x15\xca\xd1\xe9\x7d\xa9\x86" // Ki
|
||||
"\xdd\xe4\x2e\xca\x7c\xd9\x86\x3f\xc3\xce\x89\xcb\xc9\x43\x62\xd7", // Ke
|
||||
.klen = 4 + 4 + 16 * 2,
|
||||
.ptext =
|
||||
"\xA5\xB4\xA7\x1E\x07\x7A\xEE\xF9\x3C\x87\x63\xC1\x8F\xDB\x1F\x10" // Confounder
|
||||
"9 bytesss", // Plain
|
||||
.plen = 16 + 9,
|
||||
.ctext =
|
||||
"\x61\x9F\xF0\x72\xE3\x62\x86\xFF\x0A\x28\xDE\xB3\xA3\x52\xEC\x0D"
|
||||
"\x0E\xDF\x5C\x51\x60\xD6\x63\xC9\x01\x75\x8C\xCF\x9D\x1E\xD3\x3D"
|
||||
"\x71\xDB\x8F\x23\xAA\xBF\x83\x48\xA0",
|
||||
.clen = 16 + 9 + 16,
|
||||
}, {
|
||||
// "enc 13 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\xb8\xc4\x38\xcc\x1a\x00\x60\xfc\x91\x3a\x8e\x07\x16\x96\xbd\x08" // Ki
|
||||
"\xc3\x11\x3a\x25\x85\x90\xb9\xae\xbf\x72\x1b\x1a\xf6\xb0\xcb\xf8", // Ke
|
||||
.klen = 4 + 4 + 16 * 2,
|
||||
.ptext =
|
||||
"\x19\xFE\xE4\x0D\x81\x0C\x52\x4B\x5B\x22\xF0\x18\x74\xC6\x93\xDA" // Confounder
|
||||
"13 bytes byte", // Plain
|
||||
.plen = 16 + 13,
|
||||
.ctext =
|
||||
"\xB8\xEC\xA3\x16\x7A\xE6\x31\x55\x12\xE5\x9F\x98\xA7\xC5\x00\x20"
|
||||
"\x5E\x5F\x63\xFF\x3B\xB3\x89\xAF\x1C\x41\xA2\x1D\x64\x0D\x86\x15"
|
||||
"\xC9\xED\x3F\xBE\xB0\x5A\xB6\xAC\xB6\x76\x89\xB5\xEA",
|
||||
.clen = 16 + 13 + 16,
|
||||
}, {
|
||||
// "enc 30 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x10")
|
||||
"\x18\xaf\x19\xb0\x23\x74\x44\xfd\x75\x04\xad\x7d\xbd\x48\xad\xd3" // Ki
|
||||
"\x8b\x07\xee\xd3\x01\x49\x91\x6a\xa2\x0d\xb3\xf5\xce\xd8\xaf\xad", // Ke
|
||||
.klen = 4 + 4 + 16 * 2,
|
||||
.ptext =
|
||||
"\xCA\x7A\x7A\xB4\xBE\x19\x2D\xAB\xD6\x03\x50\x6D\xB1\x9C\x39\xE2" // Confounder
|
||||
"30 bytes bytes bytes bytes byt", // Plain
|
||||
.plen = 16 + 30,
|
||||
.ctext =
|
||||
"\xA2\x6A\x39\x05\xA4\xFF\xD5\x81\x6B\x7B\x1E\x27\x38\x0D\x08\x09"
|
||||
"\x0C\x8E\xC1\xF3\x04\x49\x6E\x1A\xBD\xCD\x2B\xDC\xD1\xDF\xFC\x66"
|
||||
"\x09\x89\xE1\x17\xA7\x13\xDD\xBB\x57\xA4\x14\x6C\x15\x87\xCB\xA4"
|
||||
"\x35\x66\x65\x59\x1D\x22\x40\x28\x2F\x58\x42\xB1\x05\xA5",
|
||||
.clen = 16 + 30 + 16,
|
||||
}, {
|
||||
// "enc no plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\xa2\xb8\x33\xe9\x43\xbb\x10\xee\x53\xb4\xa1\x9b\xc2\xbb\xc7\xe1"
|
||||
"\x9b\x87\xad\x5d\xe9\x21\x22\xa4\x33\x8b\xe6\xf7\x32\xfd\x8a\x0e" // Ki
|
||||
"\x6c\xcb\x3f\x25\xd8\xae\x57\xf4\xe8\xf6\xca\x47\x4b\xdd\xef\xf1"
|
||||
"\x16\xce\x13\x1b\x3f\x71\x01\x2e\x75\x6d\x6b\x1e\x3f\x70\xa7\xf1", // Ke
|
||||
.klen = 4 + 4 + 32 * 2,
|
||||
.ptext =
|
||||
"\x3C\xBB\xD2\xB4\x59\x17\x94\x10\x67\xF9\x65\x99\xBB\x98\x92\x6C" // Confounder
|
||||
"", // Plain
|
||||
.plen = 16 + 0,
|
||||
.ctext =
|
||||
"\x03\x88\x6D\x03\x31\x0B\x47\xA6\xD8\xF0\x6D\x7B\x94\xD1\xDD\x83"
|
||||
"\x7E\xCC\xE3\x15\xEF\x65\x2A\xFF\x62\x08\x59\xD9\x4A\x25\x92\x66",
|
||||
.clen = 16 + 0 + 16,
|
||||
}, {
|
||||
// "enc 1 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x84\x61\x4b\xfa\x98\xf1\x74\x8a\xa4\xaf\x99\x2b\x8c\x26\x28\x0d"
|
||||
"\xc8\x98\x73\x29\xdf\x77\x5c\x1d\xb0\x4a\x43\xf1\x21\xaa\x86\x65" // Ki
|
||||
"\xe9\x31\x73\xaa\x01\xeb\x3c\x24\x62\x31\xda\xfc\x78\x02\xee\x32"
|
||||
"\xaf\x24\x85\x1d\x8c\x73\x87\xd1\x8c\xb9\xb2\xc5\xb7\xf5\x70\xb8", // Ke
|
||||
.klen = 4 + 4 + 32 * 2,
|
||||
.ptext =
|
||||
"\xDE\xF4\x87\xFC\xEB\xE6\xDE\x63\x46\xD4\xDA\x45\x21\xBB\xA2\xD2" // Confounder
|
||||
"1", // Plain
|
||||
.plen = 16 + 1,
|
||||
.ctext =
|
||||
"\x2C\x9C\x15\x70\x13\x3C\x99\xBF\x6A\x34\xBC\x1B\x02\x12\x00\x2F"
|
||||
"\xD1\x94\x33\x87\x49\xDB\x41\x35\x49\x7A\x34\x7C\xFC\xD9\xD1\x8A"
|
||||
"\x12",
|
||||
.clen = 16 + 1 + 16,
|
||||
}, {
|
||||
// "enc 9 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x47\xb9\xf5\xba\xd7\x63\x00\x58\x2a\x54\x45\xfa\x0c\x1b\x29\xc3"
|
||||
"\xaa\x83\xec\x63\xb9\x0b\x4a\xb0\x08\x48\xc1\x85\x67\x4f\x44\xa7" // Ki
|
||||
"\xcd\xa2\xd3\x9a\x9b\x24\x3f\xfe\xb5\x6e\x8d\x5f\x4b\xd5\x28\x74"
|
||||
"\x1e\xcb\x52\x0c\x62\x12\x3f\xb0\x40\xb8\x41\x8b\x15\xc7\xd7\x0c", // Ke
|
||||
.klen = 4 + 4 + 32 * 2,
|
||||
.ptext =
|
||||
"\xAD\x4F\xF9\x04\xD3\x4E\x55\x53\x84\xB1\x41\x00\xFC\x46\x5F\x88" // Confounder
|
||||
"9 bytesss", // Plain
|
||||
.plen = 16 + 9,
|
||||
.ctext =
|
||||
"\x9C\x6D\xE7\x5F\x81\x2D\xE7\xED\x0D\x28\xB2\x96\x35\x57\xA1\x15"
|
||||
"\x64\x09\x98\x27\x5B\x0A\xF5\x15\x27\x09\x91\x3F\xF5\x2A\x2A\x9C"
|
||||
"\x8E\x63\xB8\x72\xF9\x2E\x64\xC8\x39",
|
||||
.clen = 16 + 9 + 16,
|
||||
}, {
|
||||
// "enc 13 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x15\x2f\x8c\x9d\xc9\x85\x79\x6e\xb1\x94\xed\x14\xc5\x9e\xac\xdd"
|
||||
"\x41\x8a\x33\x32\x36\xb7\x8f\xaf\xa7\xc7\x9b\x04\xe0\xac\xe7\xbf" // Ki
|
||||
"\xcd\x8a\x10\xe2\x79\xda\xdd\xb6\x90\x1e\xc3\x0b\xdf\x98\x73\x25"
|
||||
"\x0f\x6e\xfc\x6a\x77\x36\x7d\x74\xdc\x3e\xe7\xf7\x4b\xc7\x77\x4e", // Ke
|
||||
.klen = 4 + 4 + 32 * 2,
|
||||
.ptext =
|
||||
"\xCF\x9B\xCA\x6D\xF1\x14\x4E\x0C\x0A\xF9\xB8\xF3\x4C\x90\xD5\x14" // Confounder
|
||||
"13 bytes byte",
|
||||
.plen = 16 + 13,
|
||||
.ctext =
|
||||
"\xEE\xEC\x85\xA9\x81\x3C\xDC\x53\x67\x72\xAB\x9B\x42\xDE\xFC\x57"
|
||||
"\x06\xF7\x26\xE9\x75\xDD\xE0\x5A\x87\xEB\x54\x06\xEA\x32\x4C\xA1"
|
||||
"\x85\xC9\x98\x6B\x42\xAA\xBE\x79\x4B\x84\x82\x1B\xEE",
|
||||
.clen = 16 + 13 + 16,
|
||||
}, {
|
||||
// "enc 30 plain",
|
||||
.key =
|
||||
AUTHENC_KEY_HEADER("\x00\x00\x00\x20")
|
||||
"\x04\x8d\xeb\xf7\xb1\x2c\x09\x32\xe8\xb2\x96\x99\x6c\x23\xf8\xb7"
|
||||
"\x9d\x59\xb9\x7e\xa1\x19\xfc\x0c\x15\x6b\xf7\x88\xdc\x8c\x85\xe8" // Ki
|
||||
"\x1d\x51\x47\xf3\x4b\xb0\x01\xa0\x4a\x68\xa7\x13\x46\xe7\x65\x4e"
|
||||
"\x02\x23\xa6\x0d\x90\xbc\x2b\x79\xb4\xd8\x79\x56\xd4\x7c\xd4\x2a", // Ke
|
||||
.klen = 4 + 4 + 32 * 2,
|
||||
.ptext =
|
||||
"\x64\x4D\xEF\x38\xDA\x35\x00\x72\x75\x87\x8D\x21\x68\x55\xE2\x28" // Confounder
|
||||
"30 bytes bytes bytes bytes byt", // Plain
|
||||
.plen = 16 + 30,
|
||||
.ctext =
|
||||
"\x0E\x44\x68\x09\x85\x85\x5F\x2D\x1F\x18\x12\x52\x9C\xA8\x3B\xFD"
|
||||
"\x8E\x34\x9D\xE6\xFD\x9A\xDA\x0B\xAA\xA0\x48\xD6\x8E\x26\x5F\xEB"
|
||||
"\xF3\x4A\xD1\x25\x5A\x34\x49\x99\xAD\x37\x14\x68\x87\xA6\xC6\x84"
|
||||
"\x57\x31\xAC\x7F\x46\x37\x6A\x05\x04\xCD\x06\x57\x14\x74",
|
||||
.clen = 16 + 30 + 16,
|
||||
},
|
||||
};
|
||||
|
||||
#endif /* _CRYPTO_TESTMGR_H */
|
||||
|
|
|
|||
|
|
@ -28,5 +28,7 @@ struct crypto_authenc_keys {
|
|||
|
||||
int crypto_authenc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key,
|
||||
unsigned int keylen);
|
||||
int crypto_krb5enc_extractkeys(struct crypto_authenc_keys *keys, const u8 *key,
|
||||
unsigned int keylen);
|
||||
|
||||
#endif /* _CRYPTO_AUTHENC_H */
|
||||
|
|
|
|||
160
include/crypto/krb5.h
Normal file
160
include/crypto/krb5.h
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Kerberos 5 crypto
|
||||
*
|
||||
* Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_KRB5_H
|
||||
#define _CRYPTO_KRB5_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
struct crypto_shash;
|
||||
struct scatterlist;
|
||||
|
||||
/*
|
||||
* Per Kerberos v5 protocol spec crypto types from the wire. These get mapped
|
||||
* to linux kernel crypto routines.
|
||||
*/
|
||||
#define KRB5_ENCTYPE_NULL 0x0000
|
||||
#define KRB5_ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */
|
||||
#define KRB5_ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */
|
||||
#define KRB5_ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */
|
||||
#define KRB5_ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */
|
||||
/* XXX deprecated? */
|
||||
#define KRB5_ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */
|
||||
#define KRB5_ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
|
||||
#define KRB5_ENCTYPE_DES_HMAC_SHA1 0x0008
|
||||
#define KRB5_ENCTYPE_DES3_CBC_SHA1 0x0010
|
||||
#define KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011
|
||||
#define KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012
|
||||
#define KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128 0x0013
|
||||
#define KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192 0x0014
|
||||
#define KRB5_ENCTYPE_ARCFOUR_HMAC 0x0017
|
||||
#define KRB5_ENCTYPE_ARCFOUR_HMAC_EXP 0x0018
|
||||
#define KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC 0x0019
|
||||
#define KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC 0x001a
|
||||
#define KRB5_ENCTYPE_UNKNOWN 0x01ff
|
||||
|
||||
#define KRB5_CKSUMTYPE_CRC32 0x0001
|
||||
#define KRB5_CKSUMTYPE_RSA_MD4 0x0002
|
||||
#define KRB5_CKSUMTYPE_RSA_MD4_DES 0x0003
|
||||
#define KRB5_CKSUMTYPE_DESCBC 0x0004
|
||||
#define KRB5_CKSUMTYPE_RSA_MD5 0x0007
|
||||
#define KRB5_CKSUMTYPE_RSA_MD5_DES 0x0008
|
||||
#define KRB5_CKSUMTYPE_NIST_SHA 0x0009
|
||||
#define KRB5_CKSUMTYPE_HMAC_SHA1_DES3 0x000c
|
||||
#define KRB5_CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f
|
||||
#define KRB5_CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010
|
||||
#define KRB5_CKSUMTYPE_CMAC_CAMELLIA128 0x0011
|
||||
#define KRB5_CKSUMTYPE_CMAC_CAMELLIA256 0x0012
|
||||
#define KRB5_CKSUMTYPE_HMAC_SHA256_128_AES128 0x0013
|
||||
#define KRB5_CKSUMTYPE_HMAC_SHA384_192_AES256 0x0014
|
||||
#define KRB5_CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */
|
||||
|
||||
/*
|
||||
* Constants used for key derivation
|
||||
*/
|
||||
/* from rfc3961 */
|
||||
#define KEY_USAGE_SEED_CHECKSUM (0x99)
|
||||
#define KEY_USAGE_SEED_ENCRYPTION (0xAA)
|
||||
#define KEY_USAGE_SEED_INTEGRITY (0x55)
|
||||
|
||||
/*
|
||||
* Mode of operation.
|
||||
*/
|
||||
enum krb5_crypto_mode {
|
||||
KRB5_CHECKSUM_MODE, /* Checksum only */
|
||||
KRB5_ENCRYPT_MODE, /* Fully encrypted, possibly with integrity checksum */
|
||||
};
|
||||
|
||||
struct krb5_buffer {
|
||||
unsigned int len;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Kerberos encoding type definition.
|
||||
*/
|
||||
struct krb5_enctype {
|
||||
int etype; /* Encryption (key) type */
|
||||
int ctype; /* Checksum type */
|
||||
const char *name; /* "Friendly" name */
|
||||
const char *encrypt_name; /* Crypto encrypt+checksum name */
|
||||
const char *cksum_name; /* Crypto checksum name */
|
||||
const char *hash_name; /* Crypto hash name */
|
||||
const char *derivation_enc; /* Cipher used in key derivation */
|
||||
u16 block_len; /* Length of encryption block */
|
||||
u16 conf_len; /* Length of confounder (normally == block_len) */
|
||||
u16 cksum_len; /* Length of checksum */
|
||||
u16 key_bytes; /* Length of raw key, in bytes */
|
||||
u16 key_len; /* Length of final key, in bytes */
|
||||
u16 hash_len; /* Length of hash in bytes */
|
||||
u16 prf_len; /* Length of PRF() result in bytes */
|
||||
u16 Kc_len; /* Length of Kc in bytes */
|
||||
u16 Ke_len; /* Length of Ke in bytes */
|
||||
u16 Ki_len; /* Length of Ki in bytes */
|
||||
bool keyed_cksum; /* T if a keyed cksum */
|
||||
|
||||
const struct krb5_crypto_profile *profile;
|
||||
|
||||
int (*random_to_key)(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *in,
|
||||
struct krb5_buffer *out); /* complete key generation */
|
||||
};
|
||||
|
||||
/*
|
||||
* krb5_api.c
|
||||
*/
|
||||
const struct krb5_enctype *crypto_krb5_find_enctype(u32 enctype);
|
||||
size_t crypto_krb5_how_much_buffer(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t data_size, size_t *_offset);
|
||||
size_t crypto_krb5_how_much_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_buffer_size, size_t *_offset);
|
||||
void crypto_krb5_where_is_the_data(const struct krb5_enctype *krb5,
|
||||
enum krb5_crypto_mode mode,
|
||||
size_t *_offset, size_t *_len);
|
||||
struct crypto_aead *crypto_krb5_prepare_encryption(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp);
|
||||
struct crypto_shash *crypto_krb5_prepare_checksum(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *TK,
|
||||
u32 usage, gfp_t gfp);
|
||||
ssize_t crypto_krb5_encrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len,
|
||||
bool preconfounded);
|
||||
int crypto_krb5_decrypt(const struct krb5_enctype *krb5,
|
||||
struct crypto_aead *aead,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
ssize_t crypto_krb5_get_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t sg_len,
|
||||
size_t data_offset, size_t data_len);
|
||||
int crypto_krb5_verify_mic(const struct krb5_enctype *krb5,
|
||||
struct crypto_shash *shash,
|
||||
const struct krb5_buffer *metadata,
|
||||
struct scatterlist *sg, unsigned int nr_sg,
|
||||
size_t *_offset, size_t *_len);
|
||||
|
||||
/*
|
||||
* krb5_kdf.c
|
||||
*/
|
||||
int crypto_krb5_calc_PRFplus(const struct krb5_enctype *krb5,
|
||||
const struct krb5_buffer *K,
|
||||
unsigned int L,
|
||||
const struct krb5_buffer *S,
|
||||
struct krb5_buffer *result,
|
||||
gfp_t gfp);
|
||||
|
||||
#endif /* _CRYPTO_KRB5_H */
|
||||
Loading…
Reference in New Issue
Block a user