]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Add aes-sha2 enctype support
authorGreg Hudson <ghudson@mit.edu>
Sun, 6 Dec 2015 00:36:57 +0000 (19:36 -0500)
committerGreg Hudson <ghudson@mit.edu>
Mon, 3 Oct 2016 19:38:13 +0000 (15:38 -0400)
Add support to libk5crypto for the aes128-cts-hmac-sha256-128 and
aes256-cts-hmac-sha384-192 encryption types, and the
hmac-sha256-128-aes128 and hmac-sha384-192-aes256 checksum types.

Key derivation for the new encryption types uses a hash, so we need to
add a hash parameter to the krb5int_derive_ functions, which can be
null except when DERIVE_SP800_108_HMAC is given.  Rename the helper
function derive_random_sp800_108_cmac() to
derive_random_sp800_108_feedback_cmac() to make it clear that feedback
mode is used, since the new enctype uses counter mode.

ticket: 8490

18 files changed:
src/include/krb5/krb5.hin
src/lib/crypto/crypto_tests/t_derive.c
src/lib/crypto/krb/Makefile.in
src/lib/crypto/krb/checksum_dk_cmac.c
src/lib/crypto/krb/checksum_dk_hmac.c
src/lib/crypto/krb/checksum_etm.c [new file with mode: 0644]
src/lib/crypto/krb/cksumtypes.c
src/lib/crypto/krb/combine_keys.c
src/lib/crypto/krb/crypto_int.h
src/lib/crypto/krb/derive.c
src/lib/crypto/krb/enc_dk_cmac.c
src/lib/crypto/krb/enc_dk_hmac.c
src/lib/crypto/krb/enc_etm.c [new file with mode: 0644]
src/lib/crypto/krb/etypes.c
src/lib/crypto/krb/prf_aes2.c [new file with mode: 0644]
src/lib/crypto/krb/prf_cmac.c
src/lib/crypto/krb/prf_dk.c
src/lib/crypto/krb/s2k_pbkdf2.c

