summaryrefslogtreecommitdiffstats
path: root/src/lib/crypto/krb
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2013-05-06 00:43:27 -0400
committerGreg Hudson <ghudson@mit.edu>2013-05-24 14:15:03 -0400
commit3b142e5746e7db1939a9cf8095faecfed6222054 (patch)
treeef9496f0e47a52e58a88b7f0aac8e3cc77fcf797 /src/lib/crypto/krb
parent48c9a082940373b82d4b8e3c338e9eb9d0d3c3f2 (diff)
downloadkrb5-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.c86
-rw-r--r--src/lib/crypto/krb/cmac.c18
-rw-r--r--src/lib/crypto/krb/crypto_int.h260
-rw-r--r--src/lib/crypto/krb/enc_old.c10
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);