diff options
author | Sam Hartman <hartmans@mit.edu> | 2008-12-02 20:10:20 +0000 |
---|---|---|
committer | Sam Hartman <hartmans@mit.edu> | 2008-12-02 20:10:20 +0000 |
commit | b5d22c309b734f6d3908fafa0e681ef7844ad9b3 (patch) | |
tree | cb6c8bae9acfc8e05bdcc5b156d4d9896c5e251d /src/lib/crypto/enc_provider | |
parent | b282e93924be15445fb48ab186da737d62a003f6 (diff) | |
download | krb5-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.c | 177 | ||||
-rw-r--r-- | src/lib/crypto/enc_provider/des3.c | 83 | ||||
-rw-r--r-- | src/lib/crypto/enc_provider/enc_provider.h | 1 | ||||
-rw-r--r-- | src/lib/crypto/enc_provider/rc4.c | 61 |
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 }; + |