index 44c8bfa956cb9a7f5f01b585b134f4b9b50edbf2..64b0d0fb74fc84ef9036363ba8da46dc478a65c7 100644 (file)
@@ -423,14 +423,16 @@ typedef struct _krb5_crypto_iov {
 #define ENCTYPE_RSA_ES_OAEP_ENV 0x000e  /**< RSA w/OEAP encryption, CMS enveloped data */
 #define ENCTYPE_DES3_CBC_ENV    0x000f  /**< DES-3 cbc mode, CMS enveloped data */
 
-#define ENCTYPE_DES3_CBC_SHA1           0x0010
-#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011 /**< RFC 3962 */
-#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012 /**< RFC 3962 */
-#define ENCTYPE_ARCFOUR_HMAC            0x0017
-#define ENCTYPE_ARCFOUR_HMAC_EXP        0x0018
-#define ENCTYPE_CAMELLIA128_CTS_CMAC    0x0019 /**< RFC 6803 */
-#define ENCTYPE_CAMELLIA256_CTS_CMAC    0x001a /**< RFC 6803 */
-#define ENCTYPE_UNKNOWN                 0x01ff
+#define ENCTYPE_DES3_CBC_SHA1               0x0010
+#define ENCTYPE_AES128_CTS_HMAC_SHA1_96     0x0011 /**< RFC 3962 */
+#define ENCTYPE_AES256_CTS_HMAC_SHA1_96     0x0012 /**< RFC 3962 */
+#define ENCTYPE_AES128_CTS_HMAC_SHA256_128  0x0013
+#define ENCTYPE_AES256_CTS_HMAC_SHA384_192  0x0014
+#define ENCTYPE_ARCFOUR_HMAC                0x0017
+#define ENCTYPE_ARCFOUR_HMAC_EXP            0x0018
+#define ENCTYPE_CAMELLIA128_CTS_CMAC        0x0019 /**< RFC 6803 */
+#define ENCTYPE_CAMELLIA256_CTS_CMAC        0x001a /**< RFC 6803 */
+#define ENCTYPE_UNKNOWN                     0x01ff
 
 #define CKSUMTYPE_CRC32         0x0001
 #define CKSUMTYPE_RSA_MD4       0x0002
@@ -446,6 +448,8 @@ typedef struct _krb5_crypto_iov {
                                                 ENCTYPE_AES128_CTS_HMAC_SHA1_96 */
 #define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010 /**< RFC 3962. Used with
                                                 ENCTYPE_AES256_CTS_HMAC_SHA1_96 */
+#define CKSUMTYPE_HMAC_SHA256_128_AES128 0x0013
+#define CKSUMTYPE_HMAC_SHA384_192_AES256 0x0014
 #define CKSUMTYPE_CMAC_CAMELLIA128 0x0011 /**< RFC 6803 */
 #define CKSUMTYPE_CMAC_CAMELLIA256 0x0012 /**< RFC 6803 */
 #define CKSUMTYPE_MD5_HMAC_ARCFOUR -137 /*Microsoft netlogon cksumtype*/
index fe287513e5d3b68672f375169e1ec040d28651c0..f8c32917af25e6ec1fae27b3359020117ae90736 100644 (file)
@@ -259,7 +259,7 @@ main(int argc, char **argv)
         ret = krb5_k_create_key(context, &kb, &inkey);
         assert(!ret);
         enc = get_enc_provider(test->enctype);
-        ret = krb5int_derive_key(enc, inkey, &outkey, &test->constant,
+        ret = krb5int_derive_key(enc, NULL, inkey, &outkey, &test->constant,
                                  test->alg);
         assert(!ret);
         if (verbose) {
index 7b59839b0f50e4002e60585e45a28527d88db2ee..c5660c5fe1fa88d8e64a860c8ef77369f08685a2 100644 (file)
@@ -14,6 +14,7 @@ STLIBOBJS=\
        checksum_confounder.o   \
        checksum_dk_cmac.o      \
        checksum_dk_hmac.o      \
+       checksum_etm.o          \
        checksum_hmac_md5.o     \
        checksum_unkeyed.o      \
        checksum_length.o       \
@@ -35,6 +36,7 @@ STLIBOBJS=\
        enctype_util.o          \
        enc_dk_cmac.o           \
        enc_dk_hmac.o           \
+       enc_etm.o               \
        enc_old.o               \
        enc_raw.o               \
        enc_rc4.o               \
@@ -51,6 +53,7 @@ STLIBOBJS=\
        nfold.o                 \
        old_api_glue.o          \
        prf.o                   \
+       prf_aes2.o              \
        prf_cmac.o              \
        prf_des.o               \
        prf_dk.o                \
@@ -76,6 +79,7 @@ OBJS=\
        $(OUTPRE)checksum_confounder.$(OBJEXT)  \
        $(OUTPRE)checksum_dk_cmac.$(OBJEXT)     \
        $(OUTPRE)checksum_dk_hmac.$(OBJEXT)     \
+       $(OUTPRE)checksum_etm.$(OBJEXT)         \
        $(OUTPRE)checksum_hmac_md5.$(OBJEXT)    \
        $(OUTPRE)checksum_unkeyed.$(OBJEXT)     \
        $(OUTPRE)checksum_length.$(OBJEXT)      \
@@ -97,6 +101,7 @@ OBJS=\
        $(OUTPRE)enctype_util.$(OBJEXT)         \
        $(OUTPRE)enc_dk_cmac.$(OBJEXT)          \
        $(OUTPRE)enc_dk_hmac.$(OBJEXT)          \
+       $(OUTPRE)enc_etm.$(OBJEXT)              \
        $(OUTPRE)enc_old.$(OBJEXT)              \
        $(OUTPRE)enc_raw.$(OBJEXT)              \
        $(OUTPRE)enc_rc4.$(OBJEXT)              \
@@ -113,6 +118,7 @@ OBJS=\
        $(OUTPRE)nfold.$(OBJEXT)                \
        $(OUTPRE)old_api_glue.$(OBJEXT)         \
        $(OUTPRE)prf.$(OBJEXT)                  \
+       $(OUTPRE)prf_aes2.$(OBJEXT)             \
        $(OUTPRE)prf_cmac.$(OBJEXT)             \
        $(OUTPRE)prf_des.$(OBJEXT)              \
        $(OUTPRE)prf_dk.$(OBJEXT)               \
@@ -138,6 +144,7 @@ SRCS=\
        $(srcdir)/checksum_confounder.c \
        $(srcdir)/checksum_dk_cmac.c    \
        $(srcdir)/checksum_dk_hmac.c    \
+       $(srcdir)/checksum_etm.c        \
        $(srcdir)/checksum_hmac_md5.c   \
        $(srcdir)/checksum_unkeyed.c    \
        $(srcdir)/checksum_length.c     \
@@ -159,6 +166,7 @@ SRCS=\
        $(srcdir)/enctype_util.c        \
        $(srcdir)/enc_dk_cmac.c         \
        $(srcdir)/enc_dk_hmac.c         \
+       $(srcdir)/enc_etm.c             \
        $(srcdir)/enc_old.c             \
        $(srcdir)/enc_raw.c             \
        $(srcdir)/enc_rc4.c             \
@@ -175,6 +183,7 @@ SRCS=\
        $(srcdir)/nfold.c               \
        $(srcdir)/old_api_glue.c        \
        $(srcdir)/prf.c                 \
+       $(srcdir)/prf_aes2.c            \
        $(srcdir)/prf_cmac.c            \
        $(srcdir)/prf_des.c             \
        $(srcdir)/prf_dk.c              \
index 59d5c5a523224aadf15bd6ed3c9a480cd4fa0244..809f9d729b4183511a054d211cb971661d8cd75c 100644 (file)
@@ -44,7 +44,8 @@ krb5int_dk_cmac_checksum(const struct krb5_cksumtypes *ctp,
     datain = make_data(constantdata, K5CLENGTH);
     store_32_be(usage, constantdata);
     constantdata[4] = (char) 0x99;
-    ret = krb5int_derive_key(enc, key, &kc, &datain, DERIVE_SP800_108_CMAC);
+    ret = krb5int_derive_key(enc, NULL, key, &kc, &datain,
+                             DERIVE_SP800_108_CMAC);
     if (ret != 0)
         return ret;
 
index 517a5f32c89b2e42aab17172766fb8cffd742d08..64ab8993e838850844214124370d98c50e720bbb 100644 (file)
@@ -45,7 +45,7 @@ krb5int_dk_checksum(const struct krb5_cksumtypes *ctp,
     datain = make_data(constantdata, K5CLENGTH);
     store_32_be(usage, constantdata);
     constantdata[4] = (char) 0x99;
-    ret = krb5int_derive_key(enc, key, &kc, &datain, DERIVE_RFC3961);
+    ret = krb5int_derive_key(enc, NULL, key, &kc, &datain, DERIVE_RFC3961);
     if (ret)
         return ret;
 
diff --git a/src/lib/crypto/krb/checksum_etm.c b/src/lib/crypto/krb/checksum_etm.c
new file mode 100644 (file)
index 0000000..eaa85b2
--- /dev/null
@@ -0,0 +1,65 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/crypto/krb/checksum_etm.c - checksum for encrypt-then-mac enctypes */
+/*
+ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "crypto_int.h"
+
+krb5_error_code
+krb5int_etm_checksum(const struct krb5_cksumtypes *ctp, krb5_key key,
+                     krb5_keyusage usage, const krb5_crypto_iov *data,
+                     size_t num_data, krb5_data *output)
+{
+    krb5_error_code ret;
+    uint8_t label[5];
+    krb5_data label_data = make_data(label, 5), kc = empty_data();
+    krb5_keyblock kb = { 0 };
+
+    /* Derive the checksum key. */
+    store_32_be(usage, label);
+    label[4] = 0x99;
+    label_data = make_data(label, 5);
+    ret = alloc_data(&kc, ctp->hash->hashsize / 2);
+    if (ret)
+        goto cleanup;
+    ret = krb5int_derive_random(ctp->enc, ctp->hash, key, &kc, &label_data,
+                                DERIVE_SP800_108_HMAC);
+    if (ret)
+        goto cleanup;
+
+    /* Compute an HMAC with kc over the data. */
+    kb.length = kc.length;
+    kb.contents = (uint8_t *)kc.data;
+    ret = krb5int_hmac_keyblock(ctp->hash, &kb, data, num_data, output);
+
+cleanup:
+    zapfree(kc.data, kc.length);
+    return ret;
+}
index a1ced981fb19c15a2e52f3c16676843991a71cd2..85967f9aa0ad6a44407dd6860964d683ebfa4047 100644 (file)
@@ -112,6 +112,18 @@ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = {
       &krb5int_enc_camellia256, NULL,
       krb5int_dk_cmac_checksum, NULL,
       16, 16, 0 },
+
+    { CKSUMTYPE_HMAC_SHA256_128_AES128,
+      "hmac-sha256-128-aes128", { 0 }, "HMAC-SHA256 AES128 key",
+      &krb5int_enc_aes128, &krb5int_hash_sha256,
+      krb5int_etm_checksum, NULL,
+      32, 16, 0 },
+
+    { CKSUMTYPE_HMAC_SHA384_192_AES256,
+      "hmac-sha384-192-aes256", { 0 }, "HMAC-SHA384 AES256 key",
+      &krb5int_enc_aes256, &krb5int_hash_sha384,
+      krb5int_etm_checksum, NULL,
+      48, 24, 0 },
 };
 
 const size_t krb5int_cksumtypes_length =
index 9ab0ac4f94bbf3da03f6bb08292f43777bbf3187..90905c5ae2d836c97fa46d9011cfb796bdeb5bf4 100644 (file)
@@ -191,7 +191,8 @@ krb5int_c_combine_keys(krb5_context context, krb5_keyblock *key1,
         myalloc = TRUE;
     }
 
-    ret = krb5int_derive_keyblock(enc, tkey, outkey, &input, DERIVE_RFC3961);
+    ret = krb5int_derive_keyblock(enc, NULL, tkey, outkey, &input,
+                                  DERIVE_RFC3961);
     if (ret) {
         if (myalloc) {
             free(outkey->contents);
@@ -222,7 +223,7 @@ dr(const struct krb5_enc_provider *enc, const krb5_keyblock *inkey,
     ret = krb5_k_create_key(NULL, inkey, &key);
     if (ret != 0)
         return ret;
-    ret = krb5int_derive_random(enc, key, &outdata, in_constant,
+    ret = krb5int_derive_random(enc, NULL, key, &outdata, in_constant,
                                 DERIVE_RFC3961);
     krb5_k_free_key(NULL, key);
     return ret;
index fec0eab777e6a47cfa51e5bbb59039f67de37d48..d75b49c693f03fe9bfe906302df4c1a0fce4d525 100644 (file)
@@ -184,6 +184,8 @@ unsigned int krb5int_aes_crypto_length(const struct krb5_keytypes *ktp,
                                        krb5_cryptotype type);
 unsigned int krb5int_camellia_crypto_length(const struct krb5_keytypes *ktp,
                                             krb5_cryptotype type);
+unsigned int krb5int_aes2_crypto_length(const struct krb5_keytypes *ktp,
+                                        krb5_cryptotype type);
 
 /* Encrypt */
 krb5_error_code krb5int_old_encrypt(const struct krb5_keytypes *ktp,
@@ -208,6 +210,10 @@ krb5_error_code krb5int_dk_cmac_encrypt(const struct krb5_keytypes *ktp,
                                         const krb5_data *ivec,
                                         krb5_crypto_iov *data,
                                         size_t num_data);
+krb5_error_code krb5int_etm_encrypt(const struct krb5_keytypes *ktp,
+                                    krb5_key key, krb5_keyusage usage,
+                                    const krb5_data *ivec,
+                                    krb5_crypto_iov *data, size_t num_data);
 
 /* Decrypt */
 krb5_error_code krb5int_old_decrypt(const struct krb5_keytypes *ktp,
@@ -232,6 +238,10 @@ krb5_error_code krb5int_dk_cmac_decrypt(const struct krb5_keytypes *ktp,
                                         const krb5_data *ivec,
                                         krb5_crypto_iov *data,
                                         size_t num_data);
+krb5_error_code krb5int_etm_decrypt(const struct krb5_keytypes *ktp,
+                                    krb5_key key, krb5_keyusage usage,
+                                    const krb5_data *ivec,
+                                    krb5_crypto_iov *data, size_t num_data);
 
 /* String to key */
 krb5_error_code krb5int_des_string_to_key(const struct krb5_keytypes *ktp,
@@ -259,6 +269,11 @@ krb5_error_code krb5int_camellia_string_to_key(const struct krb5_keytypes *enc,
                                                const krb5_data *salt,
                                                const krb5_data *params,
                                                krb5_keyblock *key);
+krb5_error_code krb5int_aes2_string_to_key(const struct krb5_keytypes *enc,
+                                           const krb5_data *string,
+                                           const krb5_data *salt,
+                                           const krb5_data *params,
+                                           krb5_keyblock *key);
 
 /* Random to key */
 krb5_error_code k5_rand2key_direct(const krb5_data *randombits,
@@ -280,6 +295,8 @@ krb5_error_code krb5int_dk_prf(const struct krb5_keytypes *ktp, krb5_key key,
 krb5_error_code krb5int_dk_cmac_prf(const struct krb5_keytypes *ktp,
                                     krb5_key key, const krb5_data *in,
                                     krb5_data *out);
+krb5_error_code krb5int_aes2_prf(const struct krb5_keytypes *ktp, krb5_key key,
+                                 const krb5_data *in, krb5_data *out);
 
 /*** Prototypes for cksumtype handler functions ***/
 
@@ -317,26 +334,38 @@ krb5_error_code krb5int_confounder_verify(const struct krb5_cksumtypes *ctp,
                                           size_t num_data,
                                           const krb5_data *input,
                                           krb5_boolean *valid);
+krb5_error_code krb5int_etm_checksum(const struct krb5_cksumtypes *ctp,
+                                     krb5_key key, krb5_keyusage usage,
+                                     const krb5_crypto_iov *data,
+                                     size_t num_data, krb5_data *output);
 
 /*** Key derivation functions ***/
 
 enum deriv_alg {
     DERIVE_RFC3961,             /* RFC 3961 section 5.1 */
-    DERIVE_SP800_108_CMAC       /* NIST SP 800-108 with CMAC as PRF */
+    DERIVE_SP800_108_CMAC,      /* NIST SP 800-108 with CMAC as PRF */
+    DERIVE_SP800_108_HMAC       /* NIST SP 800-108 with HMAC as PRF */
 };
 
 krb5_error_code krb5int_derive_keyblock(const struct krb5_enc_provider *enc,
+                                        const struct krb5_hash_provider *hash,
                                         krb5_key inkey, krb5_keyblock *outkey,
                                         const krb5_data *in_constant,
                                         enum deriv_alg alg);
 krb5_error_code krb5int_derive_key(const struct krb5_enc_provider *enc,
+                                   const struct krb5_hash_provider *hash,
                                    krb5_key inkey, krb5_key *outkey,
                                    const krb5_data *in_constant,
                                    enum deriv_alg alg);
 krb5_error_code krb5int_derive_random(const struct krb5_enc_provider *enc,
+                                      const struct krb5_hash_provider *hash,
                                       krb5_key inkey, krb5_data *outrnd,
                                       const krb5_data *in_constant,
                                       enum deriv_alg alg);
+krb5_error_code
+k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
+                          krb5_key inkey, krb5_data *outrnd,
+                          const krb5_data *label, const krb5_data *context);
 
 /*** Miscellaneous prototypes ***/
 
index f15fec1a292763414a5db41b1e5fd596afe270ab..6707a73082596e3942f543b92e5fefca76717530 100644 (file)
@@ -139,9 +139,9 @@ cleanup:
  *   - Four bytes are used to encode the output length in the PRF input.
  */
 static krb5_error_code
-derive_random_sp800_108_cmac(const struct krb5_enc_provider *enc,
-                             krb5_key inkey, krb5_data *outrnd,
-                             const krb5_data *in_constant)
+derive_random_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
+                                      krb5_key inkey, krb5_data *outrnd,
+                                      const krb5_data *in_constant)
 {
     size_t blocksize, keybytes, n;
     krb5_crypto_iov iov[6];
@@ -204,16 +204,75 @@ cleanup:
     return ret;
 }
 
+/*
+ * NIST SP800-108 KDF in counter mode (section 5.1).
+ * Parameters:
+ *   - HMAC (with hash as the hash provider) is the PRF.
+ *   - A block counter of four bytes is used.
+ *   - Four bytes are used to encode the output length in the PRF input.
+ *
+ * There are no uses requiring more than a single PRF invocation.
+ */
+krb5_error_code
+k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
+                          krb5_key inkey, krb5_data *outrnd,
+                          const krb5_data *label, const krb5_data *context)
+{
+    krb5_crypto_iov iov[5];
+    krb5_error_code ret;
+    krb5_data prf;
+    unsigned char ibuf[4], lbuf[4];
+
+    if (hash == NULL || outrnd->length > hash->hashsize)
+        return KRB5_CRYPTO_INTERNAL;
+
+    /* Allocate encryption data buffer. */
+    ret = alloc_data(&prf, hash->hashsize);
+    if (ret)
+        return ret;
+
+    /* [i]2: four-byte big-endian binary string giving the block counter (1) */
+    iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[0].data = make_data(ibuf, sizeof(ibuf));
+    store_32_be(1, ibuf);
+    /* Label */
+    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[1].data = *label;
+    /* 0x00: separator byte */
+    iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[2].data = make_data("", 1);
+    /* Context */
+    iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[3].data = *context;
+    /* [L]2: four-byte big-endian binary string giving the output length */
+    iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
+    iov[4].data = make_data(lbuf, sizeof(lbuf));
+    store_32_be(outrnd->length * 8, lbuf);
+
+    ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
+    if (!ret)
+        memcpy(outrnd->data, prf.data, outrnd->length);
+    zapfree(prf.data, prf.length);
+    return ret;
+}
+
 krb5_error_code
 krb5int_derive_random(const struct krb5_enc_provider *enc,
+                      const struct krb5_hash_provider *hash,
                       krb5_key inkey, krb5_data *outrnd,
                       const krb5_data *in_constant, enum deriv_alg alg)
 {
+    krb5_data empty = empty_data();
+
     switch (alg) {
     case DERIVE_RFC3961:
         return derive_random_rfc3961(enc, inkey, outrnd, in_constant);
     case DERIVE_SP800_108_CMAC:
-        return derive_random_sp800_108_cmac(enc, inkey, outrnd, in_constant);
+        return derive_random_sp800_108_feedback_cmac(enc, inkey, outrnd,
+                                                     in_constant);
+    case DERIVE_SP800_108_HMAC:
+        return k5_sp800_108_counter_hmac(hash, inkey, outrnd, in_constant,
+                                         &empty);
     default:
         return EINVAL;
     }
@@ -227,6 +286,7 @@ krb5int_derive_random(const struct krb5_enc_provider *enc,
  */
 krb5_error_code
 krb5int_derive_keyblock(const struct krb5_enc_provider *enc,
+                        const struct krb5_hash_provider *hash,
                         krb5_key inkey, krb5_keyblock *outkey,
                         const krb5_data *in_constant, enum deriv_alg alg)
 {
@@ -239,7 +299,7 @@ krb5int_derive_keyblock(const struct krb5_enc_provider *enc,
         goto cleanup;
 
     /* Derive pseudo-random data for the key bytes. */
-    ret = krb5int_derive_random(enc, inkey, &rawkey, in_constant, alg);
+    ret = krb5int_derive_random(enc, hash, inkey, &rawkey, in_constant, alg);
     if (ret)
         goto cleanup;
 
@@ -253,6 +313,7 @@ cleanup:
 
 krb5_error_code
 krb5int_derive_key(const struct krb5_enc_provider *enc,
+                   const struct krb5_hash_provider *hash,
                    krb5_key inkey, krb5_key *outkey,
                    const krb5_data *in_constant, enum deriv_alg alg)
 {
@@ -275,7 +336,8 @@ krb5int_derive_key(const struct krb5_enc_provider *enc,
     keyblock.enctype = inkey->keyblock.enctype;
     if (keyblock.contents == NULL)
         return ENOMEM;
-    ret = krb5int_derive_keyblock(enc, inkey, &keyblock, in_constant, alg);
+    ret = krb5int_derive_keyblock(enc, hash, inkey, &keyblock, in_constant,
+                                  alg);
     if (ret)
         goto cleanup;
 
index 9bb3dbaecd4ea21a152811eb6dce81207fe6a140..b65b9b70eb1c322f5e43000e37e2315e30655277 100644 (file)
@@ -64,13 +64,15 @@ derive_keys(const struct krb5_enc_provider *enc, krb5_key key,
     /* Derive the encryption key. */
     store_32_be(usage, buf);
     buf[4] = 0xAA;
-    ret = krb5int_derive_key(enc, key, &ke, &constant, DERIVE_SP800_108_CMAC);
+    ret = krb5int_derive_key(enc, NULL, key, &ke, &constant,
+                             DERIVE_SP800_108_CMAC);
     if (ret != 0)
         return ret;
 
     /* Derive the integrity key. */
     buf[4] = 0x55;
-    ret = krb5int_derive_key(enc, key, &ki, &constant, DERIVE_SP800_108_CMAC);
+    ret = krb5int_derive_key(enc, NULL, key, &ki, &constant,
+                             DERIVE_SP800_108_CMAC);
     if (ret != 0) {
         krb5_k_free_key(NULL, ke);
         return ret;
index f16459ec21544ee7902774254b6ad02b71448f16..713044c67d69215df99647b02b89d4284afa01a5 100644 (file)
@@ -131,13 +131,13 @@ krb5int_dk_encrypt(const struct krb5_keytypes *ktp, krb5_key key,
 
     d1.data[4] = 0xAA;
 
-    ret = krb5int_derive_key(enc, key, &ke, &d1, DERIVE_RFC3961);
+    ret = krb5int_derive_key(enc, NULL, key, &ke, &d1, DERIVE_RFC3961);
     if (ret != 0)
         goto cleanup;
 
     d1.data[4] = 0x55;
 
-    ret = krb5int_derive_key(enc, key, &ki, &d1, DERIVE_RFC3961);
+    ret = krb5int_derive_key(enc, NULL, key, &ki, &d1, DERIVE_RFC3961);
     if (ret != 0)
         goto cleanup;
 
@@ -232,13 +232,13 @@ krb5int_dk_decrypt(const struct krb5_keytypes *ktp, krb5_key key,
 
     d1.data[4] = 0xAA;
 
-    ret = krb5int_derive_key(enc, key, &ke, &d1, DERIVE_RFC3961);
+    ret = krb5int_derive_key(enc, NULL, key, &ke, &d1, DERIVE_RFC3961);
     if (ret != 0)
         goto cleanup;
 
     d1.data[4] = 0x55;
 
-    ret = krb5int_derive_key(enc, key, &ki, &d1, DERIVE_RFC3961);
+    ret = krb5int_derive_key(enc, NULL, key, &ki, &d1, DERIVE_RFC3961);
     if (ret != 0)
         goto cleanup;
 
diff --git a/src/lib/crypto/krb/enc_etm.c b/src/lib/crypto/krb/enc_etm.c
new file mode 100644 (file)
index 0000000..3135dd5
--- /dev/null
@@ -0,0 +1,257 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/crypto/krb/enc_etm.c - encrypt-then-mac construction for aes-sha2 */
+/*
+ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "crypto_int.h"
+
+unsigned int
+krb5int_aes2_crypto_length(const struct krb5_keytypes *ktp,
+                           krb5_cryptotype type)
+{
+    switch (type) {
+    case KRB5_CRYPTO_TYPE_HEADER:
+        return ktp->enc->block_size;
+    case KRB5_CRYPTO_TYPE_PADDING:
+        return 0;
+    case KRB5_CRYPTO_TYPE_TRAILER:
+    case KRB5_CRYPTO_TYPE_CHECKSUM:
+        return ktp->hash->hashsize / 2;
+    default:
+        assert(0 && "invalid cryptotype passed to krb5int_aes2_crypto_length");
+        return 0;
+    }
+}
+
+/* Derive encryption and integrity keys for CMAC-using enctypes. */
+static krb5_error_code
+derive_keys(const struct krb5_keytypes *ktp, krb5_key key,
+            krb5_keyusage usage, krb5_key *ke_out, krb5_data *ki_out)
+{
+    krb5_error_code ret;
+    uint8_t label[5];
+    krb5_data label_data = make_data(label, 5), ki = empty_data();
+    krb5_key ke = NULL;
+
+    *ke_out = NULL;
+    *ki_out = empty_data();
+
+    /* Derive the encryption key. */
+    store_32_be(usage, label);
+    label[4] = 0xAA;
+    ret = krb5int_derive_key(ktp->enc, ktp->hash, key, &ke, &label_data,
+                             DERIVE_SP800_108_HMAC);
+    if (ret)
+        goto cleanup;
+
+    /* Derive the integrity key. */
+    label[4] = 0x55;
+    ret = alloc_data(&ki, ktp->hash->hashsize / 2);
+    if (ret)
+        goto cleanup;
+    ret = krb5int_derive_random(NULL, ktp->hash, key, &ki, &label_data,
+                                DERIVE_SP800_108_HMAC);
+    if (ret)
+        goto cleanup;
+
+    *ke_out = ke;
+    ke = NULL;
+    *ki_out = ki;
+    ki = empty_data();
+
+cleanup:
+    krb5_k_free_key(NULL, ke);
+    zapfree(ki.data, ki.length);
+    return ret;
+}
+
+/* Compute an HMAC checksum over the cipher state and data.  Allocate enough
+ * space in *out for the checksum. */
+static krb5_error_code
+hmac_ivec_data(const struct krb5_keytypes *ktp, const krb5_data *ki,
+               const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data,
+               krb5_data *out)
+{
+    krb5_error_code ret;
+    krb5_data zeroivec = empty_data();
+    krb5_crypto_iov *iovs = NULL;
+    krb5_keyblock kb = { 0 };
+
+    if (ivec == NULL) {
+        ret = ktp->enc->init_state(NULL, 0, &zeroivec);
+        if (ret)
+            goto cleanup;
+        ivec = &zeroivec;
+    }
+
+    /* Make a copy of data with an extra iov at the beginning for the ivec. */
+    iovs = k5calloc(num_data + 1, sizeof(*iovs), &ret);
+    if (iovs == NULL)
+        goto cleanup;
+    iovs[0].flags = KRB5_CRYPTO_TYPE_DATA;
+    iovs[0].data = *ivec;
+    memcpy(iovs + 1, data, num_data * sizeof(*iovs));
+
+    ret = alloc_data(out, ktp->hash->hashsize);
+    if (ret)
+        goto cleanup;
+    kb.length = ki->length;
+    kb.contents = (uint8_t *)ki->data;
+    ret = krb5int_hmac_keyblock(ktp->hash, &kb, iovs, num_data + 1, out);
+
+cleanup:
+    if (zeroivec.data != NULL)
+        ktp->enc->free_state(&zeroivec);
+    free(iovs);
+    return ret;
+}
+
+krb5_error_code
+krb5int_etm_encrypt(const struct krb5_keytypes *ktp, krb5_key key,
+                    krb5_keyusage usage, const krb5_data *ivec,
+                    krb5_crypto_iov *data, size_t num_data)
+{
+    const struct krb5_enc_provider *enc = ktp->enc;
+    krb5_error_code ret;
+    krb5_data ivcopy = empty_data(), cksum = empty_data();
+    krb5_crypto_iov *header, *trailer, *padding;
+    krb5_key ke = NULL;
+    krb5_data ki = empty_data();
+    unsigned int trailer_len;
+
+    /* E(Confounder | Plaintext) | Checksum(IV | ciphertext) */
+
+    trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER);
+
+    /* Validate header and trailer lengths, and zero out padding length. */
+    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
+    if (header == NULL || header->data.length < enc->block_size)
+        return KRB5_BAD_MSIZE;
+    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
+    if (trailer == NULL || trailer->data.length < trailer_len)
+        return KRB5_BAD_MSIZE;
+    padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
+    if (padding != NULL)
+        padding->data.length = 0;
+
+    if (ivec != NULL) {
+        ret = alloc_data(&ivcopy, ivec->length);
+        if (ret)
+            goto cleanup;
+        memcpy(ivcopy.data, ivec->data, ivec->length);
+    }
+
+    /* Derive the encryption and integrity keys. */
+    ret = derive_keys(ktp, key, usage, &ke, &ki);
+    if (ret)
+        goto cleanup;
+
+    /* Generate confounder. */
+    header->data.length = enc->block_size;
+    ret = krb5_c_random_make_octets(NULL, &header->data);
+    if (ret)
+        goto cleanup;
+
+    /* Encrypt the plaintext (header | data). */
+    ret = enc->encrypt(ke, (ivec == NULL) ? NULL : &ivcopy, data, num_data);
+    if (ret)
+        goto cleanup;
+
+    /* HMAC the IV, confounder, and ciphertext with sign-only data. */
+    ret = hmac_ivec_data(ktp, &ki, ivec, data, num_data, &cksum);
+    if (ret)
+        goto cleanup;
+
+    /* Truncate the HMAC checksum to the trailer length. */
+    assert(trailer_len <= cksum.length);
+    memcpy(trailer->data.data, cksum.data, trailer_len);
+    trailer->data.length = trailer_len;
+
+    /* Copy out the updated ivec if desired. */
+    if (ivec != NULL)
+        memcpy(ivec->data, ivcopy.data, ivcopy.length);
+
+cleanup:
+    krb5_k_free_key(NULL, ke);
+    zapfree(ki.data, ki.length);
+    free(cksum.data);
+    zapfree(ivcopy.data, ivcopy.length);
+    return ret;
+}
+
+krb5_error_code
+krb5int_etm_decrypt(const struct krb5_keytypes *ktp, krb5_key key,
+                    krb5_keyusage usage, const krb5_data *ivec,
+                    krb5_crypto_iov *data, size_t num_data)
+{
+    const struct krb5_enc_provider *enc = ktp->enc;
+    krb5_error_code ret;
+    krb5_data cksum = empty_data();
+    krb5_crypto_iov *header, *trailer;
+    krb5_key ke = NULL;
+    krb5_data ki = empty_data();
+    unsigned int trailer_len;
+
+    trailer_len = ktp->crypto_length(ktp, KRB5_CRYPTO_TYPE_TRAILER);
+
+    /* Validate header and trailer lengths. */
+    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
+    if (header == NULL || header->data.length != enc->block_size)
+        return KRB5_BAD_MSIZE;
+    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
+    if (trailer == NULL || trailer->data.length != trailer_len)
+        return KRB5_BAD_MSIZE;
+
+    /* Derive the encryption and integrity keys. */
+    ret = derive_keys(ktp, key, usage, &ke, &ki);
+    if (ret)
+        goto cleanup;
+
+    /* HMAC the IV, confounder, and ciphertext with sign-only data. */
+    ret = hmac_ivec_data(ktp, &ki, ivec, data, num_data, &cksum);
+    if (ret)
+        goto cleanup;
+
+    /* Compare only the possibly truncated length. */
+    assert(trailer_len <= cksum.length);
+    if (k5_bcmp(cksum.data, trailer->data.data, trailer_len) != 0) {
+        ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+        goto cleanup;
+    }
+
+    /* Decrypt the ciphertext (header | data | padding). */
+    ret = enc->decrypt(ke, ivec, data, num_data);
+
+cleanup:
+    krb5_k_free_key(NULL, ke);
+    zapfree(ki.data, ki.length);
+    zapfree(cksum.data, cksum.length);
+    return ret;
+}
index 53be1d54df5196eccf39c74346bf53d6e6398c1f..112ae08aa5648561ac95cc3e8cfd80183033c3c1 100644 (file)
@@ -167,6 +167,27 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
       krb5int_dk_cmac_prf,
       CKSUMTYPE_CMAC_CAMELLIA256,
       0 /*flags */ },
+
+    { ENCTYPE_AES128_CTS_HMAC_SHA256_128,
+      "aes128-cts-hmac-sha256-128", { "aes128-sha2" },
+      "AES-128 CTS mode with 128-bit SHA-256 HMAC",
+      &krb5int_enc_aes128, &krb5int_hash_sha256,
+      32,
+      krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt,
+      krb5int_aes2_string_to_key, k5_rand2key_direct,
+      krb5int_aes2_prf,
+      CKSUMTYPE_HMAC_SHA256_128_AES128,
+      0 /*flags*/ },
+    { ENCTYPE_AES256_CTS_HMAC_SHA384_192,
+      "aes256-cts-hmac-sha384-192", { "aes256-sha2" },
+      "AES-256 CTS mode with 192-bit SHA-384 HMAC",
+      &krb5int_enc_aes256, &krb5int_hash_sha384,
+      48,
+      krb5int_aes2_crypto_length, krb5int_etm_encrypt, krb5int_etm_decrypt,
+      krb5int_aes2_string_to_key, k5_rand2key_direct,
+      krb5int_aes2_prf,
+      CKSUMTYPE_HMAC_SHA384_192_AES256,
+      0 /*flags*/ },
 };
 
 const int krb5int_enctypes_length =
diff --git a/src/lib/crypto/krb/prf_aes2.c b/src/lib/crypto/krb/prf_aes2.c
new file mode 100644 (file)
index 0000000..9a5cffc
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/crypto/krb/prf_aes2.c - PRF for aes-sha2 enctypes */
+/*
+ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "crypto_int.h"
+
+krb5_error_code
+krb5int_aes2_prf(const struct krb5_keytypes *ktp, krb5_key key,
+                 const krb5_data *in, krb5_data *out)
+{
+    krb5_data label = string2data("prf");
+
+    return k5_sp800_108_counter_hmac(ktp->hash, key, out, &label, in);
+}
index 131c36d123f96a8f0bbe57ca3a9fe482e341a6bb..1d4cc4c39501c30071994951906ecf5b24611b08 100644 (file)
@@ -42,7 +42,7 @@ krb5int_dk_cmac_prf(const struct krb5_keytypes *ktp, krb5_key key,
     iov.data = *in;
 
     /* Derive a key using the PRF constant. */
-    ret = krb5int_derive_key(ktp->enc, key, &kp, &prfconst,
+    ret = krb5int_derive_key(ktp->enc, NULL, key, &kp, &prfconst,
                              DERIVE_SP800_108_CMAC);
     if (ret != 0)
         goto cleanup;
index bf8d5223be32bc5c05d147fce7f1bfaf50d671fd..544418bab74e37e28bc4b85703552e633218a591 100644 (file)
@@ -48,7 +48,8 @@ krb5int_dk_prf(const struct krb5_keytypes *ktp, krb5_key key,
         goto cleanup;
 
     /* Derive a key using the PRF constant. */
-    ret = krb5int_derive_key(ktp->enc, key, &kp, &prfconst, DERIVE_RFC3961);
+    ret = krb5int_derive_key(ktp->enc, NULL, key, &kp, &prfconst,
+                             DERIVE_RFC3961);
     if (ret != 0)
         goto cleanup;
 
index 316f59a9052ab3676574899735adb305cd2168f8..ec5856c2be79b9664e06b08dcb6c0d5d0f33c4cb 100644 (file)
@@ -87,7 +87,7 @@ krb5int_dk_string_to_key(const struct krb5_keytypes *ktp,
     indata.length = kerberos_len;
     indata.data = (char *) kerberos;
 
-    ret = krb5int_derive_keyblock(ktp->enc, foldkey, keyblock, &indata,
+    ret = krb5int_derive_keyblock(ktp->enc, NULL, foldkey, keyblock, &indata,
                                   DERIVE_RFC3961);
     if (ret != 0)
         memset(keyblock->contents, 0, keyblock->length);
@@ -168,7 +168,8 @@ pbkdf2_string_to_key(const struct krb5_keytypes *ktp, const krb5_data *string,
     if (err)
         goto cleanup;
 
-    err = krb5int_derive_keyblock(ktp->enc, tempkey, key, &usage, deriv_alg);
+    err = krb5int_derive_keyblock(ktp->enc, ktp->hash, tempkey, key, &usage,
+                                  deriv_alg);
 
 cleanup:
     if (sandp.data)
@@ -202,3 +203,14 @@ krb5int_camellia_string_to_key(const struct krb5_keytypes *ktp,
     return pbkdf2_string_to_key(ktp, string, salt, &pepper, params, key,
                                 DERIVE_SP800_108_CMAC, 32768);
 }
+
+krb5_error_code
+krb5int_aes2_string_to_key(const struct krb5_keytypes *ktp,
+                           const krb5_data *string, const krb5_data *salt,
+                           const krb5_data *params, krb5_keyblock *key)
+{
+    krb5_data pepper = string2data(ktp->name);
+
+    return pbkdf2_string_to_key(ktp, string, salt, &pepper, params, key,
+                                DERIVE_SP800_108_HMAC, 32768);
+}