mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 15:39:42 -04:00
crypto/krb5: Implement the Camellia enctypes from rfc6803
Implement the camellia128-cts-cmac and camellia256-cts-cmac enctypes from rfc6803. Note that the test vectors in rfc6803 for encryption are incomplete, lacking the key usage number needed to derive Ke and Ki, and there are errata for this: https://www.rfc-editor.org/errata_search.php?rfc=6803 Signed-off-by: David Howells <dhowells@redhat.com> cc: Herbert Xu <herbert@gondor.apana.org.au> cc: "David S. Miller" <davem@davemloft.net> cc: Chuck Lever <chuck.lever@oracle.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: Eric Dumazet <edumazet@google.com> cc: Jakub Kicinski <kuba@kernel.org> cc: Paolo Abeni <pabeni@redhat.com> cc: Simon Horman <horms@kernel.org> cc: linux-afs@lists.infradead.org cc: linux-nfs@vger.kernel.org cc: linux-crypto@vger.kernel.org cc: netdev@vger.kernel.org
This commit is contained in:
@@ -6,12 +6,14 @@ config CRYPTO_KRB5
|
||||
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.
|
||||
|
||||
@@ -8,6 +8,7 @@ krb5-y += \
|
||||
krb5_api.o \
|
||||
rfc3961_simplified.o \
|
||||
rfc3962_aes.o \
|
||||
rfc6803_camellia.o \
|
||||
rfc8009_aes2.o
|
||||
|
||||
obj-$(CONFIG_CRYPTO_KRB5) += krb5.o
|
||||
|
||||
@@ -186,6 +186,12 @@ int rfc3961_verify_mic(const struct krb5_enctype *krb5,
|
||||
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
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,8 @@ static const struct krb5_enctype *const krb5_supported_enctypes[] = {
|
||||
&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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
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,
|
||||
};
|
||||
Reference in New Issue
Block a user