Crypto IOV API per Projects/AEAD encryption API
authorSam Hartman <hartmans@mit.edu>
Tue, 2 Dec 2008 20:10:20 +0000 (20:10 +0000)
committerSam Hartman <hartmans@mit.edu>
Tue, 2 Dec 2008 20:10:20 +0000 (20:10 +0000)
Merge in the mskrb-crypto-iov branch at r21259 in order to move an
implementation of
http://k5wiki.kerberos.org/wiki/Projects/AEAD_encryption_API onto the
trunk.  This branch contains a subset of the commits on the
mskrb-integ branch that implement the krb5 library part of the crypto
IOV API.

ticket: new
Status: open

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@21263 dc483132-0cff-0310-8789-dd5450dbe970

35 files changed:
src/include/k5-int.h
src/include/krb5/krb5.hin
src/lib/crypto/Makefile.in
src/lib/crypto/aead.c [new file with mode: 0644]
src/lib/crypto/aead.h [new file with mode: 0644]
src/lib/crypto/arcfour/Makefile.in
src/lib/crypto/arcfour/arcfour-int.h
src/lib/crypto/arcfour/arcfour.c
src/lib/crypto/arcfour/arcfour.h
src/lib/crypto/arcfour/arcfour_aead.c [new file with mode: 0644]
src/lib/crypto/crypto_length.c [new file with mode: 0644]
src/lib/crypto/decrypt_iov.c [new file with mode: 0644]
src/lib/crypto/des/Makefile.in
src/lib/crypto/des/d3_aead.c [new file with mode: 0644]
src/lib/crypto/des/des_int.h
src/lib/crypto/dk/Makefile.in
src/lib/crypto/dk/checksum.c
src/lib/crypto/dk/dk.h
src/lib/crypto/dk/dk_aead.c [new file with mode: 0644]
src/lib/crypto/enc_provider/aes.c
src/lib/crypto/enc_provider/des3.c
src/lib/crypto/enc_provider/enc_provider.h
src/lib/crypto/enc_provider/rc4.c
src/lib/crypto/encrypt_iov.c [new file with mode: 0644]
src/lib/crypto/etypes.c
src/lib/crypto/hmac.c
src/lib/crypto/keyhash_provider/descbc.c
src/lib/crypto/keyhash_provider/hmac_md5.c
src/lib/crypto/keyhash_provider/k5_md4des.c
src/lib/crypto/keyhash_provider/k5_md5des.c
src/lib/crypto/libk5crypto.exports
src/lib/crypto/make_checksum_iov.c [new file with mode: 0644]
src/lib/crypto/t_encrypt.c
src/lib/crypto/verify_checksum_iov.c [new file with mode: 0644]
src/lib/krb5/os/accessor.c

