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;
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) {
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)
--- /dev/null
+/* -*- 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
+};