summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2008-12-02 20:10:20 +0000
committerSam Hartman <hartmans@mit.edu>2008-12-02 20:10:20 +0000
commitb5d22c309b734f6d3908fafa0e681ef7844ad9b3 (patch)
treecb6c8bae9acfc8e05bdcc5b156d4d9896c5e251d /src/lib
parentb282e93924be15445fb48ab186da737d62a003f6 (diff)
downloadkrb5-b5d22c309b734f6d3908fafa0e681ef7844ad9b3.tar.gz
krb5-b5d22c309b734f6d3908fafa0e681ef7844ad9b3.tar.xz
krb5-b5d22c309b734f6d3908fafa0e681ef7844ad9b3.zip
Crypto IOV API per Projects/AEAD encryption API
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
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/crypto/Makefile.in47
-rw-r--r--src/lib/crypto/aead.c431
-rw-r--r--src/lib/crypto/aead.h94
-rw-r--r--src/lib/crypto/arcfour/Makefile.in3
-rw-r--r--src/lib/crypto/arcfour/arcfour-int.h1
-rw-r--r--src/lib/crypto/arcfour/arcfour.c6
-rw-r--r--src/lib/crypto/arcfour/arcfour.h2
-rw-r--r--src/lib/crypto/arcfour/arcfour_aead.c325
-rw-r--r--src/lib/crypto/crypto_length.c192
-rw-r--r--src/lib/crypto/decrypt_iov.c61
-rw-r--r--src/lib/crypto/des/Makefile.in3
-rw-r--r--src/lib/crypto/des/d3_aead.c198
-rw-r--r--src/lib/crypto/des/des_int.h15
-rw-r--r--src/lib/crypto/dk/Makefile.in3
-rw-r--r--src/lib/crypto/dk/checksum.c71
-rw-r--r--src/lib/crypto/dk/dk.h12
-rw-r--r--src/lib/crypto/dk/dk_aead.c387
-rw-r--r--src/lib/crypto/enc_provider/aes.c177
-rw-r--r--src/lib/crypto/enc_provider/des3.c83
-rw-r--r--src/lib/crypto/enc_provider/enc_provider.h1
-rw-r--r--src/lib/crypto/enc_provider/rc4.c61
-rw-r--r--src/lib/crypto/encrypt_iov.c55
-rw-r--r--src/lib/crypto/etypes.c60
-rw-r--r--src/lib/crypto/hmac.c38
-rw-r--r--src/lib/crypto/keyhash_provider/descbc.c2
-rw-r--r--src/lib/crypto/keyhash_provider/hmac_md5.c61
-rw-r--r--src/lib/crypto/keyhash_provider/k5_md4des.c4
-rw-r--r--src/lib/crypto/keyhash_provider/k5_md5des.c4
-rw-r--r--src/lib/crypto/libk5crypto.exports8
-rw-r--r--src/lib/crypto/make_checksum_iov.c68
-rw-r--r--src/lib/crypto/t_encrypt.c45
-rw-r--r--src/lib/crypto/verify_checksum_iov.c92
-rw-r--r--src/lib/krb5/os/accessor.c1
33 files changed, 2561 insertions, 50 deletions
diff --git a/src/lib/crypto/Makefile.in b/src/lib/crypto/Makefile.in
index 2a3015adc4..a4ab872b0c 100644
--- a/src/lib/crypto/Makefile.in
+++ b/src/lib/crypto/Makefile.in
@@ -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
index 0000000000..6d042e60da
--- /dev/null
+++ b/src/lib/crypto/aead.c
@@ -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
index 0000000000..f183d1a05b
--- /dev/null
+++ b/src/lib/crypto/aead.h
@@ -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);
+
diff --git a/src/lib/crypto/arcfour/Makefile.in b/src/lib/crypto/arcfour/Makefile.in
index d03ca878a6..ff5b51dcfb 100644
--- a/src/lib/crypto/arcfour/Makefile.in
+++ b/src/lib/crypto/arcfour/Makefile.in
@@ -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)
diff --git a/src/lib/crypto/arcfour/arcfour-int.h b/src/lib/crypto/arcfour/arcfour-int.h
index 398fe57a1d..efd7a02829 100644
--- a/src/lib/crypto/arcfour/arcfour-int.h
+++ b/src/lib/crypto/arcfour/arcfour-int.h
@@ -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 */
diff --git a/src/lib/crypto/arcfour/arcfour.c b/src/lib/crypto/arcfour/arcfour.c
index a2df5ddf59..8c9e8e1a4e 100644
--- a/src/lib/crypto/arcfour/arcfour.c
+++ b/src/lib/crypto/arcfour/arcfour.c
@@ -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;
diff --git a/src/lib/crypto/arcfour/arcfour.h b/src/lib/crypto/arcfour/arcfour.h
index c6e4353348..e8ff203ca1 100644
--- a/src/lib/crypto/arcfour/arcfour.h
+++ b/src/lib/crypto/arcfour/arcfour.h
@@ -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
index 0000000000..40151d96be
--- /dev/null
+++ b/src/lib/crypto/arcfour/arcfour_aead.c
@@ -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
index 0000000000..4a64b90f91
--- /dev/null
+++ b/src/lib/crypto/crypto_length.c
@@ -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
index 0000000000..1a98b06570
--- /dev/null
+++ b/src/lib/crypto/decrypt_iov.c
@@ -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);
+}
+
diff --git a/src/lib/crypto/des/Makefile.in b/src/lib/crypto/des/Makefile.in
index 10660bbf40..6c5fc89ae1 100644
--- a/src/lib/crypto/des/Makefile.in
+++ b/src/lib/crypto/des/Makefile.in
@@ -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
index 0000000000..8463fc8837
--- /dev/null
+++ b/src/lib/crypto/des/d3_aead.c
@@ -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);
+}
diff --git a/src/lib/crypto/des/des_int.h b/src/lib/crypto/des/des_int.h
index c330a935ad..f040564499 100644
--- a/src/lib/crypto/des/des_int.h
+++ b/src/lib/crypto/des/des_int.h
@@ -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) \
diff --git a/src/lib/crypto/dk/Makefile.in b/src/lib/crypto/dk/Makefile.in
index 08393ba4a5..f8bfef139a 100644
--- a/src/lib/crypto/dk/Makefile.in
+++ b/src/lib/crypto/dk/Makefile.in
@@ -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 \
diff --git a/src/lib/crypto/dk/checksum.c b/src/lib/crypto/dk/checksum.c
index 2f30cb740d..a0ec05c5d5 100644
--- a/src/lib/crypto/dk/checksum.c
+++ b/src/lib/crypto/dk/checksum.c
@@ -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);
+}
+
diff --git a/src/lib/crypto/dk/dk.h b/src/lib/crypto/dk/dk.h
index 47bda6ebf2..a8def7a93d 100644
--- a/src/lib/crypto/dk/dk.h
+++ b/src/lib/crypto/dk/dk.h
@@ -85,6 +85,18 @@ krb5_error_code krb5_dk_make_checksum
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
index 0000000000..839b13344e
--- /dev/null
+++ b/src/lib/crypto/dk/dk_aead.c
@@ -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
+};
+
diff --git a/src/lib/crypto/enc_provider/aes.c b/src/lib/crypto/enc_provider/aes.c
index fde1a81f0e..e025cc3ebc 100644
--- a/src/lib/crypto/enc_provider/aes.c
+++ b/src/lib/crypto/enc_provider/aes.c
@@ -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]);
@@ -198,6 +199,169 @@ krb5int_aes_decrypt(const krb5_keyblock *key, const krb5_data *ivec,
}
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)
{
if (key->length != 16 && key->length != 32)
@@ -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
};
+
diff --git a/src/lib/crypto/enc_provider/des3.c b/src/lib/crypto/enc_provider/des3.c
index 51e4ce7967..e7a07f64cc 100644
--- a/src/lib/crypto/enc_provider/des3.c
+++ b/src/lib/crypto/enc_provider/des3.c
@@ -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,
@@ -54,6 +55,37 @@ validate_and_schedule(const krb5_keyblock *key, const krb5_data *ivec,
}
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
};
+
diff --git a/src/lib/crypto/enc_provider/enc_provider.h b/src/lib/crypto/enc_provider/enc_provider.h
index 5754d1a2d5..4c370c14dd 100644
--- a/src/lib/crypto/enc_provider/enc_provider.h
+++ b/src/lib/crypto/enc_provider/enc_provider.h
@@ -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;
+
diff --git a/src/lib/crypto/enc_provider/rc4.c b/src/lib/crypto/enc_provider/rc4.c
index a88ad79376..b950a605b8 100644
--- a/src/lib/crypto/enc_provider/rc4.c
+++ b/src/lib/crypto/enc_provider/rc4.c
@@ -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
index 0000000000..a35c5b5770
--- /dev/null
+++ b/src/lib/crypto/encrypt_iov.c
@@ -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);
+}
+
diff --git a/src/lib/crypto/etypes.c b/src/lib/crypto/etypes.c
index 4273e2826e..340fc31d33 100644
--- a/src/lib/crypto/etypes.c
+++ b/src/lib/crypto/etypes.c
@@ -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 =
diff --git a/src/lib/crypto/hmac.c b/src/lib/crypto/hmac.c
index 3c02726455..42785f5729 100644
--- a/src/lib/crypto/hmac.c
+++ b/src/lib/crypto/hmac.c
@@ -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;
+}
+
diff --git a/src/lib/crypto/keyhash_provider/descbc.c b/src/lib/crypto/keyhash_provider/descbc.c
index 23b33fc07d..bf68e324ce 100644
--- a/src/lib/crypto/keyhash_provider/descbc.c
+++ b/src/lib/crypto/keyhash_provider/descbc.c
@@ -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
};
diff --git a/src/lib/crypto/keyhash_provider/hmac_md5.c b/src/lib/crypto/keyhash_provider/hmac_md5.c
index a2472a8329..0f510925d9 100644
--- a/src/lib/crypto/keyhash_provider/hmac_md5.c
+++ b/src/lib/crypto/keyhash_provider/hmac_md5.c
@@ -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 */
};
diff --git a/src/lib/crypto/keyhash_provider/k5_md4des.c b/src/lib/crypto/keyhash_provider/k5_md4des.c
index 9f19f4f968..fceb58ebd4 100644
--- a/src/lib/crypto/keyhash_provider/k5_md4des.c
+++ b/src/lib/crypto/keyhash_provider/k5_md4des.c
@@ -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
};
diff --git a/src/lib/crypto/keyhash_provider/k5_md5des.c b/src/lib/crypto/keyhash_provider/k5_md5des.c
index e70965b791..0175c68ab7 100644
--- a/src/lib/crypto/keyhash_provider/k5_md5des.c
+++ b/src/lib/crypto/keyhash_provider/k5_md5des.c
@@ -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
};
diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
index d705a6b5f3..9fe8e69e15 100644
--- a/src/lib/crypto/libk5crypto.exports
+++ b/src/lib/crypto/libk5crypto.exports
@@ -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
index 0000000000..0d862c8352
--- /dev/null
+++ b/src/lib/crypto/make_checksum_iov.c
@@ -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);
+}
diff --git a/src/lib/crypto/t_encrypt.c b/src/lib/crypto/t_encrypt.c
index eb2378b5e5..ded1d8d982 100644
--- a/src/lib/crypto/t_encrypt.c
+++ b/src/lib/crypto/t_encrypt.c
@@ -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
index 0000000000..5627188dfb
--- /dev/null
+++ b/src/lib/crypto/verify_checksum_iov.c
@@ -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);
+}
diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c
index 5a4e9557a0..9eb81af763 100644
--- a/src/lib/krb5/os/accessor.c
+++ b/src/lib/krb5/os/accessor.c
@@ -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),