index fe831b2504d1227cea1d0e482841a21a2f6de46b..1b4a60b4909bbe5c46dc8de9807b485d498b792d 100644 (file)
@@ -562,7 +562,19 @@ struct krb5_enc_provider {
   krb5_error_code (*init_state) (const krb5_keyblock *key,
                                 krb5_keyusage keyusage, krb5_data *out_state);
   krb5_error_code (*free_state) (krb5_data *state);
-  
+
+    /* In-place encryption/decryption of multiple buffers */
+    krb5_error_code (*encrypt_iov) (const krb5_keyblock *key,
+                                   const krb5_data *cipher_state,
+                                   krb5_crypto_iov *data,
+                                   size_t num_data);
+
+
+    krb5_error_code (*decrypt_iov) (const krb5_keyblock *key,
+                                   const krb5_data *cipher_state,
+                                   krb5_crypto_iov *data,
+                                   size_t num_data);
+
 };
 
 struct krb5_hash_provider {
@@ -588,6 +600,45 @@ struct krb5_keyhash_provider {
                               const krb5_data *input,
                               const krb5_data *hash,
                               krb5_boolean *valid);
+
+    krb5_error_code (*hash_iov) (const krb5_keyblock *key,
+                                krb5_keyusage keyusage,
+                                const krb5_data *ivec,
+                                const krb5_crypto_iov *data,
+                                size_t num_data,
+                                krb5_data *output);
+
+    krb5_error_code (*verify_iov) (const krb5_keyblock *key,
+                                 krb5_keyusage keyusage,
+                                 const krb5_data *ivec,
+                                 const krb5_data *input,
+                                 const krb5_crypto_iov *data,
+                                 size_t num_data,
+                                 krb5_boolean *valid);
+};
+
+struct krb5_aead_provider {
+    krb5_error_code (*crypto_length) (const struct krb5_aead_provider *aead,
+                                     const struct krb5_enc_provider *enc,
+                                     const struct krb5_hash_provider *hash,
+                                     krb5_cryptotype type,
+                                     size_t *length);
+    krb5_error_code (*encrypt_iov) (const struct krb5_aead_provider *aead,
+                                   const struct krb5_enc_provider *enc,
+                                   const struct krb5_hash_provider *hash,
+                                   const krb5_keyblock *key,
+                                   krb5_keyusage keyusage,
+                                   const krb5_data *ivec,
+                                   krb5_crypto_iov *data,
+                                   size_t num_data);
+    krb5_error_code (*decrypt_iov) (const struct krb5_aead_provider *aead,
+                                   const struct krb5_enc_provider *enc,
+                                   const struct krb5_hash_provider *hash,
+                                   const krb5_keyblock *key,
+                                   krb5_keyusage keyusage,
+                                   const krb5_data *ivec,
+                                   krb5_crypto_iov *data,
+                                   size_t num_data);
 };
 
 typedef void (*krb5_encrypt_length_func) (const struct krb5_enc_provider *enc,
@@ -615,13 +666,14 @@ struct krb5_keytypes {
     char *out_string;
     const struct krb5_enc_provider *enc;
     const struct krb5_hash_provider *hash;
-  size_t prf_length;
+    size_t prf_length;
     krb5_encrypt_length_func encrypt_len;
     krb5_crypt_func encrypt;
     krb5_crypt_func decrypt;
     krb5_str2key_func str2key;
-  krb5_prf_func prf;
+    krb5_prf_func prf;
     krb5_cksumtype required_ctype;
+    const struct krb5_aead_provider *aead;
 };
 
 struct krb5_cksumtypes {
@@ -665,6 +717,12 @@ krb5_error_code krb5_hmac
                const krb5_keyblock *key, unsigned int icount,
                const krb5_data *input, krb5_data *output);
 
+krb5_error_code krb5_hmac_iov
+(const struct krb5_hash_provider *hash,
+               const krb5_keyblock *key,
+               const krb5_crypto_iov *data, size_t num_data,
+               krb5_data *output);
+
 krb5_error_code krb5int_pbkdf2_hmac_sha1 (const krb5_data *, unsigned long,
                                          const krb5_data *,
                                          const krb5_data *);
@@ -1848,6 +1906,10 @@ typedef struct _krb5int_access {
                                   const krb5_keyblock *key,
                                   unsigned int icount, const krb5_data *input,
                                   krb5_data *output);
+    krb5_error_code (* krb5_hmac_iov) (const struct krb5_hash_provider *hash,
+                                      const krb5_keyblock *key,
+                                      const krb5_crypto_iov *data, size_t num_data,
+                                      krb5_data *output);
     /* service location and communication */
     krb5_error_code (*sendto_udp) (krb5_context, const krb5_data *msg,
                                   const struct addrlist *, struct sendto_callback_info*, krb5_data *reply,
index 62fd90df4e6356c84d3aab60f4ef0c8c05b2c30a..accde60fcaed4b51a0aedc1f5681b3c58d370c97 100644 (file)
@@ -195,6 +195,7 @@ typedef krb5_int32 krb5_enctype;
 typedef krb5_int32 krb5_cksumtype;
 typedef krb5_int32 krb5_authdatatype;
 typedef krb5_int32 krb5_keyusage;
+typedef krb5_int32 krb5_cryptotype;
 
 typedef krb5_int32     krb5_preauthtype; /* This may change, later on */
 typedef        krb5_int32      krb5_flags;
@@ -358,6 +359,11 @@ typedef struct _krb5_enc_data {
     krb5_data ciphertext;
 } krb5_enc_data;
 
+typedef struct _krb5_crypto_iov {
+    krb5_cryptotype flags;
+    krb5_data data;
+} krb5_crypto_iov;
+
 /* per Kerberos v5 protocol spec */
 #define        ENCTYPE_NULL            0x0000
 #define        ENCTYPE_DES_CBC_CRC     0x0001  /* DES cbc mode with CRC-32 */
@@ -606,6 +612,57 @@ krb5_boolean KRB5_CALLCONV krb5_c_is_coll_proof_cksum
 krb5_boolean KRB5_CALLCONV krb5_c_is_keyed_cksum
        (krb5_cksumtype ctype);
 
+/* AEAD APIs */
+#define KRB5_CRYPTO_TYPE_EMPTY     0   /* [in] ignored */
+#define KRB5_CRYPTO_TYPE_HEADER            1   /* [out] header */
+#define KRB5_CRYPTO_TYPE_DATA      2   /* [in, out] plaintext */
+#define KRB5_CRYPTO_TYPE_SIGN_ONLY  3  /* [in] associated data */
+#define KRB5_CRYPTO_TYPE_PADDING    4  /* [out] padding */
+#define KRB5_CRYPTO_TYPE_TRAILER    5  /* [out] checksum for encrypt */
+#define KRB5_CRYPTO_TYPE_CHECKSUM   6  /* [out] checksum for MIC */
+#define KRB5_CRYPTO_TYPE_STREAM            7   /* [in] entire message */
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_make_checksum_iov
+    (krb5_context context, krb5_cksumtype cksumtype,
+                   const krb5_keyblock *key, krb5_keyusage usage,
+                   krb5_crypto_iov *data, size_t num_data);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_verify_checksum_iov
+    (krb5_context context, 
+                   krb5_cksumtype cksumtype,
+                   const krb5_keyblock *key, krb5_keyusage usage,
+                   const krb5_crypto_iov *data, size_t num_data,
+                   krb5_boolean *valid);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_encrypt_iov
+    (krb5_context context, const krb5_keyblock *key,
+                   krb5_keyusage usage, const krb5_data *cipher_state,
+                   krb5_crypto_iov *data, size_t num_data);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_decrypt_iov
+    (krb5_context context, const krb5_keyblock *key,
+                   krb5_keyusage usage, const krb5_data *cipher_state,
+                   krb5_crypto_iov *data, size_t num_data);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_crypto_length
+    (krb5_context context, krb5_enctype enctype,
+                   krb5_cryptotype type, unsigned int *size);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_crypto_length_iov
+    (krb5_context context, krb5_enctype enctype,
+                   krb5_crypto_iov *data, size_t num_data);
+
+krb5_error_code KRB5_CALLCONV
+    krb5_c_padding_length
+    (krb5_context context, krb5_enctype enctype,
+                   size_t data_length, unsigned int *size);
+
 #ifdef KRB5_OLD_CRYPTO
 /*
  * old cryptosystem routine prototypes.  These are now layered
index 2a3015adc458157fe8d1abe2baa398b6efdd9f72..a4ab872b0cd81c709b20ffd6b1d6d09e764e6c72 100644 (file)
@@ -34,16 +34,20 @@ PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
 STLIBOBJS=\
+       aead.o                  \
        block_size.o            \
        checksum_length.o       \
        cksumtype_to_string.o   \
        cksumtypes.o            \
        coll_proof_cksum.o      \
        combine_keys.o  \
+       crypto_length.o         \
        crypto_libinit.o        \
        default_state.o \
        decrypt.o               \
+       decrypt_iov.o           \
        encrypt.o               \
+       encrypt_iov.o           \
        encrypt_length.o        \
        enctype_compare.o       \
        enctype_to_string.o     \
@@ -54,6 +58,7 @@ STLIBOBJS=\
        keyed_checksum_types.o  \
        keylengths.o            \
        make_checksum.o         \
+       make_checksum_iov.o     \
        make_random_key.o       \
        mandatory_sumtype.o     \
        nfold.o                 \
@@ -68,19 +73,24 @@ STLIBOBJS=\
        string_to_key.o         \
        valid_cksumtype.o       \
        valid_enctype.o         \
-       verify_checksum.o
+       verify_checksum.o       \
+       verify_checksum_iov.o
 
 OBJS=\
+       $(OUTPRE)aead.$(OBJEXT)                 \
        $(OUTPRE)block_size.$(OBJEXT)           \
        $(OUTPRE)checksum_length.$(OBJEXT)      \
        $(OUTPRE)cksumtype_to_string.$(OBJEXT)  \
        $(OUTPRE)cksumtypes.$(OBJEXT)           \
        $(OUTPRE)coll_proof_cksum.$(OBJEXT)     \
        $(OUTPRE)combine_keys.$(OBJEXT) \
+       $(OUTPRE)crypto_length.$(OBJEXT)        \
        $(OUTPRE)crypto_libinit.$(OBJEXT)       \
        $(OUTPRE)default_state.$(OBJEXT) \
        $(OUTPRE)decrypt.$(OBJEXT)              \
+       $(OUTPRE)decrypt_iov.$(OBJEXT)          \
        $(OUTPRE)encrypt.$(OBJEXT)              \
+       $(OUTPRE)encrypt_iov.$(OBJEXT)          \
        $(OUTPRE)encrypt_length.$(OBJEXT)       \
        $(OUTPRE)enctype_compare.$(OBJEXT)      \
        $(OUTPRE)enctype_to_string.$(OBJEXT)    \
@@ -91,6 +101,7 @@ OBJS=\
        $(OUTPRE)keyed_checksum_types.$(OBJEXT) \
        $(OUTPRE)keylengths.$(OBJEXT)   \
        $(OUTPRE)make_checksum.$(OBJEXT)        \
+       $(OUTPRE)make_checksum_iov.$(OBJEXT)    \
        $(OUTPRE)make_random_key.$(OBJEXT)      \
        $(OUTPRE)mandatory_sumtype.$(OBJEXT)    \
        $(OUTPRE)nfold.$(OBJEXT)                \
@@ -105,19 +116,24 @@ OBJS=\
        $(OUTPRE)string_to_key.$(OBJEXT)        \
        $(OUTPRE)valid_cksumtype.$(OBJEXT)      \
        $(OUTPRE)valid_enctype.$(OBJEXT)        \
-       $(OUTPRE)verify_checksum.$(OBJEXT)
+       $(OUTPRE)verify_checksum.$(OBJEXT)      \
+       $(OUTPRE)verify_checksum_iov.$(OBJEXT)
 
 SRCS=\
+       $(srcdir)/aead.c                \
        $(srcdir)/block_size.c          \
        $(srcdir)/checksum_length.c     \
        $(srcdir)/cksumtype_to_string.c \
        $(srcdir)/cksumtypes.c          \
        $(srcdir)/coll_proof_cksum.c    \
        $(srcdir)/combine_keys.c        \
+       $(srcdir)/crypto_length.c       \
        $(srcdir)/crypto_libinit.c      \
        $(srcdir)/default_state.c \
        $(srcdir)/decrypt.c             \
+       $(srcdir)/decrypt_iov.c         \
        $(srcdir)/encrypt.c             \
+       $(srcdir)/encrypt_iov.c         \
        $(srcdir)/encrypt_length.c      \
        $(srcdir)/enctype_compare.c     \
        $(srcdir)/enctype_to_string.c   \
@@ -128,6 +144,7 @@ SRCS=\
        $(srcdir)/keyed_checksum_types.c\
        $(srcdir)/keylengths.c          \
        $(srcdir)/make_checksum.c       \
+       $(srcdir)/make_checksum_iov.c   \
        $(srcdir)/make_random_key.c     \
        $(srcdir)/mandatory_sumtype.c   \
        $(srcdir)/nfold.c               \
@@ -142,7 +159,8 @@ SRCS=\
        $(srcdir)/string_to_key.c       \
        $(srcdir)/valid_cksumtype.c     \
        $(srcdir)/valid_enctype.c       \
-       $(srcdir)/verify_checksum.c
+       $(srcdir)/verify_checksum.c     \
+       $(srcdir)/verify_checksum_iov.c
 
 
 LIBBASE=k5crypto
@@ -368,6 +386,16 @@ check-windows::
 # Makefile dependencies follow.  This must be the last section in
 # the Makefile.in file
 #
+aead.so aead.po $(OUTPRE)aead.$(OBJEXT): \
+  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
+  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-gmt_mktime.h \
+  $(SRCTOP)/include/k5-int-pkinit.h $(SRCTOP)/include/k5-int.h \
+  $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \
+  $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/krb5.h \
+  $(SRCTOP)/include/krb5/locate_plugin.h $(SRCTOP)/include/krb5/preauth_plugin.h \
+  $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \
+  aead.c etypes.h aead.h
 block_size.so block_size.po $(OUTPRE)block_size.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
@@ -422,17 +450,6 @@ coll_proof_cksum.so coll_proof_cksum.po $(OUTPRE)coll_proof_cksum.$(OBJEXT): \
   $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
   $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
   $(SRCTOP)/include/socket-utils.h cksumtypes.h coll_proof_cksum.c
-combine_keys.so combine_keys.po $(OUTPRE)combine_keys.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
-  $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
-  $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
-  $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
-  $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \
-  $(SRCTOP)/include/krb5/preauth_plugin.h $(SRCTOP)/include/port-sockets.h \
-  $(SRCTOP)/include/socket-utils.h $(srcdir)/dk/dk.h \
-  combine_keys.c etypes.h
 crypto_libinit.so crypto_libinit.po $(OUTPRE)crypto_libinit.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
   $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
@@ -445,8 +462,6 @@ crypto_libinit.so crypto_libinit.po $(OUTPRE)crypto_libinit.$(OBJEXT): \
   $(SRCTOP)/include/socket-utils.h crypto_libinit.c
 default_state.so default_state.po $(OUTPRE)default_state.$(OBJEXT): \
   $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(SRCTOP)/include/k5-buf.h $(SRCTOP)/include/k5-err.h \
   $(SRCTOP)/include/k5-gmt_mktime.h $(SRCTOP)/include/k5-int-pkinit.h \
   $(SRCTOP)/include/k5-int.h $(SRCTOP)/include/k5-platform.h \
   $(SRCTOP)/include/k5-plugin.h $(SRCTOP)/include/k5-thread.h \
diff --git a/src/lib/crypto/aead.c b/src/lib/crypto/aead.c
new file mode 100644 (file)
index 0000000..6d042e6
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * lib/crypto/aead.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "cksumtypes.h"
+#include "dk.h"
+#include "aead.h"
+
+krb5_crypto_iov * KRB5_CALLCONV
+krb5int_c_locate_iov(krb5_crypto_iov *data,
+                    size_t num_data,
+                    krb5_cryptotype type)
+{
+    size_t i;
+    krb5_crypto_iov *iov = NULL;
+
+    if (data == NULL)
+       return NULL;
+
+    for (i = 0; i < num_data; i++) {
+       if (data[i].flags == type) {
+           if (iov == NULL)
+               iov = &data[i];
+           else
+               return NULL; /* can't appear twice */
+       }
+    }
+
+    return iov;
+}
+
+static krb5_error_code
+make_unkeyed_checksum_iov(const struct krb5_hash_provider *hash_provider,
+                         const krb5_crypto_iov *data,
+                         size_t num_data,
+                         krb5_data *output)
+{
+    krb5_data *sign_data;
+    size_t num_sign_data;
+    krb5_error_code ret;
+    size_t i, j;
+
+    /* Create a checksum over all the data to be signed */
+    for (i = 0, num_sign_data = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (SIGN_IOV(iov))
+           num_sign_data++;
+    }
+
+    /* XXX cleanup to avoid alloc */
+    sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
+    if (sign_data == NULL)
+       return ENOMEM;
+
+    for (i = 0, j = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (SIGN_IOV(iov))
+           sign_data[j++] = iov->data;
+    }
+
+    ret = hash_provider->hash(num_sign_data, sign_data, output);
+
+    free(sign_data);
+
+    return ret;
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum_type,
+                           const krb5_keyblock *key,
+                           krb5_keyusage usage,
+                           const krb5_crypto_iov *data,
+                           size_t num_data,
+                           krb5_data *cksum_data)
+{
+    int e1, e2;
+    krb5_error_code ret;
+
+    if (cksum_type->keyhash != NULL) {
+       /* check if key is compatible */
+
+       if (cksum_type->keyed_etype) {
+           for (e1=0; e1<krb5_enctypes_length; e1++) 
+               if (krb5_enctypes_list[e1].etype ==
+                   cksum_type->keyed_etype)
+                   break;
+
+           for (e2=0; e2<krb5_enctypes_length; e2++) 
+               if (krb5_enctypes_list[e2].etype == key->enctype)
+                   break;
+
+           if ((e1 == krb5_enctypes_length) ||
+               (e2 == krb5_enctypes_length) ||
+               (krb5_enctypes_list[e1].enc != krb5_enctypes_list[e2].enc)) {
+               ret = KRB5_BAD_ENCTYPE;
+               goto cleanup;
+           }
+       }
+
+       if (cksum_type->keyhash->hash_iov == NULL) {
+           return KRB5_BAD_ENCTYPE;
+       }
+
+       ret = (*(cksum_type->keyhash->hash_iov))(key, usage, 0,
+                                                data, num_data, cksum_data);
+    } else if (cksum_type->flags & KRB5_CKSUMFLAG_DERIVE) {
+       ret = krb5_dk_make_checksum_iov(cksum_type->hash,
+                                       key, usage, data, num_data,
+                                       cksum_data);
+    } else {
+       ret = make_unkeyed_checksum_iov(cksum_type->hash, data, num_data,
+                                       cksum_data);
+    }
+
+    if (ret == 0) {
+       if (cksum_type->trunc_size) {
+           cksum_data->length = cksum_type->trunc_size;
+       }
+    }
+
+cleanup:
+    if (ret != 0) {
+       memset(cksum_data->data, 0, cksum_data->length);
+    }
+
+    return ret;
+}
+
+const struct krb5_cksumtypes * KRB5_CALLCONV
+krb5int_c_find_checksum_type(krb5_cksumtype cksumtype)
+{
+    size_t i;
+
+    for (i = 0; i < krb5_cksumtypes_length; i++) {
+       if (krb5_cksumtypes_list[i].ctype == cksumtype)
+           break;
+    }
+
+    if (i == krb5_cksumtypes_length)
+       return NULL;
+
+    return &krb5_cksumtypes_list[i];
+}
+
+#ifdef DEBUG_IOV
+static void
+dump_block(const char *tag,
+          size_t i,
+          size_t j,
+          unsigned char *block,
+          size_t block_size)
+{
+    size_t k;
+
+    printf("[%s: %d.%d] ", tag, i, j);
+
+    for (k = 0; k < block_size; k++)
+       printf("%02x ", block[k] & 0xFF);
+
+    printf("\n");
+}
+#endif
+
+static int
+process_block_p(const krb5_crypto_iov *data,
+               size_t num_data,
+               struct iov_block_state *iov_state,
+               size_t i)
+{
+    const krb5_crypto_iov *iov = &data[i];
+    int process_block;
+
+    switch (iov->flags) {
+    case KRB5_CRYPTO_TYPE_SIGN_ONLY:
+       process_block = iov_state->include_sign_only;
+       break;
+    case KRB5_CRYPTO_TYPE_PADDING:
+       process_block = (iov_state->pad_to_boundary == 0);
+       break;
+    case KRB5_CRYPTO_TYPE_HEADER:
+       process_block = (iov_state->ignore_header == 0);
+       break;
+    case KRB5_CRYPTO_TYPE_DATA:
+       process_block = 1;
+       break;
+    default:
+       process_block = 0;
+       break;
+    }
+
+    return process_block;
+}
+
+/*
+ * Returns TRUE if, having reached the end of the current buffer,
+ * we should pad the rest of the block with zeros.
+ */
+static int
+pad_to_boundary_p(const krb5_crypto_iov *data,
+                 size_t num_data,
+                 struct iov_block_state *iov_state,
+                 size_t i,
+                 size_t j)
+{
+    /* If the pad_to_boundary flag is unset, return FALSE */
+    if (iov_state->pad_to_boundary == 0)
+       return 0;
+
+    /* If we haven't got any data, we need to get some */
+    if (j == 0)
+       return 0;
+
+    /* No boundary between adjacent buffers marked for processing */
+    if (data[iov_state->iov_pos].flags == data[i].flags)
+       return 0;
+
+    return 1;
+}
+
+krb5_boolean KRB5_CALLCONV
+krb5int_c_iov_get_block(unsigned char *block,
+                       size_t block_size,
+                       const krb5_crypto_iov *data,
+                       size_t num_data,
+                       struct iov_block_state *iov_state)
+{
+    size_t i, j = 0;
+
+    for (i = iov_state->iov_pos; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+       size_t nbytes;
+
+       if (!process_block_p(data, num_data, iov_state, i))
+           continue;
+
+       if (pad_to_boundary_p(data, num_data, iov_state, i, j))
+           break;
+
+       iov_state->iov_pos = i;
+
+       nbytes = iov->data.length - iov_state->data_pos;
+       if (nbytes > block_size - j)
+           nbytes = block_size - j;
+
+       memcpy(block + j, iov->data.data + iov_state->data_pos, nbytes);
+
+       iov_state->data_pos += nbytes;
+       j += nbytes;
+
+       assert(j <= block_size);
+
+       if (j == block_size)
+           break;
+
+       assert(iov_state->data_pos == iov->data.length);
+
+       iov_state->data_pos = 0;
+    }
+
+    iov_state->iov_pos = i;
+
+    if (j != block_size)
+       memset(block + j, 0, block_size - j);
+
+#ifdef DEBUG_IOV
+    if (iov_state->iov_pos < num_data)
+       dump_block("get_block", i, j, block, block_size);
+#endif
+
+    return (iov_state->iov_pos < num_data);
+}
+
+krb5_boolean KRB5_CALLCONV
+krb5int_c_iov_put_block(const krb5_crypto_iov *data,
+                       size_t num_data,
+                       unsigned char *block,
+                       size_t block_size,
+                       struct iov_block_state *iov_state)
+{
+    size_t i, j = 0;
+
+    for (i = iov_state->iov_pos; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+       size_t nbytes;
+
+       if (!process_block_p(data, num_data, iov_state, i))
+           continue;
+
+       if (pad_to_boundary_p(data, num_data, iov_state, i, j))
+           break;
+
+       iov_state->iov_pos = i;
+
+       nbytes = iov->data.length - iov_state->data_pos;
+       if (nbytes > block_size - j)
+           nbytes = block_size - j;
+
+       memcpy(iov->data.data + iov_state->data_pos, block + j, nbytes);
+
+       iov_state->data_pos += nbytes;
+       j += nbytes;
+
+       assert(j <= block_size);
+
+       if (j == block_size)
+           break;
+
+       assert(iov_state->data_pos == iov->data.length);
+
+       iov_state->data_pos = 0;
+    }
+
+    iov_state->iov_pos = i;
+
+#ifdef DEBUG_IOV
+    if (iov_state->iov_pos < num_data)
+       dump_block("put_block", i, j, block, block_size);
+#endif
+
+    return (iov_state->iov_pos < num_data);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5int_c_iov_decrypt_stream(const struct krb5_aead_provider *aead,
+                            const struct krb5_enc_provider *enc,
+                            const struct krb5_hash_provider *hash,
+                            const krb5_keyblock *key,
+                            krb5_keyusage keyusage,
+                            const krb5_data *ivec,
+                            krb5_crypto_iov *data,
+                            size_t num_data)
+{
+    krb5_error_code ret;
+    size_t header_len, trailer_len, padding_len;
+    krb5_crypto_iov *iov;
+    krb5_crypto_iov *stream;
+    size_t i, j;
+    int got_data = 0;
+
+    stream = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_STREAM);
+    assert(stream != NULL);
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_HEADER, &header_len);
+    if (ret != 0)
+       return ret;
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_TRAILER, &trailer_len);
+    if (ret != 0)
+       return ret;
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_PADDING, &padding_len);
+    if (ret != 0)
+       return ret;
+
+    if (stream->data.length < header_len + trailer_len)
+       return KRB5_BAD_MSIZE;
+
+    iov = (krb5_crypto_iov *)calloc(num_data + 2, sizeof(krb5_crypto_iov));
+    if (iov == NULL)
+       return ENOMEM;
+
+    i = 0;
+
+    iov[i].flags = KRB5_CRYPTO_TYPE_HEADER; /* takes place of STREAM */
+    iov[i].data.data = stream->data.data;
+    iov[i].data.length = header_len;
+    i++;
+    for (j = 0; j < num_data; j++) {
+       if (data[j].flags == KRB5_CRYPTO_TYPE_DATA) {
+           if (got_data) {
+               free(iov);
+               return KRB5_BAD_MSIZE;
+           }
+
+           got_data++;
+
+           data[j].data.data = stream->data.data + header_len;
+           data[j].data.length = stream->data.length - header_len - trailer_len;
+       }
+       if (data[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY ||
+           data[j].flags == KRB5_CRYPTO_TYPE_DATA)
+           iov[i++] = data[j];
+    }
+
+    /* XXX not self-describing with respect to length, this is the best we can do */
+    iov[i].flags = KRB5_CRYPTO_TYPE_PADDING;
+    iov[i].data.data = NULL;
+    iov[i].data.length = 0;
+    i++;
+
+    iov[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
+    iov[i].data.data = stream->data.data + stream->data.length - trailer_len;
+    iov[i].data.length = trailer_len;
+    i++;
+
+    assert(i <= num_data + 2);
+
+    ret = aead->decrypt_iov(aead, enc, hash, key, keyusage, ivec, iov, i);
+
+    free(iov);
+
+    return ret;
+}
+
diff --git a/src/lib/crypto/aead.h b/src/lib/crypto/aead.h
new file mode 100644 (file)
index 0000000..f183d1a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * lib/crypto/aead.h
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+
+/* AEAD helpers */
+
+krb5_crypto_iov * KRB5_CALLCONV
+krb5int_c_locate_iov(krb5_crypto_iov *data,
+                    size_t num_data,
+                    krb5_cryptotype type);
+
+krb5_error_code KRB5_CALLCONV
+krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum,
+                           const krb5_keyblock *key,
+                           krb5_keyusage usage,
+                           const krb5_crypto_iov *data,
+                           size_t num_data,
+                           krb5_data *cksum_data);
+
+const struct krb5_cksumtypes * KRB5_CALLCONV
+krb5int_c_find_checksum_type(krb5_cksumtype cksumtype);
+
+#define ENCRYPT_CONF_IOV(_iov) ((_iov)->flags == KRB5_CRYPTO_TYPE_HEADER)
+
+#define ENCRYPT_DATA_IOV(_iov) ((_iov)->flags == KRB5_CRYPTO_TYPE_DATA || \
+                                (_iov)->flags == KRB5_CRYPTO_TYPE_PADDING)
+
+#define ENCRYPT_IOV(_iov)      (ENCRYPT_CONF_IOV(_iov) || ENCRYPT_DATA_IOV(_iov))
+
+#define SIGN_IOV(_iov)         (ENCRYPT_IOV(_iov) || \
+                                (_iov)->flags == KRB5_CRYPTO_TYPE_SIGN_ONLY )
+
+struct iov_block_state {
+    size_t iov_pos;                    /* index into iov array */
+    size_t data_pos;                   /* index into iov contents */
+    unsigned int ignore_header : 1;    /* have/should we process HEADER */
+    unsigned int include_sign_only : 1;        /* should we process SIGN_ONLY blocks */
+    unsigned int pad_to_boundary : 1;  /* should we zero fill blocks until next buffer */
+};
+
+#define IOV_BLOCK_STATE_INIT(_state)   ((_state)->iov_pos = \
+                                        (_state)->data_pos = \
+                                        (_state)->ignore_header = \
+                                        (_state)->include_sign_only = \
+                                        (_state)->pad_to_boundary = 0)
+
+krb5_boolean KRB5_CALLCONV
+krb5int_c_iov_get_block(unsigned char *block,
+                       size_t block_size,
+                       const krb5_crypto_iov *data,
+                       size_t num_data,
+                       struct iov_block_state *iov_state);
+
+krb5_boolean KRB5_CALLCONV
+krb5int_c_iov_put_block(const krb5_crypto_iov *data,
+                       size_t num_data,
+                       unsigned char *block,
+                       size_t block_size,
+                       struct iov_block_state *iov_state);
+
+krb5_error_code KRB5_CALLCONV
+krb5int_c_iov_decrypt_stream(const struct krb5_aead_provider *aead,
+                            const struct krb5_enc_provider *enc,
+                            const struct krb5_hash_provider *hash,
+                            const krb5_keyblock *key,
+                            krb5_keyusage keyusage,
+                            const krb5_data *ivec,
+                            krb5_crypto_iov *data,
+                            size_t num_data);
+
index d03ca878a652657400602a1c80854ea42cfde291..ff5b51dcfb45502e6859801a903053eaae03cde0 100644 (file)
@@ -16,14 +16,17 @@ RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
 
 STLIBOBJS=\
        arcfour.o       \
