diff options
| author | Greg Hudson <ghudson@mit.edu> | 2013-05-06 00:43:27 -0400 |
|---|---|---|
| committer | Greg Hudson <ghudson@mit.edu> | 2013-05-24 14:15:03 -0400 |
| commit | 3b142e5746e7db1939a9cf8095faecfed6222054 (patch) | |
| tree | ef9496f0e47a52e58a88b7f0aac8e3cc77fcf797 /src/lib/crypto/krb | |
| parent | 48c9a082940373b82d4b8e3c338e9eb9d0d3c3f2 (diff) | |
| download | krb5-3b142e5746e7db1939a9cf8095faecfed6222054.tar.gz krb5-3b142e5746e7db1939a9cf8095faecfed6222054.tar.xz krb5-3b142e5746e7db1939a9cf8095faecfed6222054.zip | |
Simplify crypto IOV helpers
Expand the concept of an IOV block state into a cursor which remembers
the IOV set being iterated over, the block size, and both input and
output positions. Eliminate the no-copy inline block getter for now,
but provide helpers to grab contiguous chains of blocks from a cursor.
Also provide an inline helper to sum the total length of an iov chain.
Diffstat (limited to 'src/lib/crypto/krb')
| -rw-r--r-- | src/lib/crypto/krb/aead.c | 86 | ||||
| -rw-r--r-- | src/lib/crypto/krb/cmac.c | 18 | ||||
| -rw-r--r-- | src/lib/crypto/krb/crypto_int.h | 260 | ||||
| -rw-r--r-- | src/lib/crypto/krb/enc_old.c | 10 |
4 files changed, 138 insertions, 236 deletions
diff --git a/src/lib/crypto/krb/aead.c b/src/lib/crypto/krb/aead.c index 7bfed4b1e..935125d9d 100644 --- a/src/lib/crypto/krb/aead.c +++ b/src/lib/crypto/krb/aead.c @@ -135,3 +135,89 @@ krb5int_c_padding_length(const struct krb5_keytypes *ktp, size_t data_length) else return padding - (data_length % padding); } + +/* Return the next iov (starting from ind) which cursor should process, or + * cursor->iov_count if there are none remaining. */ +static size_t +next_iov_to_process(struct iov_cursor *cursor, size_t ind) +{ + krb5_crypto_iov *iov; + + for (; ind < cursor->iov_count; ind++) { + iov = &cursor->iov[ind]; + if (cursor->signing ? SIGN_IOV(iov) : ENCRYPT_IOV(iov)) + break; + } + return ind; +} + +void +k5_iov_cursor_init(struct iov_cursor *cursor, const krb5_crypto_iov *iov, + size_t count, size_t block_size, krb5_boolean signing) +{ + cursor->iov = iov; + cursor->iov_count = count; + cursor->block_size = block_size; + cursor->signing = signing; + cursor->in_iov = next_iov_to_process(cursor, 0); + cursor->out_iov = cursor->in_iov; + cursor->in_pos = cursor->out_pos = 0; +} + +/* Fetch one block from cursor's input position. */ +krb5_boolean +k5_iov_cursor_get(struct iov_cursor *cursor, unsigned char *block) +{ + size_t nbytes, bsz = cursor->block_size, remain = cursor->block_size; + const krb5_crypto_iov *iov; + + remain = cursor->block_size; + while (remain > 0 && cursor->in_iov < cursor->iov_count) { + iov = &cursor->iov[cursor->in_iov]; + + nbytes = iov->data.length - cursor->in_pos; + if (nbytes > remain) + nbytes = remain; + + memcpy(block + bsz - remain, iov->data.data + cursor->in_pos, nbytes); + cursor->in_pos += nbytes; + remain -= nbytes; + + if (cursor->in_pos == iov->data.length) { + cursor->in_iov = next_iov_to_process(cursor, cursor->in_iov + 1); + cursor->in_pos = 0; + } + } + + if (remain == bsz) + return FALSE; + if (remain > 0) + memset(block + bsz - remain, 0, remain); + return TRUE; +} + +/* Write a block to a cursor's output position. */ +void +k5_iov_cursor_put(struct iov_cursor *cursor, unsigned char *block) +{ + size_t nbytes, bsz = cursor->block_size, remain = cursor->block_size; + const krb5_crypto_iov *iov; + + remain = cursor->block_size; + while (remain > 0 && cursor->out_iov < cursor->iov_count) { + iov = &cursor->iov[cursor->out_iov]; + + nbytes = iov->data.length - cursor->out_pos; + if (nbytes > remain) + nbytes = remain; + + memcpy(iov->data.data + cursor->out_pos, block + bsz - remain, nbytes); + cursor->out_pos += nbytes; + remain -= nbytes; + + if (cursor->out_pos == iov->data.length) { + cursor->out_iov = next_iov_to_process(cursor, cursor->out_iov + 1); + cursor->out_pos = 0; + } + } +} diff --git a/src/lib/crypto/krb/cmac.c b/src/lib/crypto/krb/cmac.c index 2e220c5d5..066b534d1 100644 --- a/src/lib/crypto/krb/cmac.c +++ b/src/lib/crypto/krb/cmac.c @@ -145,8 +145,8 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, unsigned char input[BLOCK_SIZE]; unsigned int n, i, flag; krb5_error_code ret; - struct iov_block_state iov_state; - unsigned int length; + struct iov_cursor cursor; + size_t length; krb5_crypto_iov iov[1]; krb5_data d; @@ -155,12 +155,7 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, if (enc->block_size != BLOCK_SIZE) return KRB5_BAD_MSIZE; - for (i = 0, length = 0; i < num_data; i++) { - const krb5_crypto_iov *piov = &data[i]; - - if (SIGN_IOV(piov)) - length += piov->data.length; - } + length = iov_total_length(data, num_data, TRUE); /* Step 1. */ ret = generate_subkey(enc, key, K1, K2); @@ -186,10 +181,9 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, d = make_data(Y, BLOCK_SIZE); /* Step 6 (all but last block). */ - IOV_BLOCK_STATE_INIT(&iov_state); - iov_state.include_sign_only = 1; + k5_iov_cursor_init(&cursor, data, num_data, BLOCK_SIZE, TRUE); for (i = 0; i < n - 1; i++) { - krb5int_c_iov_get_block(input, BLOCK_SIZE, data, num_data, &iov_state); + k5_iov_cursor_get(&cursor, input); ret = enc->cbc_mac(key, iov, 1, &d, &d); if (ret != 0) @@ -197,7 +191,7 @@ krb5int_cmac_checksum(const struct krb5_enc_provider *enc, krb5_key key, } /* Step 4. */ - krb5int_c_iov_get_block(input, BLOCK_SIZE, data, num_data, &iov_state); + k5_iov_cursor_get(&cursor, input); if (flag) { /* last block is complete block */ xor_128(input, K1, M_last); diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h index 01090d006..c2c6344bc 100644 --- a/src/lib/crypto/krb/crypto_int.h +++ b/src/lib/crypto/krb/crypto_int.h @@ -381,20 +381,17 @@ void krb5int_default_free_state(krb5_data *state); #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 */ +struct iov_cursor { + const krb5_crypto_iov *iov; /* iov array we are iterating over */ + size_t iov_count; /* size of iov array */ + size_t block_size; /* size of blocks we will be obtaining */ + krb5_boolean signing; /* should we process SIGN_ONLY blocks */ + size_t in_iov; /* read index into iov array */ + size_t in_pos; /* read index into iov contents */ + size_t out_iov; /* write index into iov array */ + size_t out_pos; /* write index into iov contents */ }; -#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_crypto_iov *krb5int_c_locate_iov(krb5_crypto_iov *data, size_t num_data, krb5_cryptotype type); @@ -408,6 +405,14 @@ krb5_error_code krb5int_c_iov_decrypt_stream(const struct krb5_keytypes *ktp, unsigned int krb5int_c_padding_length(const struct krb5_keytypes *ktp, size_t data_length); +void k5_iov_cursor_init(struct iov_cursor *cursor, const krb5_crypto_iov *iov, + size_t count, size_t block_size, krb5_boolean signing); + +krb5_boolean k5_iov_cursor_get(struct iov_cursor *cursor, + unsigned char *block); + +void k5_iov_cursor_put(struct iov_cursor *cursor, unsigned char *block); + /*** Crypto module declarations ***/ /* Modules must implement the following enc_providers and hash_providers: */ @@ -580,225 +585,50 @@ encrypt_block(const struct krb5_enc_provider *enc, krb5_key key, return enc->encrypt(key, 0, &iov, 1); } -/* Decide whether to process an IOV block. */ -static inline 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 inline 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; -} - -/* - * Retrieve a block from the IOV. If p is non-NULL and the next block is - * completely contained within the current buffer, then *p will contain an - * alias into the buffer; otherwise, a copy will be made into storage. - * - * After calling this function, encrypt the returned block and then call - * krb5int_c_iov_put_block_nocopy() (with a separate output cursor). If - * p was non-NULL on the call to get_block(), then pass that pointer in. - */ -static inline krb5_boolean -krb5int_c_iov_get_block_nocopy(unsigned char *storage, - size_t block_size, - const krb5_crypto_iov *data, - size_t num_data, - struct iov_block_state *iov_state, - unsigned char **p) +/* Return the total length of the to-be-signed or to-be-encrypted buffers in an + * iov chain. */ +static inline size_t +iov_total_length(const krb5_crypto_iov *data, size_t num_data, + krb5_boolean signing) { - size_t i, j = 0; - - if (p != NULL) - *p = storage; - - 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; - - /* - * If we can return a pointer into a complete block, then do so. - */ - if (p != NULL && j == 0 && nbytes == block_size) { - *p = (unsigned char *)iov->data.data + iov_state->data_pos; - } else { - memcpy(storage + j, iov->data.data + iov_state->data_pos, nbytes); - } + size_t i, total = 0; - 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; + for (i = 0; i < num_data; i++) { + if (signing ? SIGN_IOV(&data[i]) : ENCRYPT_IOV(&data[i])) + total += data[i].data.length; } - - iov_state->iov_pos = i; - - if (j == 0) - return FALSE; - else if (j != block_size) - memset(storage + j, 0, block_size - j); - - return TRUE; + return total; } /* - * Store a block retrieved with krb5int_c_iov_get_block_no_copy if - * necessary, and advance the output cursor. + * Return the number of contiguous blocks available within the current input + * IOV of the cursor c, so that the caller can do in-place encryption. + * Do not call if c might be exhausted. */ -static inline krb5_boolean -krb5int_c_iov_put_block_nocopy(const krb5_crypto_iov *data, - size_t num_data, - unsigned char *storage, - size_t block_size, - struct iov_block_state *iov_state, - unsigned char *p) +static inline size_t +iov_cursor_contig_blocks(struct iov_cursor *c) { - size_t i, j = 0; - - assert(p != NULL); - - 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; - - /* - * If we had previously returned a pointer into a complete block, - * then no action is required. - */ - if (p == storage) { - memcpy(iov->data.data + iov_state->data_pos, storage + j, nbytes); - } else { - /* Ensure correctly paired with a call to get_block_nocopy(). */ - assert(j == 0); - assert(nbytes == 0 || nbytes == block_size); - } - - 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 - dump_block("put_block", i, j, p, block_size); -#endif - - return (iov_state->iov_pos < num_data); + return (c->iov[c->in_iov].data.length - c->in_pos) / c->block_size; } -/* - * A wrapper for krb5int_c_iov_get_block_nocopy() that always makes - * a copy. - */ -static inline krb5_boolean -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) +/* Return the current input pointer within the cursor c. Do not call if c + * might be exhausted. */ +static inline unsigned char * +iov_cursor_ptr(struct iov_cursor *c) { - return krb5int_c_iov_get_block_nocopy(block, block_size, data, num_data, - iov_state, NULL); + return (unsigned char *)&c->iov[c->in_iov].data.data[c->in_pos]; } /* - * A wrapper for krb5int_c_iov_put_block_nocopy() that always copies - * the block. + * Advance the input and output pointers of c by nblocks blocks. nblocks must + * not be greater than the return value of iov_cursor_contig_blocks, and the + * input and output positions must be identical. */ -static inline krb5_boolean -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) +static inline void +iov_cursor_advance(struct iov_cursor *c, size_t nblocks) { - return krb5int_c_iov_put_block_nocopy(data, num_data, block, block_size, - iov_state, block); + c->in_pos += nblocks * c->block_size; + c->out_pos += nblocks * c->block_size; } #endif /* CRYPTO_INT_H */ diff --git a/src/lib/crypto/krb/enc_old.c b/src/lib/crypto/krb/enc_old.c index b44a3994f..a40f70942 100644 --- a/src/lib/crypto/krb/enc_old.c +++ b/src/lib/crypto/krb/enc_old.c @@ -130,17 +130,9 @@ krb5int_old_decrypt(const struct krb5_keytypes *ktp, krb5_key key, 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) + if (iov_total_length(data, num_data, FALSE) % enc->block_size != 0) return KRB5_BAD_MSIZE; header = krb5int_c_locate_iov(data, num_data, KRB5_CRYPTO_TYPE_HEADER); |
