summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/enc_provider
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/crypto/enc_provider
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/crypto/enc_provider')
-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
4 files changed, 316 insertions, 6 deletions
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
};
+