+       arcfour_aead.o  \
        arcfour_s2k.o
 
 OBJS=\
        $(OUTPRE)arcfour.$(OBJEXT)      \
+       $(OUTPRE)arcfour_aead.$(OBJEXT) \
        $(OUTPRE)arcfour_s2k.$(OBJEXT)
 
 SRCS=\
        $(srcdir)/arcfour.c     \
+       $(srcdir)/arcfour_aead.c\
        $(srcdir)/arcfour_s2k.c
 
 ##DOS##LIBOBJS = $(OBJS)
index 398fe57a1d8068ed84ee06ccdb4abcf511539b01..efd7a0282917d1e1ffcfc4c3a16e187c5b43badf 100644 (file)
@@ -27,5 +27,6 @@ typedef struct {
 
 krb5_keyusage krb5int_arcfour_translate_usage(krb5_keyusage usage);
 
+extern const char *const krb5int_arcfour_l40;
 
 #endif /* ARCFOUR_INT_H */
index a2df5ddf5975694ec119f3f52660ebdc23b01b83..8c9e8e1a4e637a90e5cac6aec5a73e2daf95e58d 100644 (file)
@@ -8,7 +8,7 @@ of RSA Data Security)
 */
 #include "k5-int.h"
 #include "arcfour-int.h"
