]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
crypto/krb5: Implement the Camellia enctypes from rfc6803
authorDavid Howells <dhowells@redhat.com>
Fri, 25 Sep 2020 11:24:50 +0000 (12:24 +0100)
committerDavid Howells <dhowells@redhat.com>
Sun, 2 Mar 2025 21:55:23 +0000 (21:55 +0000)
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

crypto/krb5/Kconfig
crypto/krb5/Makefile
crypto/krb5/internal.h
crypto/krb5/krb5_api.c
crypto/krb5/rfc6803_camellia.c [new file with mode: 0644]
include/crypto/krb5.h

index 52f0ed2d782018b5445b1d78b54e6ea15f67f328..5b339690905cfe87bc16d512d8149147877a42d9 100644 (file)
@@ -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.
index 7fd215ec3a8514d2c0bd83b4eff254a9cddd54b7..7cbe5e5ded19db005f2f95a03fc62891aa04586e 100644 (file)
@@ -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
index f537f6eb86eb33cf6da8533750175f3b0fe31ad2..8679140ef90d391a94f92a3695ed6fbe7430dff1 100644 (file)
@@ -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
  */
index 5b94cc5db4616866dbb684b012dd4f5beeffc6f3..02e21c8f4d144909b09b14b3c9ef457cb10d51bb 100644 (file)
@@ -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,
 };
 
 /**
diff --git a/crypto/krb5/rfc6803_camellia.c b/crypto/krb5/rfc6803_camellia.c
new file mode 100644 (file)
index 0000000..77cd4ce
--- /dev/null
@@ -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,
+};
index b8fda81379ab30ca9d3e744394976c447fc7afa1..62d998e62f47d1040eea25cb8da3d829063c533c 100644 (file)
@@ -35,6 +35,8 @@ struct scatterlist;
 #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
@@ -47,6 +49,8 @@ struct scatterlist;
 #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 */