aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2009-11-30 16:19:24 +0000
committerGreg Hudson <ghudson@mit.edu>2009-11-30 16:19:24 +0000
commit2b02e102d3c4e3bb54c936d301371d6b3d88cb52 (patch)
treed9ae2f2202a2a62b2e727167adbfb4fdfa3d4be1
parentc54198be3feb7c98aa632be7d4bf56e6002cfffc (diff)
downloadkrb5-2b02e102d3c4e3bb54c936d301371d6b3d88cb52.zip
krb5-2b02e102d3c4e3bb54c936d301371d6b3d88cb52.tar.gz
krb5-2b02e102d3c4e3bb54c936d301371d6b3d88cb52.tar.bz2
Add an AEAD provider for enctypes which use krb5_old_encrypt and
krb5_old_decrypt; this makes every enctype have an AEAD provider. To make this work, expose make_unkeyed_checksum_iov to other files (under the name krb5int_hash_iov) and make krb5int_c_padding_length take into account the header length. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23388 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/lib/crypto/krb/aead.c28
-rw-r--r--src/lib/crypto/krb/aead.h5
-rw-r--r--src/lib/crypto/krb/etypes.c8
-rw-r--r--src/lib/crypto/krb/old/Makefile.in10
-rw-r--r--src/lib/crypto/krb/old/old.h2
-rw-r--r--src/lib/crypto/krb/old/old_aead.c209
6 files changed, 245 insertions, 17 deletions
diff --git a/src/lib/crypto/krb/aead.c b/src/lib/crypto/krb/aead.c
index d6c5bbf..04fdab0 100644
--- a/src/lib/crypto/krb/aead.c
+++ b/src/lib/crypto/krb/aead.c
@@ -54,11 +54,11 @@ krb5int_c_locate_iov(krb5_crypto_iov *data,
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)
+/* Glue the IOV interface to the hash provider's old list-of-buffers. */
+krb5_error_code
+krb5int_hash_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;
@@ -125,8 +125,7 @@ krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum_type,
key, usage, data, num_data,
cksum_data);
} else {
- ret = make_unkeyed_checksum_iov(cksum_type->hash, data, num_data,
- cksum_data);
+ ret = krb5int_hash_iov(cksum_type->hash, data, num_data, cksum_data);
}
if (ret == 0) {
@@ -432,9 +431,22 @@ krb5int_c_padding_length(const struct krb5_aead_provider *aead,
size_t data_length,
unsigned int *pad_length)
{
- unsigned int padding;
+ unsigned int header, padding;
krb5_error_code ret;
+ /*
+ * Add in the header length since the header is encrypted along with the
+ * data. (arcfour violates this assumption since not all of the header is
+ * encrypted, but that's okay since it has no padding. If there is ever an
+ * enctype using a similar token format and a block cipher, we will have to
+ * move this logic into an enctype-dependent function.)
+ */
+ ret = (*aead->crypto_length)(aead, enc, hash, KRB5_CRYPTO_TYPE_HEADER,
+ &header);
+ if (ret != 0)
+ return ret;
+ data_length += header;
+
ret = (*aead->crypto_length)(aead, enc, hash, KRB5_CRYPTO_TYPE_PADDING,
&padding);
if (ret != 0)
diff --git a/src/lib/crypto/krb/aead.h b/src/lib/crypto/krb/aead.h
index fd06500..dcadfee 100644
--- a/src/lib/crypto/krb/aead.h
+++ b/src/lib/crypto/krb/aead.h
@@ -36,6 +36,11 @@ krb5int_c_locate_iov(krb5_crypto_iov *data,
krb5_cryptotype type);
krb5_error_code
+krb5int_hash_iov(const struct krb5_hash_provider *hash_provider,
+ const krb5_crypto_iov *data, size_t num_data,
+ krb5_data *output);
+
+krb5_error_code
krb5int_c_make_checksum_iov(const struct krb5_cksumtypes *cksum,
krb5_key key,
krb5_keyusage usage,
diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c
index bd9bb97..9e15034 100644
--- a/src/lib/crypto/krb/etypes.c
+++ b/src/lib/crypto/krb/etypes.c
@@ -52,7 +52,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
krb5int_des_string_to_key,
krb5int_des_prf,
CKSUMTYPE_RSA_MD5,
- NULL, /*AEAD*/
+ &krb5int_aead_old,
ETYPE_WEAK },
{ ENCTYPE_DES_CBC_MD4,
"des-cbc-md4", { 0 }, "DES cbc mode with RSA-MD4",
@@ -62,7 +62,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
krb5int_des_string_to_key,
krb5int_des_prf,
CKSUMTYPE_RSA_MD4,
- NULL, /*AEAD*/
+ &krb5int_aead_old,
ETYPE_WEAK },
{ ENCTYPE_DES_CBC_MD5,
"des-cbc-md5", { "des" }, "DES cbc mode with RSA-MD5",
@@ -72,7 +72,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
krb5int_des_string_to_key,
krb5int_des_prf,
CKSUMTYPE_RSA_MD5,
- NULL, /*AEAD*/
+ &krb5int_aead_old,
ETYPE_WEAK },
{ ENCTYPE_DES_CBC_RAW,
"des-cbc-raw", { 0 }, "DES cbc mode raw",
@@ -115,7 +115,7 @@ const struct krb5_keytypes krb5int_enctypes_list[] = {
krb5int_dk_string_to_key,
NULL, /*PRF*/
0,
- NULL,
+ &krb5int_aead_old,
ETYPE_WEAK },
{ ENCTYPE_ARCFOUR_HMAC,
"arcfour-hmac", { "rc4-hmac", "arcfour-hmac-md5" },
diff --git a/src/lib/crypto/krb/old/Makefile.in b/src/lib/crypto/krb/old/Makefile.in
index ea704cc..aadeacc 100644
--- a/src/lib/crypto/krb/old/Makefile.in
+++ b/src/lib/crypto/krb/old/Makefile.in
@@ -1,6 +1,6 @@
mydir=lib/crypto/krb/old
BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/../../@CRYPTO_IMPL@/des -I$(srcdir)
+LOCALINCLUDES = -I$(srcdir)/../../@CRYPTO_IMPL@/des -I$(srcdir)/.. -I$(srcdir)
DEFS=
##DOS##BUILDTOP = ..\..\..
@@ -12,12 +12,12 @@ PROG_RPATH=$(KRB5_LIBDIR)
RUN_SETUP = @KRB5_RUN_ENV@ KRB5_CONFIG=$(top_srcdir)/config-files/krb5.conf
-STLIBOBJS= old_decrypt.o old_encrypt.o des_stringtokey.o
+STLIBOBJS= old_aead.o old_decrypt.o old_encrypt.o des_stringtokey.o
-OBJS= $(OUTPRE)des_stringtokey.$(OBJEXT) $(OUTPRE)old_decrypt.$(OBJEXT) $(OUTPRE)old_encrypt.$(OBJEXT)
+OBJS= $(OUTPRE)des_stringtokey.$(OBJEXT) $(OUTPRE)old_aead.$(OBJEXT) $(OUTPRE)old_decrypt.$(OBJEXT) $(OUTPRE)old_encrypt.$(OBJEXT)
-SRCS= $(srcdir)/des_stringtokey.c $(srcdir)/old_decrypt.c \
- $(srcdir)/old_encrypt.c
+SRCS= $(srcdir)/des_stringtokey.c $(srcdir)/old_aead.c \
+ $(srcdir)/old_decrypt.c $(srcdir)/old_encrypt.c
##DOS##LIBOBJS = $(OBJS)
diff --git a/src/lib/crypto/krb/old/old.h b/src/lib/crypto/krb/old/old.h
index 1ed19a0..58f4f5a 100644
--- a/src/lib/crypto/krb/old/old.h
+++ b/src/lib/crypto/krb/old/old.h
@@ -49,3 +49,5 @@ krb5_error_code krb5int_des_string_to_key(const struct krb5_enc_provider *enc,
const krb5_data *salt,
const krb5_data *params,
krb5_keyblock *key);
+
+extern const struct krb5_aead_provider krb5int_aead_old;
diff --git a/src/lib/crypto/krb/old/old_aead.c b/src/lib/crypto/krb/old/old_aead.c
new file mode 100644
index 0000000..3dea3c3
--- /dev/null
+++ b/src/lib/crypto/krb/old/old_aead.c
@@ -0,0 +1,209 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * lib/crypto/old/old_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 "old.h"
+#include "aead.h"
+
+static krb5_error_code
+krb5int_old_crypto_length(const struct krb5_aead_provider *aead,
+ const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ krb5_cryptotype type,
+ unsigned int *length)
+{
+ switch (type) {
+ case KRB5_CRYPTO_TYPE_HEADER:
+ *length = enc->block_size + hash->hashsize;
+ break;
+ case KRB5_CRYPTO_TYPE_PADDING:
+ *length = enc->block_size;
+ 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_old_crypto_length");
+ break;
+ }
+
+ return 0;
+}
+
+static krb5_error_code
+krb5int_old_encrypt_iov(const struct krb5_aead_provider *aead,
+ const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ krb5_key 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, *padding;
+ krb5_data checksum, confounder, crcivec = empty_data();
+ unsigned int plainlen, padsize;
+ size_t i;
+
+ /* E(Confounder | Checksum | Plaintext | Pad) */
+
+ plainlen = enc->block_size + hash->hashsize;
+ for (i = 0; i < num_data; i++) {
+ krb5_crypto_iov *iov = &data[i];
+
+ if (iov->flags == KRB5_CRYPTO_TYPE_DATA)
+ plainlen += iov->data.length;
+ }
+
+ header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
+ if (header == NULL ||
+ header->data.length < enc->block_size + hash->hashsize)
+ return KRB5_BAD_MSIZE;
+
+ /* Trailer may be absent. */
+ trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
+ if (trailer != NULL)
+ trailer->data.length = 0;
+
+ /* Check that the input data is correctly padded. */
+ padsize = krb5_roundup(plainlen, enc->block_size) - plainlen;
+ padding = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_PADDING);
+ if (padsize > 0 && (padding == NULL || padding->data.length < padsize))
+ return KRB5_BAD_MSIZE;
+ if (padding) {
+ padding->data.length = padsize;
+ memset(padding->data.data, 0, padsize);
+ }
+
+ /* Generate a confounder in the header block. */
+ confounder = make_data(header->data.data, enc->block_size);
+ ret = krb5_c_random_make_octets(0, &confounder);
+ if (ret != 0)
+ goto cleanup;
+ checksum = make_data(header->data.data + enc->block_size, hash->hashsize);
+ memset(checksum.data, 0, hash->hashsize);
+
+ /* Checksum the plaintext with zeroed checksum and padding. */
+ ret = krb5int_hash_iov(hash, data, num_data, &checksum);
+ if (ret != 0)
+ goto cleanup;
+
+ /* Use the key as the ivec for des-cbc-crc if none was provided. */
+ if (key->keyblock.enctype == ENCTYPE_DES_CBC_CRC && ivec == NULL) {
+ ret = alloc_data(&crcivec, key->keyblock.length);
+ memcpy(crcivec.data, key->keyblock.contents, key->keyblock.length);
+ ivec = &crcivec;
+ }
+
+ ret = enc->encrypt_iov(key, ivec, data, num_data);
+ if (ret != 0)
+ goto cleanup;
+
+cleanup:
+ zapfree(crcivec.data, crcivec.length);
+ return ret;
+}
+
+static krb5_error_code
+krb5int_old_decrypt_iov(const struct krb5_aead_provider *aead,
+ const struct krb5_enc_provider *enc,
+ const struct krb5_hash_provider *hash,
+ krb5_key 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_data checksum, crcivec = empty_data();
+ char *saved_checksum = NULL;
+ size_t i;
+ unsigned int cipherlen = 0;
+
+ /* Check that the input data is correctly padded. */
+ for (i = 0; i < num_data; i++) {
+ const krb5_crypto_iov *iov = &data[i];
+
+ if (ENCRYPT_IOV(iov))
+ cipherlen += iov->data.length;
+ }
+ if (cipherlen % enc->block_size != 0)
+ return KRB5_BAD_MSIZE;
+
+ header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER);
+ if (header == NULL ||
+ header->data.length != enc->block_size + hash->hashsize)
+ return KRB5_BAD_MSIZE;
+
+ trailer = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_TRAILER);
+ if (trailer != NULL && trailer->data.length != 0)
+ return KRB5_BAD_MSIZE;
+
+ /* Use the key as the ivec for des-cbc-crc if none was provided. */
+ if (key->keyblock.enctype == ENCTYPE_DES_CBC_CRC && ivec == NULL) {
+ ret = alloc_data(&crcivec, key->keyblock.length);
+ memcpy(crcivec.data, key->keyblock.contents, key->keyblock.length);
+ ivec = &crcivec;
+ }
+
+ /* Decrypt the ciphertext. */
+ ret = enc->decrypt_iov(key, ivec, data, num_data);
+ if (ret != 0)
+ goto cleanup;
+
+ /* Save the checksum, then zero it out in the plaintext. */
+ checksum = make_data(header->data.data + enc->block_size, hash->hashsize);
+ saved_checksum = k5alloc(hash->hashsize, &ret);
+ if (saved_checksum == NULL)
+ goto cleanup;
+ memcpy(saved_checksum, checksum.data, checksum.length);
+ memset(checksum.data, 0, checksum.length);
+
+ /*
+ * Checksum the plaintext (with zeroed checksum field), storing the result
+ * back into the plaintext field we just zeroed out. Then compare it to
+ * the saved checksum.
+ */
+ ret = krb5int_hash_iov(hash, data, num_data, &checksum);
+ if (memcmp(checksum.data, saved_checksum, checksum.length) != 0) {
+ ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ goto cleanup;
+ }
+
+cleanup:
+ zapfree(crcivec.data, crcivec.length);
+ zapfree(saved_checksum, hash->hashsize);
+ return ret;
+}
+
+const struct krb5_aead_provider krb5int_aead_old = {
+ krb5int_old_crypto_length,
+ krb5int_old_encrypt_iov,
+ krb5int_old_decrypt_iov
+};