-static const char *const l40 = "fortybits";
+const char *const krb5int_arcfour_l40 = "fortybits";
 
 void
 krb5_arcfour_encrypt_length(const struct krb5_enc_provider *enc,
@@ -139,7 +139,7 @@ krb5_arcfour_encrypt(const struct krb5_enc_provider *enc,
   /* begin the encryption, computer K1 */
   ms_usage=krb5int_arcfour_translate_usage(usage);
   if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
-    strncpy(salt.data, l40, salt.length);
+    strncpy(salt.data, krb5int_arcfour_l40, salt.length);
     store_32_le(ms_usage, salt.data+10);
   } else {
     salt.length=4;
@@ -253,7 +253,7 @@ krb5_arcfour_decrypt(const struct krb5_enc_provider *enc,
   /* compute the salt */
   ms_usage=krb5int_arcfour_translate_usage(usage);
   if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
-    strncpy(salt.data, l40, salt.length);
+    strncpy(salt.data, krb5int_arcfour_l40, salt.length);
     salt.data[10]=ms_usage & 0xff;
     salt.data[11]=(ms_usage>>8) & 0xff;
     salt.data[12]=(ms_usage>>16) & 0xff;
index c6e43533486937bf4b4ba2f340927e4da711845f..e8ff203ca168d7507dda13d79ad9f35abe386031 100644 (file)
@@ -33,4 +33,6 @@ extern krb5_error_code krb5int_arcfour_string_to_key(
      krb5_keyblock *);
 
 extern const struct krb5_enc_provider krb5int_enc_arcfour;
+extern const struct krb5_aead_provider krb5int_aead_arcfour;
+
 #endif /* ARCFOUR_H */
diff --git a/src/lib/crypto/arcfour/arcfour_aead.c b/src/lib/crypto/arcfour/arcfour_aead.c
new file mode 100644 (file)
index 0000000..40151d9
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * lib/crypto/arcfour/arcfour_aead.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#include "k5-int.h"
+#include "arcfour.h"
+#include "arcfour-int.h"
+#include "aead.h"
+
+/* AEAD */
+
+static krb5_error_code
+krb5int_arcfour_crypto_length(const struct krb5_aead_provider *aead,
+                             const struct krb5_enc_provider *enc,
+                             const struct krb5_hash_provider *hash,
+                             krb5_cryptotype type,
+                             size_t *length)
+{
+    switch (type) {
+    case KRB5_CRYPTO_TYPE_HEADER:
+       *length = hash->hashsize + CONFOUNDERLENGTH;
+       break;
+    case KRB5_CRYPTO_TYPE_PADDING:
+       *length = 0;
+       break;
+    case KRB5_CRYPTO_TYPE_TRAILER:
+       *length = 0;
+       break;
+    case KRB5_CRYPTO_TYPE_CHECKSUM:
+       *length = hash->hashsize;
+       break;
+    default:
+       assert(0 && "invalid cryptotype passed to krb5int_arcfour_crypto_length");
+       break;
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+alloc_derived_key(const struct krb5_enc_provider *enc,
+                 krb5_keyblock *dst,
+                 krb5_data *data,
+                 const krb5_keyblock *src)
+{
+    data->length = enc->keybytes;
+    data->data = malloc(data->length);
+    if (data->data == NULL)
+       return ENOMEM;
+
+    *dst = *src;
+    dst->length = data->length;
+    dst->contents = (void *)data->data;
+
+    return 0;
+}
+
+static krb5_error_code
+krb5int_arcfour_encrypt_iov(const struct krb5_aead_provider *aead,
+                           const struct krb5_enc_provider *enc,
+                           const struct krb5_hash_provider *hash,
+                           const krb5_keyblock *key,
+                           krb5_keyusage usage,
+                           const krb5_data *ivec,
+                           krb5_crypto_iov *data,
+                           size_t num_data)
+{
+    krb5_error_code ret;
+    krb5_crypto_iov *header, *trailer;
+    krb5_keyblock k1, k2, k3;
+    krb5_data d1, d2, d3;
+    krb5_data checksum, confounder, header_data;
+    krb5_keyusage ms_usage;
+    char salt_data[14];
+    krb5_data salt;
+    size_t i;
+
+    d1.length = d2.length = d3.length = 0;
+    d1.data = d2.data = d3.data = NULL;
+
+    /*
+     * Caller must have provided space for the header, padding
+     * and trailer; per RFC 4757 we will arrange it as:
+     *
+     *     Checksum | E(Confounder | Plaintext) 
+     */
+
+    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
+    if (header == NULL ||
+       header->data.length < hash->hashsize + CONFOUNDERLENGTH)
+       return KRB5_BAD_MSIZE;
+
+    header_data = header->data;
+
+    /* Trailer may be absent */
+    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
+    if (trailer != NULL)
+       trailer->data.length = 0;
+
+    /* Ensure that there is no padding */
+    for (i = 0; i < num_data; i++) {
+       if (data[i].flags == KRB5_CRYPTO_TYPE_PADDING)
+           data[i].data.length = 0;
+    }
+
+    ret = alloc_derived_key(enc, &k1, &d1, key);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = alloc_derived_key(enc, &k2, &d2, key);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = alloc_derived_key(enc, &k3, &d3, key);
+    if (ret != 0)
+       goto cleanup;
+
+    /* Begin the encryption, compute K1 */
+    salt.data = salt_data;
+    salt.length = sizeof(salt_data);
+
+    ms_usage = krb5int_arcfour_translate_usage(usage);
+
+    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+       strncpy(salt.data, krb5int_arcfour_l40, salt.length);
+       store_32_le(ms_usage, (unsigned char *)salt.data + 10);
+    } else {
+       salt.length = 4;
+       store_32_le(ms_usage, (unsigned char *)salt.data);
+    }
+    ret = krb5_hmac(hash, key, 1, &salt, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    memcpy(k2.contents, k1.contents, k2.length);
+
+    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+       memset(k1.contents + 7, 0xAB, 9);
+
+    header->data.length = hash->hashsize + CONFOUNDERLENGTH;
+
+    confounder.data = header->data.data + hash->hashsize;
+    confounder.length = CONFOUNDERLENGTH;
+
+    ret = krb5_c_random_make_octets(0, &confounder);
+    if (ret != 0)
+       goto cleanup;
+
+    checksum.data = header->data.data;
+    checksum.length = hash->hashsize;
+
+    /* Adjust pointers so confounder is at start of header */
+    header->data.length -= hash->hashsize;
+    header->data.data   += hash->hashsize;
+
+    ret = krb5_hmac_iov(hash, &k2, data, num_data, &checksum);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = enc->encrypt_iov(&k3, ivec, data, num_data);
+    if (ret != 0)
+       goto cleanup;
+
+cleanup:
+    header->data = header_data; /* restore header pointers */
+
+    if (d1.data != NULL) {
+       memset(d1.data, 0, d1.length);
+       free(d1.data);
+    }
+    if (d2.data != NULL) {
+       memset(d2.data, 0, d2.length);
+       free(d2.data);
+    }
+    if (d3.data != NULL) {
+       memset(d3.data, 0, d3.length);
+       free(d3.data);
+    }
+
+    return ret;
+}
+
+static krb5_error_code
+krb5int_arcfour_decrypt_iov(const struct krb5_aead_provider *aead,
+                           const struct krb5_enc_provider *enc,
+                           const struct krb5_hash_provider *hash,
+                           const krb5_keyblock *key,
+                           krb5_keyusage usage,
+                           const krb5_data *ivec,
+                           krb5_crypto_iov *data,
+                           size_t num_data)
+{
+    krb5_error_code ret;
+    krb5_crypto_iov *header, *trailer;
+    krb5_keyblock k1, k2, k3;
+    krb5_data d1, d2, d3;
+    krb5_data checksum, header_data;
+    krb5_keyusage ms_usage;
+    char salt_data[14];
+    krb5_data salt;
+
+    d1.length = d2.length = d3.length = 0;
+    d1.data = d2.data = d3.data = NULL;
+
+    header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
+    if (header == NULL ||
+        header->data.length != hash->hashsize + CONFOUNDERLENGTH)
+       return KRB5_BAD_MSIZE;
+
+    header_data = header->data;
+
+    trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
+    if (trailer != NULL && trailer->data.length != 0)
+       return KRB5_BAD_MSIZE;
+    
+    ret = alloc_derived_key(enc, &k1, &d1, key);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = alloc_derived_key(enc, &k2, &d2, key);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = alloc_derived_key(enc, &k3, &d3, key);
+    if (ret != 0)
+       goto cleanup;
+
+    /* Begin the decryption, compute K1 */
+    salt.data = salt_data;
+    salt.length = sizeof(salt_data);
+
+    ms_usage = krb5int_arcfour_translate_usage(usage);
+
+    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP) {
+       strncpy(salt.data, krb5int_arcfour_l40, salt.length);
+       store_32_le(ms_usage, (unsigned char *)salt.data + 10);
+    } else {
+       salt.length = 4;
+       store_32_le(ms_usage, (unsigned char *)salt.data);
+    }
+    ret = krb5_hmac(hash, key, 1, &salt, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    memcpy(k2.contents, k1.contents, k2.length);
+
+    if (key->enctype == ENCTYPE_ARCFOUR_HMAC_EXP)
+       memset(k1.contents + 7, 0xAB, 9);
+
+    checksum.data = header->data.data;
+    checksum.length = hash->hashsize;
+
+    /* Adjust pointers so confounder is at start of header */
+    header->data.length -= hash->hashsize;
+    header->data.data   += hash->hashsize;
+
+    ret = krb5_hmac(hash, &k1, 1, &checksum, &d3);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = enc->decrypt_iov(&k3, ivec, data, num_data);
+    if (ret != 0)
+       goto cleanup;
+
+    ret = krb5_hmac_iov(hash, &k2, data, num_data, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    if (memcmp(checksum.data, d1.data, hash->hashsize) != 0) {
+       ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+       goto cleanup;
+    }
+
+cleanup:
+    header->data = header_data; /* restore header pointers */
+
+    if (d1.data != NULL) {
+       memset(d1.data, 0, d1.length);
+       free(d1.data);
+    }
+    if (d2.data != NULL) {
+       memset(d2.data, 0, d2.length);
+       free(d2.data);
+    }
+    if (d3.data != NULL) {
+       memset(d3.data, 0, d3.length);
+       free(d3.data);
+    }
+
+    return ret;
+}
+
+const struct krb5_aead_provider krb5int_aead_arcfour = {
+    krb5int_arcfour_crypto_length,
+    krb5int_arcfour_encrypt_iov,
+    krb5int_arcfour_decrypt_iov
+};
+
diff --git a/src/lib/crypto/crypto_length.c b/src/lib/crypto/crypto_length.c
new file mode 100644 (file)
index 0000000..4a64b90
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * lib/crypto/crypto_length.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "aead.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_crypto_length(krb5_context context,
+                    krb5_enctype enctype,
+                    krb5_cryptotype type,
+                    unsigned int *size)
+{
+    int i;
+    const struct krb5_keytypes *ktp = NULL;
+    krb5_error_code ret;
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == enctype) {
+           ktp = &krb5_enctypes_list[i];
+           break;
+       }
+    }
+
+    if (ktp == NULL || ktp->aead == NULL) {
+       return KRB5_BAD_ENCTYPE;
+    }
+
+    switch (type) {
+    case KRB5_CRYPTO_TYPE_EMPTY:
+    case KRB5_CRYPTO_TYPE_SIGN_ONLY:
+       *size = 0;
+       ret = 0;
+       break;
+    case KRB5_CRYPTO_TYPE_DATA:
+       *size = (size_t)~0; /* match Heimdal */
+       ret = 0;
+       break;
+    case KRB5_CRYPTO_TYPE_HEADER:
+    case KRB5_CRYPTO_TYPE_PADDING:
+    case KRB5_CRYPTO_TYPE_TRAILER:
+    case KRB5_CRYPTO_TYPE_CHECKSUM:
+       ret = ktp->aead->crypto_length(ktp->aead, ktp->enc, ktp->hash, type, size);
+       break;
+    default:
+       ret = EINVAL;
+       break;
+    }
+
+    return ret;
+}
+
+static krb5_error_code
+k5_padding_length(const struct krb5_keytypes *ktp,
+                 size_t data_length,
+                 unsigned int *pad_length)
+{
+    unsigned int padding;
+    krb5_error_code ret;
+
+    ret = ktp->aead->crypto_length(ktp->aead, ktp->enc, ktp->hash,
+                                  KRB5_CRYPTO_TYPE_PADDING, &padding);
+    if (ret != 0)
+       return ret;
+
+    if (padding == 0 || (data_length % padding) == 0)
+       *pad_length = 0;
+    else
+       *pad_length = padding - (data_length % padding);
+
+    return 0;
+}
+
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_padding_length(krb5_context context,
+                     krb5_enctype enctype,
+                     size_t data_length,
+                     unsigned int *pad_length)
+{
+    int i;
+    const struct krb5_keytypes *ktp = NULL;
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == enctype) {
+           ktp = &krb5_enctypes_list[i];
+           break;
+       }
+    }
+
+    if (ktp == NULL || ktp->aead == NULL) {
+       return KRB5_BAD_ENCTYPE;
+    }
+
+    return k5_padding_length(ktp, data_length, pad_length);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_crypto_length_iov(krb5_context context,
+                        krb5_enctype enctype,
+                        krb5_crypto_iov *data,
+                        size_t num_data)
+{
+    krb5_error_code ret = 0;
+    size_t i;
+    const struct krb5_keytypes *ktp = NULL;
+    size_t data_length = 0, pad_length;
+    krb5_crypto_iov *padding = NULL;
+
+    /*
+     * XXX need to rejig internal interface so we can accurately
+     * report variable header lengths
+     */
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == enctype) {
+           ktp = &krb5_enctypes_list[i];
+           break;
+       }
+    }
+
+    if (ktp == NULL || ktp->aead == NULL) {
+       return KRB5_BAD_ENCTYPE;
+    }
+
+    for (i = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       switch (iov->flags) {
+       case KRB5_CRYPTO_TYPE_DATA:
+           data_length += iov->data.length;
+           break;
+       case KRB5_CRYPTO_TYPE_PADDING:
+           if (padding != NULL)
+               return EINVAL;
+
+           padding = iov;
+           break;
+       case KRB5_CRYPTO_TYPE_HEADER:
+       case KRB5_CRYPTO_TYPE_TRAILER:
+       case KRB5_CRYPTO_TYPE_CHECKSUM:
+           ret = ktp->aead->crypto_length(ktp->aead, ktp->enc, ktp->hash, iov->flags, &iov->data.length);
+           break;
+       case KRB5_CRYPTO_TYPE_EMPTY:
+       case KRB5_CRYPTO_TYPE_SIGN_ONLY:
+       default:
+           break;
+       }
+
+       if (ret != 0)
+           break;
+    }
+
+    if (ret != 0)
+       return ret;
+
+    ret = k5_padding_length(ktp, data_length, &pad_length);
+    if (ret != 0)
+       return ret;
+
+    if (pad_length != 0 && padding == NULL)
+       return EINVAL;
+
+    if (padding != NULL)
+       padding->data.length = pad_length;
+
+    return 0;
+}
+
diff --git a/src/lib/crypto/decrypt_iov.c b/src/lib/crypto/decrypt_iov.c
new file mode 100644 (file)
index 0000000..1a98b06
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * lib/crypto/encrypt_iov.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+#include "aead.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_decrypt_iov(krb5_context context,
+                  const krb5_keyblock *key,
+                  krb5_keyusage usage,
+                  const krb5_data *cipher_state,
+                  krb5_crypto_iov *data,
+                  size_t num_data)
+{
+    int i;
+    const struct krb5_keytypes *ktp = NULL;
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == key->enctype) {
+           ktp = &krb5_enctypes_list[i];
+           break;
+       }
+    }
+
+    if (ktp == NULL || ktp->aead == NULL) {
+       return KRB5_BAD_ENCTYPE;
+    }
+
+    if (krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_STREAM) != NULL) {
+       return krb5int_c_iov_decrypt_stream(ktp->aead, ktp->enc, ktp->hash,
+                                           key, usage, cipher_state, data, num_data);
+    }
+
+    return ktp->aead->decrypt_iov(ktp->aead, ktp->enc, ktp->hash,
+                                 key, usage, cipher_state, data, num_data);
+}
+
index 10660bbf40b012413dca4f0a32c6447da6be7532..6c5fc89ae145c83b87517e264448bf741a0701fe 100644 (file)
@@ -16,6 +16,7 @@ RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
 STLIBOBJS=\
        afsstring2key.o \
        d3_cbc.o        \
+       d3_aead.o       \
        d3_kysched.o    \
        f_cbc.o         \
        f_cksum.o       \
@@ -28,6 +29,7 @@ STLIBOBJS=\
 
 OBJS=  $(OUTPRE)afsstring2key.$(OBJEXT)        \
        $(OUTPRE)d3_cbc.$(OBJEXT)       \
+       $(OUTPRE)d3_aead.$(OBJEXT)      \
        $(OUTPRE)d3_kysched.$(OBJEXT)   \
        $(OUTPRE)f_cbc.$(OBJEXT)        \
        $(OUTPRE)f_cksum.$(OBJEXT)      \
@@ -40,6 +42,7 @@ OBJS= $(OUTPRE)afsstring2key.$(OBJEXT)        \
 
 SRCS=  $(srcdir)/afsstring2key.c       \
        $(srcdir)/d3_cbc.c      \
+       $(srcdir)/d3_aead.c     \
        $(srcdir)/d3_kysched.c  \
        $(srcdir)/f_cbc.c       \
        $(srcdir)/f_cksum.c     \
diff --git a/src/lib/crypto/des/d3_aead.c b/src/lib/crypto/des/d3_aead.c
new file mode 100644 (file)
index 0000000..8463fc8
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 by the Massachusetts Institute of Technology.
+ * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
+ * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  Richard P. Basch,
+ * Lehman Brothers and M.I.T. make no representations about the suitability
+ * of this software for any purpose.  It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include "des_int.h"
+#include "f_tables.h"
+#include "../aead.h"
+
+void
+krb5int_des3_cbc_encrypt_iov(krb5_crypto_iov *data,
+                            unsigned long num_data,
+                            const mit_des_key_schedule ks1,
+                            const mit_des_key_schedule ks2,
+                            const mit_des_key_schedule ks3,
+                            mit_des_cblock ivec)
+{
+    unsigned DES_INT32 left, right;
+    const unsigned DES_INT32 *kp1, *kp2, *kp3;
+    const unsigned char *ip;
+    unsigned char *op;
+    struct iov_block_state input_pos, output_pos;
+    unsigned char iblock[MIT_DES_BLOCK_LENGTH];
+    unsigned char oblock[MIT_DES_BLOCK_LENGTH];
+
+    IOV_BLOCK_STATE_INIT(&input_pos);
+    IOV_BLOCK_STATE_INIT(&output_pos);
+
+    /*
+     * Get key pointer here.  This won't need to be reinitialized
+     */
+    kp1 = (const unsigned DES_INT32 *)ks1;
+    kp2 = (const unsigned DES_INT32 *)ks2;
+    kp3 = (const unsigned DES_INT32 *)ks3;
+
+    /*
+     * Initialize left and right with the contents of the initial
+     * vector.
+     */
+    if (ivec != NULL)
+       ip = ivec;
+    else
+       ip = mit_des_zeroblock;
+    GET_HALF_BLOCK(left, ip);
+    GET_HALF_BLOCK(right, ip);
+
+    /*
+     * Suitably initialized, now work the length down 8 bytes
+     * at a time.
+     */
+    for (;;) {
+       unsigned DES_INT32 temp;
+
+       ip = iblock;
+       op = oblock;
+
+       if (!krb5int_c_iov_get_block(iblock, MIT_DES_BLOCK_LENGTH, data, num_data, &input_pos))
+           break;
+
+       GET_HALF_BLOCK(temp, ip);
+       left  ^= temp;
+       GET_HALF_BLOCK(temp, ip);
+       right ^= temp;
+
+       /*
+        * Encrypt what we have
+        */
+       DES_DO_ENCRYPT(left, right, kp1);
+       DES_DO_DECRYPT(left, right, kp2);
+       DES_DO_ENCRYPT(left, right, kp3);
+
+       /*
+        * Copy the results out
+        */
+       PUT_HALF_BLOCK(left, op);
+       PUT_HALF_BLOCK(right, op);
+
+       krb5int_c_iov_put_block(data, num_data, oblock, MIT_DES_BLOCK_LENGTH, &output_pos);
+    }
+
+    if (ivec != NULL)
+       memcpy(ivec, oblock, MIT_DES_BLOCK_LENGTH);
+}
+
+void
+krb5int_des3_cbc_decrypt_iov(krb5_crypto_iov *data,
+                            unsigned long num_data,
+                            const mit_des_key_schedule ks1,
+                            const mit_des_key_schedule ks2,
+                            const mit_des_key_schedule ks3,
+                            mit_des_cblock ivec)
+{
+    unsigned DES_INT32 left, right;
+    const unsigned DES_INT32 *kp1, *kp2, *kp3;
+    const unsigned char *ip;
+    unsigned DES_INT32 ocipherl, ocipherr;
+    unsigned DES_INT32 cipherl, cipherr;
+    unsigned char *op;
+    struct iov_block_state input_pos, output_pos;
+    unsigned char iblock[MIT_DES_BLOCK_LENGTH];
+    unsigned char oblock[MIT_DES_BLOCK_LENGTH];
+
+    IOV_BLOCK_STATE_INIT(&input_pos);
+    IOV_BLOCK_STATE_INIT(&output_pos);
+
+    /*
+     * Get key pointer here.  This won't need to be reinitialized
+     */
+    kp1 = (const unsigned DES_INT32 *)ks1;
+    kp2 = (const unsigned DES_INT32 *)ks2;
+    kp3 = (const unsigned DES_INT32 *)ks3;
+
+    /*
+     * Decrypting is harder than encrypting because of
+     * the necessity of remembering a lot more things.
+     * Should think about this a little more...
+     */
+
+    if (num_data == 0)
+       return;
+
+    /*
+     * Prime the old cipher with ivec.
+     */
+    if (ivec != NULL)
+       ip = ivec;
+    else
+       ip = mit_des_zeroblock;
+    GET_HALF_BLOCK(ocipherl, ip);
+    GET_HALF_BLOCK(ocipherr, ip);
+
+    /*
+     * Now do this in earnest until we run out of length.
+     */
+    for (;;) {
+       /*
+        * Read a block from the input into left and
+        * right.  Save this cipher block for later.
+        */
+
+       if (!krb5int_c_iov_get_block(iblock, MIT_DES_BLOCK_LENGTH, data, num_data, &input_pos))
+           break;
+
+       ip = iblock;
+       op = oblock;
+
+       GET_HALF_BLOCK(left, ip);
+       GET_HALF_BLOCK(right, ip);
+       cipherl = left;
+       cipherr = right;
+
+       /*
+        * Decrypt this.
+        */
+       DES_DO_DECRYPT(left, right, kp3);
+       DES_DO_ENCRYPT(left, right, kp2);
+       DES_DO_DECRYPT(left, right, kp1);
+
+       /*
+        * Xor with the old cipher to get plain
+        * text.  Output 8 or less bytes of this.
+        */
+       left ^= ocipherl;
+       right ^= ocipherr;
+
+       PUT_HALF_BLOCK(left, op);
+       PUT_HALF_BLOCK(right, op);
+
+       /*
+        * Save current cipher block here
+        */
+       ocipherl = cipherl;
+       ocipherr = cipherr;
+
+       krb5int_c_iov_put_block(data, num_data, oblock, MIT_DES_BLOCK_LENGTH, &output_pos);
+    }
+
+    if (ivec != NULL)
+       memcpy(ivec, oblock, MIT_DES_BLOCK_LENGTH);
+}
index c330a935adff4743103dd58a463a31c13b927e16..f040564499bf1d072503744cf7f4df05561860e8 100644 (file)
@@ -240,6 +240,21 @@ krb5int_des3_cbc_decrypt(const mit_des_cblock *in,
                         const mit_des_key_schedule ks3,
                         const mit_des_cblock ivec);
 
