krb5 commit: Add aes-sha2 enctype support

Greg Hudson ghudson at mit.edu
Mon Oct 3 16:02:42 EDT 2016


https://github.com/krb5/krb5/commit/135a9ac3c58b444998361a3b13f5decfdece2105
commit 135a9ac3c58b444998361a3b13f5decfdece2105
Author: Greg Hudson <ghudson at mit.edu>
Date:   Sat Dec 5 19:36:57 2015 -0500

    Add aes-sha2 enctype support
    
    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

 src/include/krb5/krb5.hin              |   20 ++-
 src/lib/crypto/crypto_tests/t_derive.c |    2 +-
 src/lib/crypto/krb/Makefile.in         |    9 +
 src/lib/crypto/krb/checksum_dk_cmac.c  |    3 +-
 src/lib/crypto/krb/checksum_dk_hmac.c  |    2 +-
 src/lib/crypto/krb/checksum_etm.c      |   65 ++++++++
 src/lib/crypto/krb/cksumtypes.c        |   12 ++
 src/lib/crypto/krb/combine_keys.c      |    5 +-
 src/lib/crypto/krb/crypto_int.h        |   31 ++++-
 src/lib/crypto/krb/derive.c            |   74 +++++++++-
 src/lib/crypto/krb/enc_dk_cmac.c       |    6 +-
 src/lib/crypto/krb/enc_dk_hmac.c       |    8 +-
 src/lib/crypto/krb/enc_etm.c           |  257 ++++++++++++++++++++++++++++++++
 src/lib/crypto/krb/etypes.c            |   21 +++
 src/lib/crypto/krb/prf_aes2.c          |   42 +++++
 src/lib/crypto/krb/prf_cmac.c          |    2 +-
 src/lib/crypto/krb/prf_dk.c            |    3 +-
 src/lib/crypto/krb/s2k_pbkdf2.c        |   16 ++-
 18 files changed, 548 insertions(+), 30 deletions(-)

diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 44c8bfa..64b0d0f 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -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*/
diff --git a/src/lib/crypto/crypto_tests/t_derive.c b/src/lib/crypto/crypto_tests/t_derive.c
index fe28751..f8c3291 100644
--- a/src/lib/crypto/crypto_tests/t_derive.c
+++ b/src/lib/crypto/crypto_tests/t_derive.c
@@ -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) {
diff --git a/src/lib/crypto/krb/Makefile.in b/src/lib/crypto/krb/Makefile.in
index 7b59839..c5660c5 100644
--- a/src/lib/crypto/krb/Makefile.in
+++ b/src/lib/crypto/krb/Makefile.in
@@ -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		\
diff --git a/src/lib/crypto/krb/checksum_dk_cmac.c b/src/lib/crypto/krb/checksum_dk_cmac.c
index 59d5c5a..809f9d7 100644
--- a/src/lib/crypto/krb/checksum_dk_cmac.c
+++ b/src/lib/crypto/krb/checksum_dk_cmac.c
@@ -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;
 
diff --git a/src/lib/crypto/krb/checksum_dk_hmac.c b/src/lib/crypto/krb/checksum_dk_hmac.c
index 517a5f3..64ab899 100644
--- a/src/lib/crypto/krb/checksum_dk_hmac.c
+++ b/src/lib/crypto/krb/checksum_dk_hmac.c
@@ -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
index 0000000..eaa85b2
--- /dev/null
+++ b/src/lib/crypto/krb/checksum_etm.c
@@ -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;
+}
diff --git a/src/lib/crypto/krb/cksumtypes.c b/src/lib/crypto/krb/cksumtypes.c
index a1ced98..85967f9 100644
--- a/src/lib/crypto/krb/cksumtypes.c
+++ b/src/lib/crypto/krb/cksumtypes.c
@@ -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 =
diff --git a/src/lib/crypto/krb/combine_keys.c b/src/lib/crypto/krb/combine_keys.c
index 9ab0ac4..90905c5 100644
--- a/src/lib/crypto/krb/combine_keys.c
+++ b/src/lib/crypto/krb/combine_keys.c
@@ -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;
diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
index fec0eab..d75b49c 100644
--- a/src/lib/crypto/krb/crypto_int.h
+++ b/src/lib/crypto/krb/crypto_int.h
@@ -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 ***/
 
diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c
index f15fec1..6707a73 100644
--- a/src/lib/crypto/krb/derive.c
+++ b/src/lib/crypto/krb/derive.c
@@ -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;
 
diff --git a/src/lib/crypto/krb/enc_dk_cmac.c b/src/lib/crypto/krb/enc_dk_cmac.c
index 9bb3dba..b65b9b7 100644
--- a/src/lib/crypto/krb/enc_dk_cmac.c
+++ b/src/lib/crypto/krb/enc_dk_cmac.c
@@ -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;
diff --git a/src/lib/crypto/krb/enc_dk_hmac.c b/src/lib/crypto/krb/enc_dk_hmac.c
index f16459e..713044c 100644
--- a/src/lib/crypto/krb/enc_dk_hmac.c
+++ b/src/lib/crypto/krb/enc_dk_hmac.c
@@ -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
index 0000000..3135dd5
--- /dev/null
+++ b/src/lib/crypto/krb/enc_etm.c
@@ -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;
+}
diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c
index 53be1d5..112ae08 100644
--- a/src/lib/crypto/krb/etypes.c
+++ b/src/lib/crypto/krb/etypes.c
@@ -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
index 0000000..9a5cffc
--- /dev/null
+++ b/src/lib/crypto/krb/prf_aes2.c
@@ -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);
+}
diff --git a/src/lib/crypto/krb/prf_cmac.c b/src/lib/crypto/krb/prf_cmac.c
index 131c36d..1d4cc4c 100644
--- a/src/lib/crypto/krb/prf_cmac.c
+++ b/src/lib/crypto/krb/prf_cmac.c
@@ -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;
diff --git a/src/lib/crypto/krb/prf_dk.c b/src/lib/crypto/krb/prf_dk.c
index bf8d522..544418b 100644
--- a/src/lib/crypto/krb/prf_dk.c
+++ b/src/lib/crypto/krb/prf_dk.c
@@ -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;
 
diff --git a/src/lib/crypto/krb/s2k_pbkdf2.c b/src/lib/crypto/krb/s2k_pbkdf2.c
index 316f59a..ec5856c 100644
--- a/src/lib/crypto/krb/s2k_pbkdf2.c
+++ b/src/lib/crypto/krb/s2k_pbkdf2.c
@@ -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);
+}


More information about the cvs-krb5 mailing list