+void
+krb5int_des3_cbc_encrypt_iov(krb5_crypto_iov *data,
+                            unsigned long num_data,
+                            const mit_des_key_schedule ks1,
+                            const mit_des_key_schedule ks2,
+                            const mit_des_key_schedule ks3,
+                            mit_des_cblock ivec);
+
+void
+krb5int_des3_cbc_decrypt_iov(krb5_crypto_iov *data,
+                            unsigned long num_data,
+                            const mit_des_key_schedule ks1,
+                            const mit_des_key_schedule ks2,
+                            const mit_des_key_schedule ks3,
+                            mit_des_cblock ivec);
 
 #define mit_des3_cbc_encrypt(in,out,length,ks1,ks2,ks3,ivec,enc) \
     ((enc ? krb5int_des3_cbc_encrypt : krb5int_des3_cbc_decrypt) \
index 08393ba4a59c48a7766b53260baf7299e0360df0..f8bfef139acbf7699bfb9deb8b4ac7f7c4267d85 100644 (file)
@@ -16,6 +16,7 @@ RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(SRCTOP)/config-files/krb5.conf
 
 STLIBOBJS=\
        checksum.o      \
+       dk_aead.o       \
        dk_decrypt.o    \
        dk_encrypt.o    \
        derive.o        \
@@ -24,6 +25,7 @@ STLIBOBJS=\
 
 OBJS=\
        $(OUTPRE)checksum.$(OBJEXT)     \
+       $(OUTPRE)dk_aead.$(OBJEXT)      \
        $(OUTPRE)dk_decrypt.$(OBJEXT)   \
        $(OUTPRE)dk_encrypt.$(OBJEXT)   \
        $(OUTPRE)derive.$(OBJEXT)       \
@@ -32,6 +34,7 @@ OBJS=\
 
 SRCS=\
        $(srcdir)/checksum.c    \
+       $(srcdir)/dk_aead.c     \
        $(srcdir)/dk_decrypt.c  \
        $(srcdir)/dk_encrypt.c  \
        $(srcdir)/dk_prf.c \
index 2f30cb740d9957c4e678e4f02baefc06b0d9c578..a0ec05c5d5eabc963c98281d8e1233db0f796cdb 100644 (file)
@@ -27,6 +27,7 @@
 #include "k5-int.h"
 #include "etypes.h"
 #include "dk.h"
+#include "aead.h"
 
 #define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
 
@@ -101,3 +102,73 @@ cleanup:
     return(ret);
 }
 
+krb5_error_code
+krb5_dk_make_checksum_iov(const struct krb5_hash_provider *hash,
+                         const krb5_keyblock *key, krb5_keyusage usage,
+                         const krb5_crypto_iov *data, size_t num_data,
+                         krb5_data *output)
+{
+    int i;
+    const struct krb5_enc_provider *enc;
+    size_t blocksize, keybytes, keylength;
+    krb5_error_code ret;
+    unsigned char constantdata[K5CLENGTH];
+    krb5_data datain;
+    unsigned char *kcdata;
+    krb5_keyblock kc;
+
+    for (i=0; i<krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == key->enctype)
+           break;
+    }
+
+    if (i == krb5_enctypes_length)
+       return(KRB5_BAD_ENCTYPE);
+
+    enc = krb5_enctypes_list[i].enc;
+
+    /* allocate and set to-be-derived keys */
+
+    blocksize = enc->block_size;
+    keybytes = enc->keybytes;
+    keylength = enc->keylength;
+
+    /* key->length will be tested in enc->encrypt
+       output->length will be tested in krb5_hmac */
+
+    if ((kcdata = (unsigned char *) malloc(keylength)) == NULL)
+       return(ENOMEM);
+
+    kc.contents = kcdata;
+    kc.length = keylength;
+
+    /* derive the key */
+    datain.data = (char *) constantdata;
+    datain.length = K5CLENGTH;
+
+    datain.data[0] = (usage>>24)&0xff;
+    datain.data[1] = (usage>>16)&0xff;
+    datain.data[2] = (usage>>8)&0xff;
+    datain.data[3] = usage&0xff;
+
+    datain.data[4] = (char) 0x99;
+
+    if ((ret = krb5_derive_key(enc, key, &kc, &datain)) != 0)
+       goto cleanup;
+
+    /* hash the data */
+
+    if ((ret = krb5_hmac_iov(hash, &kc, data, num_data, output)) != 0)
+       memset(output->data, 0, output->length);
+
+    /* ret is set correctly by the prior call */
+
+cleanup:
+    memset(kcdata, 0, keylength);
+
+    free(kcdata);
+
+    return(ret);
+}
+
index 47bda6ebf2a8a7ebe984018b926657c74cea55e6..a8def7a93d2d62a1b1319f27aef75ffad0808de9 100644 (file)
@@ -84,7 +84,19 @@ krb5_error_code krb5_dk_make_checksum
                const krb5_keyblock *key, krb5_keyusage usage,
                const krb5_data *input, krb5_data *output);
 
+krb5_error_code
+krb5_dk_make_checksum_iov(const struct krb5_hash_provider *hash,
+                         const krb5_keyblock *key, krb5_keyusage usage,
+                         const krb5_crypto_iov *data, size_t num_data,
+                         krb5_data *output);
+
 krb5_error_code
 krb5_derive_random(const struct krb5_enc_provider *enc,
                   const krb5_keyblock *inkey, krb5_data *outrnd,
                   const krb5_data *in_constant);
+
+/* AEAD */
+
+extern const struct krb5_aead_provider krb5int_aead_dk;
+extern const struct krb5_aead_provider krb5int_aead_aes;
+
diff --git a/src/lib/crypto/dk/dk_aead.c b/src/lib/crypto/dk/dk_aead.c
new file mode 100644 (file)
index 0000000..839b133
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * lib/crypto/dk/dk_aead.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+
+#include "k5-int.h"
+#include "dk.h"
+#include "aead.h"
+
+#define K5CLENGTH 5 /* 32 bit net byte order integer + one byte seed */
+
+/* AEAD */
+
+static krb5_error_code
+krb5int_dk_crypto_length(const struct krb5_aead_provider *aead,
+                        const struct krb5_enc_provider *enc,
+                        const struct krb5_hash_provider *hash,
+                        krb5_cryptotype type,
+                        size_t *length)
+{
+    switch (type) {
+    case KRB5_CRYPTO_TYPE_HEADER:
+    case KRB5_CRYPTO_TYPE_PADDING:
+       *length = enc->block_size;
+       break;
+    case KRB5_CRYPTO_TYPE_TRAILER:
+    case KRB5_CRYPTO_TYPE_CHECKSUM:
+       *length = hash->hashsize;
+       break;
+    default:
+       assert(0 && "invalid cryptotype passed to krb5int_dk_crypto_length");
+       break;
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+krb5int_dk_encrypt_iov(const struct krb5_aead_provider *aead,
+                      const struct krb5_enc_provider *enc,
+                      const struct krb5_hash_provider *hash,
+                      const krb5_keyblock *key,
+                      krb5_keyusage usage,
+                      const krb5_data *ivec,
+                      krb5_crypto_iov *data,
+                      size_t num_data)
+{
+    krb5_error_code ret;
+    unsigned char constantdata[K5CLENGTH];
+    krb5_data d1, d2;
+    krb5_crypto_iov *header, *trailer, *padding;
+    krb5_keyblock ke, ki;
+    size_t i;
+    size_t blocksize = 0;
+    size_t plainlen = 0;
+    size_t hmacsize = 0;
+    size_t padsize = 0;
+    unsigned char *cksum = NULL;
+
+    ke.contents = ki.contents = NULL;
+    ke.length = ki.length = 0;
+
+    /* E(Confounder | Plaintext | Pad) | Checksum */
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_PADDING, &blocksize);
+    if (ret != 0)
+       return ret;
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_TRAILER, &hmacsize);
+    if (ret != 0)
+       return ret;
+
+    for (i = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (iov->flags == KRB5_CRYPTO_TYPE_DATA)
+           plainlen += iov->data.length;
+    }
+
+    /* 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 < hmacsize)
+       return KRB5_BAD_MSIZE;
+
+    if (blocksize != 0) {
+       /* Check that the input data is correctly padded */
+       if (plainlen % blocksize)
+           padsize = blocksize - (plainlen % blocksize);
+    }
+
+    padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
+    if (padsize && (padding == NULL || padding->data.length < padsize))
+       return KRB5_BAD_MSIZE;
+
+    if (padding != NULL) {
+       memset(padding->data.data, 0, padsize);
+       padding->data.length = padsize;
+    }
+
+    ke.length = enc->keylength;
+    ke.contents = malloc(ke.length);
+    if (ke.contents == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+    ki.length = enc->keylength;
+    ki.contents = malloc(ki.length);
+    if (ki.contents == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+    cksum = (unsigned char *)malloc(hash->hashsize);
+    if (cksum == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+
+    /* derive the keys */
+
+    d1.data = (char *)constantdata;
+    d1.length = K5CLENGTH;
+
+    d1.data[0] = (usage >> 24) & 0xFF;
+    d1.data[1] = (usage >> 16) & 0xFF;
+    d1.data[2] = (usage >> 8 ) & 0xFF;
+    d1.data[3] = (usage      ) & 0xFF;
+
+    d1.data[4] = 0xAA;
+
+    ret = krb5_derive_key(enc, key, &ke, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    d1.data[4] = 0x55;
+
+    ret = krb5_derive_key(enc, key, &ki, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    /* generate confounder */
+
+    header->data.length = enc->block_size;
+
+    ret = krb5_c_random_make_octets(/* XXX */ NULL, &header->data);
+    if (ret != 0)
+       goto cleanup;
+
+    /* hash the plaintext */
+    d2.length = hash->hashsize;
+    d2.data = (char *)cksum;
+
+    ret = krb5_hmac_iov(hash, &ki, data, num_data, &d2);
+    if (ret != 0)
+       goto cleanup;
+
+    /* encrypt the plaintext (header | data | padding) */
+    assert(enc->encrypt_iov != NULL);
+
+    ret = enc->encrypt_iov(&ke, ivec, data, num_data); /* will update ivec */
+    if (ret != 0)
+       goto cleanup;
+
+    /* possibly truncate the hash */
+    assert(hmacsize <= d2.length);
+
+    memcpy(trailer->data.data, cksum, hmacsize);
+    trailer->data.length = hmacsize;
+
+cleanup:
+    if (ke.contents != NULL) {
+       memset(ke.contents, 0, ke.length);
+       free(ke.contents);
+    }
+    if (ki.contents != NULL) {
+       memset(ki.contents, 0, ki.length);
+       free(ki.contents);
+    }
+    if (cksum != NULL) {
+       free(cksum);
+    }
+
+    return ret;
+}
+
+static krb5_error_code
+krb5int_dk_decrypt_iov(const struct krb5_aead_provider *aead,
+                      const struct krb5_enc_provider *enc,
+                      const struct krb5_hash_provider *hash,
+                      const krb5_keyblock *key,
+                      krb5_keyusage usage,
+                      const krb5_data *ivec,
+                      krb5_crypto_iov *data,
+                      size_t num_data)
+{
+    krb5_error_code ret;
+    unsigned char constantdata[K5CLENGTH];
+    krb5_data d1;
+    krb5_crypto_iov *header, *trailer;
+    krb5_keyblock ke, ki;
+    size_t i;
+    size_t blocksize = 0; /* careful, this is enc block size not confounder len */
+    size_t cipherlen = 0;
+    size_t hmacsize = 0;
+    unsigned char *cksum = NULL;
+
+    ke.contents = ki.contents = NULL;
+    ke.length = ki.length = 0;
+
+    /* E(Confounder | Plaintext | Pad) | Checksum */
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_PADDING, &blocksize);
+    if (ret != 0)
+       return ret;
+
+    ret = aead->crypto_length(aead, enc, hash, KRB5_CRYPTO_TYPE_TRAILER, &hmacsize);
+    if (ret != 0)
+       return ret;
+
+    for (i = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_DATA_IOV(iov))
+           cipherlen += iov->data.length;
+    }
+
+    if (blocksize == 0) {
+       /* Check for correct input length in CTS mode */
+        if (enc->block_size != 0 && cipherlen < enc->block_size)
+           return KRB5_BAD_MSIZE;
+    } else {
+       /* Check that the input data is correctly padded */
+       if ((cipherlen % blocksize) != 0)
+           return KRB5_BAD_MSIZE;
+    }
+
+    /* 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 != hmacsize)
+       return KRB5_BAD_MSIZE;
+
+    ke.length = enc->keylength;
+    ke.contents = malloc(ke.length);
+    if (ke.contents == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+    ki.length = enc->keylength;
+    ki.contents = malloc(ki.length);
+    if (ki.contents == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+    cksum = (unsigned char *)malloc(hash->hashsize);
+    if (cksum == NULL) {
+       ret = ENOMEM;
+       goto cleanup;
+    }
+
+    /* derive the keys */
+
+    d1.data = (char *)constantdata;
+    d1.length = K5CLENGTH;
+
+    d1.data[0] = (usage >> 24) & 0xFF;
+    d1.data[1] = (usage >> 16) & 0xFF;
+    d1.data[2] = (usage >> 8 ) & 0xFF;
+    d1.data[3] = (usage      ) & 0xFF;
+
+    d1.data[4] = 0xAA;
+
+    ret = krb5_derive_key(enc, key, &ke, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    d1.data[4] = 0x55;
+
+    ret = krb5_derive_key(enc, key, &ki, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    /* decrypt the plaintext (header | data | padding) */
+    assert(enc->decrypt_iov != NULL);
+
+    ret = enc->decrypt_iov(&ke, ivec, data, num_data); /* will update ivec */
+    if (ret != 0)
+       goto cleanup;
+
+    /* verify the hash */
+    d1.length = hash->hashsize; /* non-truncated length */
+    d1.data = (char *)cksum;
+
+    ret = krb5_hmac_iov(hash, &ki, data, num_data, &d1);
+    if (ret != 0)
+       goto cleanup;
+
+    /* compare only the possibly truncated length */
+    if (memcmp(cksum, trailer->data.data, hmacsize) != 0) {
+       ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+       goto cleanup;
+    }
+
+cleanup:
+    if (ke.contents != NULL) {
+       memset(ke.contents, 0, ke.length);
+       free(ke.contents);
+    }
+    if (ki.contents != NULL) {
+       memset(ki.contents, 0, ki.length);
+       free(ki.contents);
+    }
+    if (cksum != NULL) {
+       free(cksum);
+    }
+
+    return ret;
+}
+
+const struct krb5_aead_provider krb5int_aead_dk = {
+    krb5int_dk_crypto_length,
+    krb5int_dk_encrypt_iov,
+    krb5int_dk_decrypt_iov
+};
+
+static krb5_error_code
+krb5int_aes_crypto_length(const struct krb5_aead_provider *aead,
+                        const struct krb5_enc_provider *enc,
+                        const struct krb5_hash_provider *hash,
+                        krb5_cryptotype type,
+                        size_t *length)
+{
+    switch (type) {
+    case KRB5_CRYPTO_TYPE_HEADER:
+       *length = enc->block_size;
+       break;
+    case KRB5_CRYPTO_TYPE_PADDING:
+       *length = 0;
+       break;
+    case KRB5_CRYPTO_TYPE_TRAILER:
+    case KRB5_CRYPTO_TYPE_CHECKSUM:
+       *length = 96 / 8;
+       break;
+    default:
+       assert(0 && "invalid cryptotype passed to krb5int_aes_crypto_length");
+       break;
+    }
+
+    return 0;
+}
+
+const struct krb5_aead_provider krb5int_aead_aes = {
+    krb5int_aes_crypto_length,
+    krb5int_dk_encrypt_iov,
+    krb5int_dk_decrypt_iov
+};
+
index fde1a81f0e3bf3a159fdc94c2a278a0c785384da..e025cc3ebc88f98f13fc24db1a6d7eda53c4cd97 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * lib/crypto/enc_provider/aes.h
+ * lib/crypto/enc_provider/aes.c
  *
- * Copyright (C) 2003, 2007 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2003, 2007, 2008 by the Massachusetts Institute of Technology.
  * All rights reserved.
  *
  * Export of this software from the United States of America may
@@ -27,6 +27,7 @@
 #include "k5-int.h"
 #include "enc_provider.h"
 #include "aes.h"
+#include "../aead.h"
 
 #if 0
 aes_rval aes_blk_len(unsigned int blen, aes_ctx cx[1]);
@@ -197,6 +198,169 @@ krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
     return 0;
 }
 
+static krb5_error_code
+krb5int_aes_encrypt_iov(const krb5_keyblock *key,
+                       const krb5_data *ivec,
+                       krb5_crypto_iov *data,
+                       size_t num_data)
+{
+    aes_ctx ctx;
+    char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+    size_t input_length, i;
+
+    if (aes_enc_key(key->contents, key->length, &ctx) != aes_good)
+       abort();
+
+    if (ivec != NULL)
+       memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+       memset(tmp, 0, BLOCK_SIZE);
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    assert(nblocks > 1);
+
+    {
+       char blockN2[BLOCK_SIZE];   /* second last */
+       char blockN1[BLOCK_SIZE];   /* last block */
+       struct iov_block_state input_pos, output_pos;
+
+       IOV_BLOCK_STATE_INIT(&input_pos);
+       IOV_BLOCK_STATE_INIT(&output_pos);
+
+       for (blockno = 0; blockno < nblocks - 2; blockno++) {
+           char blockN[BLOCK_SIZE];
+
+           krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos);
+           xorblock(tmp, blockN);
+           enc(tmp2, tmp, &ctx);
+           krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos);
+
+           /* Set up for next block.  */
+           memcpy(tmp, tmp2, BLOCK_SIZE);
+       }
+
+       /* Do final CTS step for last two blocks (the second of which
+          may or may not be incomplete).  */
+
+       /* First, get the last two blocks */
+       memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */
+       krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos);
+       krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos);
+
+       /* Encrypt second last block */
+       xorblock(tmp, blockN2);
+       enc(tmp2, tmp, &ctx);
+       memcpy(blockN2, tmp2, BLOCK_SIZE); /* blockN2 now contains first block */
+       memcpy(tmp, tmp2, BLOCK_SIZE);
+
+       /* Encrypt last block */
+       xorblock(tmp, blockN1);
+       enc(tmp2, tmp, &ctx);
+       memcpy(blockN1, tmp2, BLOCK_SIZE);
+       if (ivec != NULL)
+           memcpy(ivec->data, tmp2, BLOCK_SIZE);
+
+       /* Put the last two blocks back into the ivec (reverse order) */
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos);
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos);
+    }
+
+    return 0;
+}
+
+static krb5_error_code
+krb5int_aes_decrypt_iov(const krb5_keyblock *key,
+                       const krb5_data *ivec,
+                       krb5_crypto_iov *data,
+                       size_t num_data)
+{
+    aes_ctx ctx;
+    char tmp[BLOCK_SIZE], tmp2[BLOCK_SIZE], tmp3[BLOCK_SIZE];
+    int nblocks = 0, blockno;
+    size_t input_length, i;
+
+    CHECK_SIZES;
+
+    if (aes_dec_key(key->contents, key->length, &ctx) != aes_good)
+       abort();
+
+    if (ivec != NULL)
+       memcpy(tmp, ivec->data, BLOCK_SIZE);
+    else
+       memset(tmp, 0, BLOCK_SIZE);
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    nblocks = (input_length + BLOCK_SIZE - 1) / BLOCK_SIZE;
+
+    assert(nblocks > 1);
+
+    {
+       char blockN2[BLOCK_SIZE];   /* second last */
+       char blockN1[BLOCK_SIZE];   /* last block */
+       struct iov_block_state input_pos, output_pos;
+
+       IOV_BLOCK_STATE_INIT(&input_pos);
+       IOV_BLOCK_STATE_INIT(&output_pos);
+
+       for (blockno = 0; blockno < nblocks - 2; blockno++) {
+           char blockN[BLOCK_SIZE];
+
+           krb5int_c_iov_get_block((unsigned char *)blockN, BLOCK_SIZE, data, num_data, &input_pos);
+           dec(tmp2, blockN, &ctx);
+           xorblock(tmp2, tmp);
+           krb5int_c_iov_put_block(data, num_data, (unsigned char *)tmp2, BLOCK_SIZE, &output_pos);
+           memcpy(tmp, blockN, BLOCK_SIZE);
+       }
+
+       /* Do last two blocks, the second of which (next-to-last block
+          of plaintext) may be incomplete.  */
+
+       /* First, get the last two encrypted blocks */
+       memset(blockN1, 0, sizeof(blockN1)); /* pad last block with zeros */
+       krb5int_c_iov_get_block((unsigned char *)blockN2, BLOCK_SIZE, data, num_data, &input_pos);
+       krb5int_c_iov_get_block((unsigned char *)blockN1, BLOCK_SIZE, data, num_data, &input_pos);
+
+       /* Decrypt second last block */
+       dec(tmp2, blockN2, &ctx);
+       /* Set tmp3 to last ciphertext block (already padded) */
+       memcpy(tmp3, blockN1, BLOCK_SIZE);
+       /* Set tmp2 to last (possibly partial) plaintext block, and
+          save it.  */
+       xorblock(tmp2, tmp3);
+       memcpy(blockN1, tmp2, BLOCK_SIZE);
+       /* Maybe keep the trailing part, and copy in the last
+          ciphertext block.  */
+       memcpy(tmp2, tmp3, BLOCK_SIZE);
+       dec(tmp3, tmp2, &ctx);
+       xorblock(tmp3, tmp);
+       /* Copy out ivec first before we clobber blockN2 with plaintext */
+       if (ivec != NULL)
+           memcpy(ivec->data, blockN2, BLOCK_SIZE);
+       memcpy(blockN2, tmp3, BLOCK_SIZE);
+
+       /* Put the last two blocks back into the ivec */
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN2, BLOCK_SIZE, &output_pos);
+       krb5int_c_iov_put_block(data, num_data, (unsigned char *)blockN1, BLOCK_SIZE, &output_pos);
+    }
+
+    return 0;
+}
+
 static krb5_error_code
 k5_aes_make_key(const krb5_data *randombits, krb5_keyblock *key)
 {
@@ -230,7 +394,9 @@ const struct krb5_enc_provider krb5int_enc_aes128 = {
     krb5int_aes_decrypt,
     k5_aes_make_key,
     krb5int_aes_init_state,
-    krb5int_default_free_state
+    krb5int_default_free_state,
+    krb5int_aes_encrypt_iov,
+    krb5int_aes_decrypt_iov
 };
 
 const struct krb5_enc_provider krb5int_enc_aes256 = {
@@ -240,5 +406,8 @@ const struct krb5_enc_provider krb5int_enc_aes256 = {
     krb5int_aes_decrypt,
     k5_aes_make_key,
     krb5int_aes_init_state,
-    krb5int_default_free_state
+    krb5int_default_free_state,
+    krb5int_aes_encrypt_iov,
+    krb5int_aes_decrypt_iov
 };
+
index 51e4ce7967a03ac1ebce98b2099887eafd5d0c35..e7a07f64ccbd2005b2d3f5958dfc3396d3b0d80f 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "k5-int.h"
 #include "des_int.h"
+#include "../aead.h"
 
 static krb5_error_code
 validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec,
@@ -53,6 +54,37 @@ validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec,
     return 0;
 }
 
+static krb5_error_code
+validate_and_schedule_iov(const krb5_keyblock *key, const krb5_data *ivec,
+                         const krb5_crypto_iov *data, size_t num_data,
+                         mit_des3_key_schedule *schedule)
+{
+    size_t i, input_length;
+
+    for (i = 0, input_length = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           input_length += iov->data.length;
+    }
+
+    if (key->length != 24)
+       return(KRB5_BAD_KEYSIZE);
+    if ((input_length%8) != 0)
+       return(KRB5_BAD_MSIZE);
+    if (ivec && (ivec->length != 8))
+       return(KRB5_BAD_MSIZE);
+
+    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->contents,
+                              *schedule)) {
+    case -1:
+       return(KRB5DES_BAD_KEYPAR);
+    case -2:
+       return(KRB5DES_WEAK_KEY);
+    }
+    return 0;
+}
+
 static krb5_error_code
 k5_des3_encrypt(const krb5_keyblock *key, const krb5_data *ivec,
                const krb5_data *input, krb5_data *output)
@@ -129,6 +161,52 @@ k5_des3_make_key(const krb5_data *randombits, krb5_keyblock *key)
     return(0);
 }
 
+static krb5_error_code
+k5_des3_encrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+    if (err)
+       return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_encrypt_iov(data, num_data,
+                            schedule[0], schedule[1], schedule[2],
+                            ivec != NULL ? (const unsigned char *) ivec->data : NULL);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
+static krb5_error_code
+k5_des3_decrypt_iov(const krb5_keyblock *key,
+                   const krb5_data *ivec,
+                   krb5_crypto_iov *data,
+                   size_t num_data)
+{
+    mit_des3_key_schedule schedule;
+    krb5_error_code err;
+
+    err = validate_and_schedule_iov(key, ivec, data, num_data, &schedule);
+    if (err)
+       return err;
+
+    /* this has a return value, but the code always returns zero */
+    krb5int_des3_cbc_decrypt_iov(data, num_data,
+                                schedule[0], schedule[1], schedule[2],
+                                ivec != NULL ? (const unsigned char *) ivec->data : NULL);
+
+    zap(schedule, sizeof(schedule));
+
+    return(0);
+}
+
 const struct krb5_enc_provider krb5int_enc_des3 = {
     8,
     21, 24,
@@ -136,5 +214,8 @@ const struct krb5_enc_provider krb5int_enc_des3 = {
     k5_des3_decrypt,
     k5_des3_make_key,
     krb5int_des_init_state,
-    krb5int_default_free_state
+    krb5int_default_free_state,
+    k5_des3_encrypt_iov,
+    k5_des3_decrypt_iov
 };
+
index 5754d1a2d55d9dce5ce2894441e56af95c4687cb..4c370c14dd45aea54895a6d1d2c38b4d9859cacc 100644 (file)
@@ -31,3 +31,4 @@ extern const struct krb5_enc_provider krb5int_enc_des3;
 extern const struct krb5_enc_provider krb5int_enc_arcfour;
 extern const struct krb5_enc_provider krb5int_enc_aes128;
 extern const struct krb5_enc_provider krb5int_enc_aes256;
+
index a88ad79376d4428916629a14275d7dbf98835510..b950a605b8ed12e9adbde3aa074edfafde914d48 100644 (file)
@@ -9,6 +9,7 @@
 #include "k5-int.h"
 #include "arcfour-int.h"
 #include "enc_provider.h"
+#include "../aead.h"
 /* gets the next byte from the PRNG */
 #if ((__GNUC__ >= 2) )
 static __inline__ unsigned int k5_arcfour_byte(ArcfourContext *);
@@ -156,6 +157,61 @@ k5_arcfour_docrypt(const krb5_keyblock *key, const krb5_data *state,
   return 0;
 }
 
+/* In-place encryption */
+static krb5_error_code
+k5_arcfour_docrypt_iov(const krb5_keyblock *key,
+                      const krb5_data *state,
+                      krb5_crypto_iov *data,
+                      size_t num_data)
+{
+    ArcfourContext *arcfour_ctx = NULL;
+    ArcFourCipherState *cipher_state = NULL;
+    krb5_error_code ret;
+    size_t i;
+
+    if (key->length != 16)
+       return KRB5_BAD_KEYSIZE;
+    if (state != NULL && (state->length != sizeof(ArcFourCipherState)))
+       return KRB5_BAD_MSIZE;
+
+    if (state != NULL) {
+       cipher_state = (ArcFourCipherState *)state->data;
+       arcfour_ctx = &cipher_state->ctx;
+       if (cipher_state->initialized == 0) {
+           ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length);
+           if (ret != 0)
+               return ret;
+
+           cipher_state->initialized = 1;
+       }
+    } else {
+       arcfour_ctx = (ArcfourContext *)malloc(sizeof(ArcfourContext));
+       if (arcfour_ctx == NULL)
+           return ENOMEM;
+
+       ret = k5_arcfour_init(arcfour_ctx, key->contents, key->length);
+       if (ret != 0) {
+           free(arcfour_ctx);
+           return ret;
+       }
+    }
+
+    for (i = 0; i < num_data; i++) {
+       krb5_crypto_iov *iov = &data[i];
+
+       if (ENCRYPT_IOV(iov))
+           k5_arcfour_crypt(arcfour_ctx, (unsigned char *)iov->data.data,
+                            (const unsigned char *)iov->data.data, iov->data.length);
+    }
+
+    if (state == NULL) {
+       memset(arcfour_ctx, 0, sizeof(ArcfourContext));
+       free(arcfour_ctx);
+    }
+
+    return 0;
+}
+
 static krb5_error_code
 k5_arcfour_make_key(const krb5_data *randombits, krb5_keyblock *key)
 {
@@ -208,5 +264,8 @@ const struct krb5_enc_provider krb5int_enc_arcfour = {
     k5_arcfour_docrypt,
     k5_arcfour_make_key,
     k5_arcfour_init_state, /*xxx not implemented yet*/
-    krb5int_default_free_state
+    krb5int_default_free_state,
+    k5_arcfour_docrypt_iov,
+    k5_arcfour_docrypt_iov
 };
+
diff --git a/src/lib/crypto/encrypt_iov.c b/src/lib/crypto/encrypt_iov.c
new file mode 100644 (file)
index 0000000..a35c5b5
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * lib/crypto/encrypt_iov.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "etypes.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_encrypt_iov(krb5_context context,
+                  const krb5_keyblock *key,
+                  krb5_keyusage usage,
+                  const krb5_data *cipher_state,
+                  krb5_crypto_iov *data,
+                  size_t num_data)
+{
+    int i;
+    const struct krb5_keytypes *ktp = NULL;
+
+    for (i = 0; i < krb5_enctypes_length; i++) {
+       if (krb5_enctypes_list[i].etype == key->enctype) {
+           ktp = &krb5_enctypes_list[i];
+           break;
+       }
+    }
+
+    if (ktp == NULL || ktp->aead == NULL) {
+       return KRB5_BAD_ENCTYPE;
+    }
+
+    return ktp->aead->encrypt_iov(ktp->aead, ktp->enc, ktp->hash,
+                                 key, usage, cipher_state, data, num_data);
+}
+
index 4273e2826ea4c5fef170a285769fa18086fe4b0f..340fc31d33c7b4a91c2203ea1cdc899eaf0c5f7a 100644 (file)
@@ -48,7 +48,8 @@ const struct krb5_keytypes krb5_enctypes_list[] = {
       krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
       krb5int_des_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_RSA_MD5 },
+      CKSUMTYPE_RSA_MD5,
+      NULL  /*AEAD*/ },
     { ENCTYPE_DES_CBC_MD4,
       "des-cbc-md4", "DES cbc mode with RSA-MD4",
       &krb5int_enc_des, &krb5int_hash_md4,
@@ -56,7 +57,8 @@ const struct krb5_keytypes krb5_enctypes_list[] = {
       krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
       krb5int_des_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_RSA_MD4 },
+      CKSUMTYPE_RSA_MD4,
+      NULL  /*AEAD*/  },
     { ENCTYPE_DES_CBC_MD5,
       "des-cbc-md5", "DES cbc mode with RSA-MD5",
       &krb5int_enc_des, &krb5int_hash_md5,
@@ -64,7 +66,8 @@ const struct krb5_keytypes krb5_enctypes_list[] = {
       krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
       krb5int_des_string_to_key,
       NULL, /*PRF*/
-CKSUMTYPE_RSA_MD5 },
+      CKSUMTYPE_RSA_MD5,
+      NULL  /*AEAD*/ },
     { ENCTYPE_DES_CBC_MD5,
       "des", "DES cbc mode with RSA-MD5", /* alias */
       &krb5int_enc_des, &krb5int_hash_md5,
@@ -72,7 +75,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_old_encrypt_length, krb5_old_encrypt, krb5_old_decrypt,
       krb5int_des_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_RSA_MD5 },
+      CKSUMTYPE_RSA_MD5,
+      NULL  /*AEAD*/ },
 
     { ENCTYPE_DES_CBC_RAW,
       "des-cbc-raw", "DES cbc mode raw",
@@ -81,7 +85,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_raw_encrypt_length, krb5_raw_encrypt, krb5_raw_decrypt,
       krb5int_des_string_to_key,
       NULL, /*PRF*/
-      0 },
+      0,
+      NULL  /*AEAD*/ },
     { ENCTYPE_DES3_CBC_RAW,
       "des3-cbc-raw", "Triple DES cbc mode raw",
       &krb5int_enc_des3, NULL,
@@ -89,7 +94,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_raw_encrypt_length, krb5_raw_encrypt, krb5_raw_decrypt,
       krb5int_dk_string_to_key,
       NULL, /*PRF*/
-      0 },
+      0,
+      NULL  /*AEAD*/ },
 
     { ENCTYPE_DES3_CBC_SHA1,
       "des3-cbc-sha1", "Triple DES cbc mode with HMAC/sha1",
@@ -98,7 +104,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
       krb5int_dk_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_SHA1_DES3 },
+      CKSUMTYPE_HMAC_SHA1_DES3,
+      &krb5int_aead_dk },
     { ENCTYPE_DES3_CBC_SHA1,   /* alias */
       "des3-hmac-sha1", "Triple DES cbc mode with HMAC/sha1",
       &krb5int_enc_des3, &krb5int_hash_sha1,
@@ -106,7 +113,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
       krb5int_dk_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_SHA1_DES3 },
+      CKSUMTYPE_HMAC_SHA1_DES3,
+      &krb5int_aead_dk },
     { ENCTYPE_DES3_CBC_SHA1,   /* alias */
       "des3-cbc-sha1-kd", "Triple DES cbc mode with HMAC/sha1",
       &krb5int_enc_des3, &krb5int_hash_sha1,
@@ -114,7 +122,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
       krb5int_dk_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_SHA1_DES3 },
+      CKSUMTYPE_HMAC_SHA1_DES3,
+      &krb5int_aead_dk },
 
     { ENCTYPE_DES_HMAC_SHA1,
       "des-hmac-sha1", "DES with HMAC/sha1",
@@ -123,7 +132,8 @@ CKSUMTYPE_RSA_MD5 },
       krb5_dk_encrypt_length, krb5_dk_encrypt, krb5_dk_decrypt,
       krb5int_dk_string_to_key,
       NULL, /*PRF*/
-      0 },
+      0,
+      NULL },
     { ENCTYPE_ARCFOUR_HMAC, 
       "arcfour-hmac","ArcFour with HMAC/md5", &krb5int_enc_arcfour,
       &krb5int_hash_md5,
@@ -131,7 +141,8 @@ CKSUMTYPE_RSA_MD5 },
 krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+      CKSUMTYPE_HMAC_MD5_ARCFOUR,
+      &krb5int_aead_arcfour },
     { ENCTYPE_ARCFOUR_HMAC,  /* alias */
       "rc4-hmac", "ArcFour with HMAC/md5", &krb5int_enc_arcfour,
       &krb5int_hash_md5,
@@ -139,7 +150,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+      CKSUMTYPE_HMAC_MD5_ARCFOUR,
+      &krb5int_aead_arcfour },
     { ENCTYPE_ARCFOUR_HMAC,  /* alias */
       "arcfour-hmac-md5", "ArcFour with HMAC/md5", &krb5int_enc_arcfour,
       &krb5int_hash_md5,
@@ -147,7 +159,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+      CKSUMTYPE_HMAC_MD5_ARCFOUR,
+      &krb5int_aead_arcfour },
     { ENCTYPE_ARCFOUR_HMAC_EXP, 
       "arcfour-hmac-exp", "Exportable ArcFour with HMAC/md5",
       &krb5int_enc_arcfour,
@@ -156,7 +169,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+      CKSUMTYPE_HMAC_MD5_ARCFOUR,
+      &krb5int_aead_arcfour },
     { ENCTYPE_ARCFOUR_HMAC_EXP, /* alias */
       "rc4-hmac-exp", "Exportable ArcFour with HMAC/md5",
       &krb5int_enc_arcfour,
@@ -165,7 +179,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+      CKSUMTYPE_HMAC_MD5_ARCFOUR,
+      &krb5int_aead_arcfour },
     { ENCTYPE_ARCFOUR_HMAC_EXP, /* alias */
       "arcfour-hmac-md5-exp", "Exportable ArcFour with HMAC/md5",
       &krb5int_enc_arcfour,
@@ -174,7 +189,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5_arcfour_decrypt, krb5int_arcfour_string_to_key,
       NULL, /*PRF*/
-      CKSUMTYPE_HMAC_MD5_ARCFOUR },
+      CKSUMTYPE_HMAC_MD5_ARCFOUR,
+      &krb5int_aead_arcfour },
 
     { ENCTYPE_AES128_CTS_HMAC_SHA1_96,
       "aes128-cts-hmac-sha1-96", "AES-128 CTS mode with 96-bit SHA-1 HMAC",
@@ -183,7 +199,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
       krb5int_aes_string_to_key,
       krb5int_dk_prf,
-      CKSUMTYPE_HMAC_SHA1_96_AES128 },
+      CKSUMTYPE_HMAC_SHA1_96_AES128,
+      &krb5int_aead_aes },
     { ENCTYPE_AES128_CTS_HMAC_SHA1_96, /* alias */
       "aes128-cts", "AES-128 CTS mode with 96-bit SHA-1 HMAC",
       &krb5int_enc_aes128, &krb5int_hash_sha1,
@@ -191,7 +208,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
       krb5int_aes_string_to_key,
       krb5int_dk_prf,
-      CKSUMTYPE_HMAC_SHA1_96_AES128 },
+      CKSUMTYPE_HMAC_SHA1_96_AES128,
+      &krb5int_aead_aes },
     { ENCTYPE_AES256_CTS_HMAC_SHA1_96,
       "aes256-cts-hmac-sha1-96", "AES-256 CTS mode with 96-bit SHA-1 HMAC",
       &krb5int_enc_aes256, &krb5int_hash_sha1,
@@ -199,7 +217,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
       krb5int_aes_string_to_key,
       krb5int_dk_prf,
-      CKSUMTYPE_HMAC_SHA1_96_AES256 },
+      CKSUMTYPE_HMAC_SHA1_96_AES256,
+      &krb5int_aead_aes },
     { ENCTYPE_AES256_CTS_HMAC_SHA1_96, /* alias */
       "aes256-cts", "AES-256 CTS mode with 96-bit SHA-1 HMAC",
       &krb5int_enc_aes256, &krb5int_hash_sha1,
@@ -207,7 +226,8 @@ krb5_arcfour_encrypt_length, krb5_arcfour_encrypt,
       krb5int_aes_encrypt_length, krb5int_aes_dk_encrypt, krb5int_aes_dk_decrypt,
       krb5int_aes_string_to_key,
       krb5int_dk_prf,
-      CKSUMTYPE_HMAC_SHA1_96_AES256 },
+      CKSUMTYPE_HMAC_SHA1_96_AES256,
+      &krb5int_aead_aes },
 };
 
 const int krb5_enctypes_length =
index 3c027264557db015638ac268aec3b0042db08320..42785f572985c28f2f0985dea99808b7ca86d2aa 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "k5-int.h"
+#include "aead.h"
 
 /*
  * the HMAC transform looks like:
@@ -125,3 +126,40 @@ cleanup:
 
     return(ret);
 }
+
+krb5_error_code
+krb5_hmac_iov(const struct krb5_hash_provider *hash, const krb5_keyblock *key,
+             const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
+{
+    krb5_data *sign_data;
+    size_t num_sign_data;
+    krb5_error_code ret;
+    size_t i, j;
+
+    /* Create a checksum over all the data to be signed */
+    for (i = 0, num_sign_data = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (SIGN_IOV(iov))
+           num_sign_data++;
+    }
+    /* XXX cleanup to avoid alloc */
+    sign_data = (krb5_data *)calloc(num_sign_data, sizeof(krb5_data));
+    if (sign_data == NULL)
+       return ENOMEM;
+
+    for (i = 0, j = 0; i < num_data; i++) {
+       const krb5_crypto_iov *iov = &data[i];
+
+       if (SIGN_IOV(iov))
+           sign_data[j++] = iov->data;
+    }
+
+    /* caller must store checksum in iov as it may be TYPE_TRAILER or TYPE_CHECKSUM */
+    ret = krb5_hmac(hash, key, num_sign_data, sign_data, output);
+
+    free(sign_data);
+
+    return ret;
+}
+
index 23b33fc07d6c3ba79716bebbfd427ce64962ab77..bf68e324cebb8151e6e0d0eab42304a75038484a 100644 (file)
@@ -66,5 +66,7 @@ k5_descbc_hash(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data *i
 const struct krb5_keyhash_provider krb5int_keyhash_descbc = {
     8,
     k5_descbc_hash,
+    NULL,
+    NULL,
     NULL
 };
index a2472a83299aee286f7efd2fa469a8c02b914159..0f510925d93447418fc35629d75c392378283842 100644 (file)
@@ -35,6 +35,7 @@
 #include "arcfour-int.h"
 #include "rsa-md5.h"
 #include "hash_provider.h"
+#include "../aead.h"
 
 static  krb5_error_code
 k5_hmac_md5_hash (const krb5_keyblock *key, krb5_keyusage usage,
@@ -86,11 +87,67 @@ k5_hmac_md5_hash (const krb5_keyblock *key, krb5_keyusage usage,
   return ret;
 }
 
-                
+static  krb5_error_code
+k5_hmac_md5_hash_iov (const krb5_keyblock *key, krb5_keyusage usage,
+                     const krb5_data *iv,
+                     const krb5_crypto_iov *data, size_t num_data,
+                     krb5_data *output)
+{
+  krb5_keyusage ms_usage;
+  krb5_error_code ret;
+  krb5_keyblock ks;
+  krb5_data ds, ks_constant, md5tmp;
+  krb5_MD5_CTX ctx;
+  char t[4];
+  size_t i;
+
+  ds.length = key->length;
+  ks.length = key->length;
+  ds.data = malloc(ds.length);
+  if (ds.data == NULL)
+    return ENOMEM;
+  ks.contents = (void *) ds.data;
+
+  ks_constant.data = "signaturekey";
+  ks_constant.length = strlen(ks_constant.data)+1; /* Including null*/
+
+  ret = krb5_hmac( &krb5int_hash_md5, key, 1,
+                  &ks_constant, &ds);
+  if (ret)
+    goto cleanup;
+
+  krb5_MD5Init (&ctx);
+  ms_usage = krb5int_arcfour_translate_usage (usage);
+  t[0] = (ms_usage) & 0xff;
+  t[1] = (ms_usage>>8) & 0xff;
+  t[2] = (ms_usage >>16) & 0xff;
+  t[3] = (ms_usage>>24) & 0XFF;
+  krb5_MD5Update (&ctx, (unsigned char * ) &t, 4);
+  for (i = 0; i < num_data; i++) {
+    const krb5_crypto_iov *iov = &data[i];
+
+    if (SIGN_IOV(iov))
+      krb5_MD5Update (&ctx, (unsigned char *)iov->data.data,
+                     (unsigned int)iov->data.length);
+  }
+  krb5_MD5Final(&ctx);
+  md5tmp.data = (void *) ctx.digest;
+  md5tmp.length = 16;
+  ret = krb5_hmac ( &krb5int_hash_md5, &ks, 1, &md5tmp,
+                   output);
+
+    cleanup:
+  memset(&ctx, 0, sizeof(ctx));
+  memset (ks.contents, 0, ks.length);
+  free (ks.contents);
+  return ret;
+}
 
 const struct krb5_keyhash_provider krb5int_keyhash_hmac_md5 = {
   16,
   k5_hmac_md5_hash,
-  NULL /*checksum  again*/
+  NULL, /*checksum  again*/
+  k5_hmac_md5_hash_iov,
+  NULL  /*checksum  again */
 };
 
index 9f19f4f9682bcbfe0ec599a1d2f7772e229ebe9c..fceb58ebd48f3f5259f370d6ee241dc541a84419 100644 (file)
@@ -188,5 +188,7 @@ k5_md4des_verify(const krb5_keyblock *key, krb5_keyusage usage,
 const struct krb5_keyhash_provider krb5int_keyhash_md4des = {
     CONFLENGTH+RSA_MD4_CKSUM_LENGTH,
     k5_md4des_hash,
-    k5_md4des_verify
+    k5_md4des_verify,
+    NULL,
+    NULL
 };
index e70965b79103a181f45bc4c6909eba34ebb370a2..0175c68ab7c10cea86136d3c0a0224dfb8d009a6 100644 (file)
@@ -185,5 +185,7 @@ k5_md5des_verify(const krb5_keyblock *key, krb5_keyusage usage, const krb5_data
 const struct krb5_keyhash_provider krb5int_keyhash_md5des = {
     CONFLENGTH+RSA_MD5_CKSUM_LENGTH,
     k5_md5des_hash,
-    k5_md5des_verify
+    k5_md5des_verify,
+    NULL,
+    NULL
 };
index d705a6b5f34d3494ade4d09d1f4c11edfc029e68..9fe8e69e15072346b5f343badc45dd71789ea473 100644 (file)
@@ -14,8 +14,12 @@ krb5_arcfour_encrypt
 krb5_arcfour_encrypt_length
 krb5_c_block_size
 krb5_c_checksum_length
+krb5_c_crypto_length
+krb5_c_crypto_length_iov
 krb5_c_decrypt
+krb5_c_decrypt_iov
 krb5_c_encrypt
+krb5_c_encrypt_iov
 krb5_c_encrypt_length
 krb5_c_enctype_compare
 krb5_c_free_state
@@ -25,7 +29,9 @@ krb5_c_is_keyed_cksum
 krb5_c_keyed_checksum_types
 krb5_c_keylengths
 krb5_c_make_checksum
+krb5_c_make_checksum_iov
 krb5_c_make_random_key
+krb5_c_padding_length
 krb5_c_prf
 krb5_c_prf_length
 krb5_c_random_add_entropy
@@ -38,6 +44,7 @@ krb5_c_string_to_key_with_params
 krb5_c_valid_cksumtype
 krb5_c_valid_enctype
 krb5_c_verify_checksum
+krb5_c_verify_checksum_iov
 krb5_calculate_checksum
 krb5_checksum_size
 krb5_cksumtype_to_string
@@ -62,6 +69,7 @@ krb5_finish_key
 krb5_finish_random_key
 krb5_free_cksumtypes
 krb5_hmac
+krb5_hmac_iov
 krb5_init_random_key
 krb5_nfold
 krb5_old_decrypt
diff --git a/src/lib/crypto/make_checksum_iov.c b/src/lib/crypto/make_checksum_iov.c
new file mode 100644 (file)
index 0000000..0d862c8
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * lib/crypto/make_checksum_iov.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+#include "aead.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_make_checksum_iov(krb5_context context,
+                        krb5_cksumtype cksumtype,
+                        const krb5_keyblock *key,
+                        krb5_keyusage usage,
+                        krb5_crypto_iov *data,
+                        size_t num_data)
+{
+    krb5_error_code ret;
+    size_t cksumlen;
+    krb5_crypto_iov *checksum;
+    size_t i;
+
+    for (i = 0; i < krb5_cksumtypes_length; i++) {
+       if (krb5_cksumtypes_list[i].ctype == cksumtype)
+           break;
+    }
+
+    if (i == krb5_cksumtypes_length)
+       return(KRB5_BAD_ENCTYPE);
+
+    if (krb5_cksumtypes_list[i].keyhash)
+       cksumlen = krb5_cksumtypes_list[i].keyhash->hashsize;
+    else
+       cksumlen = krb5_cksumtypes_list[i].hash->hashsize;
+
+    checksum = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
+    if (checksum == NULL || checksum->data.length < cksumlen)
+       return(KRB5_BAD_MSIZE);
+
+    checksum->data.length = cksumlen;
+
+    ret = krb5int_c_make_checksum_iov(&krb5_cksumtypes_list[i],
+                                     key, usage, data, num_data,
+                                     &checksum->data);
+
+    return(ret);
+}
index eb2378b5e53ca7c53f5184e8c13b14961a05f771..ded1d8d9825272d65639eea1bc97e8abfe8c746b 100644 (file)
@@ -1,7 +1,7 @@
 /*
 main * lib/crypto/t_encrypt.c
  *
- * Copyright2001 by the Massachusetts Institute of Technology.
+ * Copyright 2001, 2008by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -76,12 +76,15 @@ main ()
 {
   krb5_context context = 0;
   krb5_data  in, in2, out, out2, check, check2, state;
+  krb5_crypto_iov iov[5];
   int i;
   size_t len;
   krb5_enc_data enc_out, enc_out2;
   krb5_error_code retval;
   krb5_keyblock *key;
 
+  memset(iov, 0, sizeof(iov));
+
   in.data = "This is a test.\n";
   in.length = strlen (in.data);
   in2.data = "This is another test.\n";
@@ -118,6 +121,46 @@ main ()
     test ("Decrypting",
          krb5_c_decrypt (context, key, 7, 0, &enc_out, &check));
     test ("Comparing", compare_results (&in, &check));
+    if ( krb5_c_crypto_length(context, key->enctype, KRB5_CRYPTO_TYPE_HEADER, &len) == 0 ){
+       /* We support iov/aead*/
+       int j, pos;
+       krb5_data signdata;
+       signdata.data = (char *) "This should be signed";
+       signdata.length = strlen(signdata.data);
+       iov[0].flags= KRB5_CRYPTO_TYPE_STREAM;
+       iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
+       iov[0].data = enc_out.ciphertext;
+       iov[1].data = out;
+       test("IOV stream decrypting",
+            krb5_c_decrypt_iov( context, key, 7, 0, iov, 2));
+       test("Comparing results",
+            compare_results(&in, &iov[1].data));
+       iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
+       iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
+       iov[1].data = in; /*We'll need to copy memory before encrypt*/
+       iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+       iov[2].data = signdata;
+       iov[3].flags = KRB5_CRYPTO_TYPE_PADDING;
+       iov[4].flags = KRB5_CRYPTO_TYPE_TRAILER;
+       test("Setting up iov lengths",
+            krb5_c_crypto_length_iov(context, key->enctype, iov, 5));
+       for (j=0,pos=0; j <= 4; j++ ){
+           if (iov[j].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
+               continue;
+           iov[j].data.data = &out.data[pos];
+           pos += iov[j].data.length;
+       }
+       assert (iov[1].data.length == in.length);
+       memcpy(iov[1].data.data, in.data, in.length);
+       test("iov encrypting",
+            krb5_c_encrypt_iov(context, key, 7, 0, iov, 5));
+       assert(iov[1].data.length == in.length);
+       test("iov decrypting",
+            krb5_c_decrypt_iov(context, key, 7, 0, iov, 5));
+       test("Comparing results",
+            compare_results(&in, &iov[1].data));
+                      
+    }
     enc_out.ciphertext.length = out.length;
     check.length = 2048;
     test ("init_state",
diff --git a/src/lib/crypto/verify_checksum_iov.c b/src/lib/crypto/verify_checksum_iov.c
new file mode 100644 (file)
index 0000000..5627188
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * lib/crypto/verify_checksum_iov.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include "cksumtypes.h"
+#include "aead.h"
+
+krb5_error_code KRB5_CALLCONV
+krb5_c_verify_checksum_iov(krb5_context context, 
+                          krb5_cksumtype checksum_type,
+                          const krb5_keyblock *key,
+                          krb5_keyusage usage,
+                          const krb5_crypto_iov *data,
+                          size_t num_data,
+                          krb5_boolean *valid)
+{
+    unsigned int i;
+    size_t hashsize;
+    krb5_error_code ret;
+    krb5_data computed;
+    krb5_crypto_iov *checksum;
+
+    for (i=0; i<krb5_cksumtypes_length; i++) {
+       if (krb5_cksumtypes_list[i].ctype == checksum_type)
+           break;
+    }
+
+    if (i == krb5_cksumtypes_length)
+       return(KRB5_BAD_ENCTYPE);
+
+    checksum = krb5int_c_locate_iov((krb5_crypto_iov *)data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM);
+    if (checksum == NULL)
+       return(KRB5_BAD_MSIZE);
+
+    /* if there's actually a verify function, call it */
+
+    if (krb5_cksumtypes_list[i].keyhash &&
+       krb5_cksumtypes_list[i].keyhash->verify_iov)
+       return((*(krb5_cksumtypes_list[i].keyhash->verify_iov))(key, usage, 0,
+                                                               &checksum->data,
+                                                               data, num_data,
+                                                               valid));
+
+    /* otherwise, make the checksum again, and compare */
+
+    if ((ret = krb5_c_checksum_length(context, checksum_type, &hashsize)))
+       return(ret);
+
+    if (checksum->data.length != hashsize)
+       return(KRB5_BAD_MSIZE);
+
+    computed.data = malloc(hashsize);
+    if (computed.data == NULL) {
+       return(ENOMEM);
+    }
+    computed.length = hashsize;
+
+    if ((ret = krb5int_c_make_checksum_iov(&krb5_cksumtypes_list[i], key, usage,
+                                       data, num_data, &computed))) {
+       free(computed.data);
+       return(ret);
+    }
+
+    *valid = (memcmp(computed.data, &checksum->data, hashsize) == 0);
+
+    free(computed.data);
+
+    return(0);
+}
index 5a4e9557a05e169d201447ee2deb35f0ecadfd79..9eb81af7635d78bc14162c1bb007e005c1d37ad3 100644 (file)
@@ -53,6 +53,7 @@ krb5int_accessor(krb5int_access *internals, krb5_int32 version)
 #endif
            S (free_addrlist, krb5int_free_addrlist),
            S (krb5_hmac, krb5_hmac),
+           S (krb5_hmac_iov, krb5_hmac_iov),
            S (md5_hash_provider, &krb5int_hash_md5),
            S (arcfour_enc_provider, &krb5int_enc_arcfour),
            S (sendto_udp, &krb5int_sendto),