From: Michael Brown Date: Fri, 19 Jun 2026 12:26:00 +0000 (+0100) Subject: [crypto] Use private data field for cipher algorithms X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;p=thirdparty%2Fipxe.git [crypto] Use private data field for cipher algorithms Following the example of commit 25072c1 ("[crypto] Use private data field for key exchange algorithms"), extend the definition of a cipher algorithm to include an opaque private data field, and use this to eliminate the wrapper functions generated for the various block cipher modes of operation by ECB_CIPHER(), CBC_CIPHER(), and GCM_CIPHER(). Signed-off-by: Michael Brown --- diff --git a/src/crypto/aes.c b/src/crypto/aes.c index fe6ccb222..c98361474 100644 --- a/src/crypto/aes.c +++ b/src/crypto/aes.c @@ -391,12 +391,14 @@ static void aes_final ( const struct aes_table *table, size_t stride, /** * Encrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to encrypt * @v dst Buffer for encrypted data * @v len Length of data */ -static void aes_encrypt ( void *ctx, const void *src, void *dst, size_t len ) { +static void aes_encrypt ( struct cipher_algorithm *cipher __unused, void *ctx, + const void *src, void *dst, size_t len ) { struct aes_context *aes = ctx; union aes_matrix buffer[2]; union aes_matrix *in = &buffer[0]; @@ -427,12 +429,14 @@ static void aes_encrypt ( void *ctx, const void *src, void *dst, size_t len ) { /** * Decrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to decrypt * @v dst Buffer for decrypted data * @v len Length of data */ -static void aes_decrypt ( void *ctx, const void *src, void *dst, size_t len ) { +static void aes_decrypt ( struct cipher_algorithm *cipher __unused, void *ctx, + const void *src, void *dst, size_t len ) { struct aes_context *aes = ctx; union aes_matrix buffer[2]; union aes_matrix *in = &buffer[0]; @@ -674,12 +678,14 @@ aes_key_rcon ( uint32_t column, unsigned int rcon ) { /** * Set key * + * @v cipher Cipher algorithm * @v ctx Context * @v key Key * @v keylen Key length * @ret rc Return status code */ -static int aes_setkey ( void *ctx, const void *key, size_t keylen ) { +static int aes_setkey ( struct cipher_algorithm *cipher __unused, void *ctx, + const void *key, size_t keylen ) { struct aes_context *aes = ctx; union aes_matrix *enc; union aes_matrix *dec; diff --git a/src/crypto/arc4.c b/src/crypto/arc4.c index 3b6adec19..2866688eb 100644 --- a/src/crypto/arc4.c +++ b/src/crypto/arc4.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Set ARC4 key * + * @v cipher Cipher algorithm * @v ctxv ARC4 encryption context * @v keyv Key to set * @v keylen Length of key @@ -39,7 +40,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); * there is no standard length for an initialisation vector in the * cipher. */ -static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen ) +static int arc4_setkey ( struct cipher_algorithm *cipher __unused, void *ctxv, + const void *keyv, size_t keylen ) { struct arc4_ctx *ctx = ctxv; const u8 *key = keyv; @@ -62,6 +64,7 @@ static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen ) /** * Perform ARC4 encryption or decryption * + * @v cipher Cipher algorithm * @v ctxv ARC4 encryption context * @v srcv Data to encrypt or decrypt * @v dstv Location to store encrypted or decrypted data @@ -75,8 +78,8 @@ static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen ) * If you pass a @c NULL source or destination pointer, @a len * keystream bytes will be consumed without encrypting any data. */ -static void arc4_xor ( void *ctxv, const void *srcv, void *dstv, - size_t len ) +static void arc4_xor ( struct cipher_algorithm *cipher __unused, void *ctxv, + const void *srcv, void *dstv, size_t len ) { struct arc4_ctx *ctx = ctxv; const u8 *src = srcv; @@ -109,10 +112,12 @@ static void arc4_xor ( void *ctxv, const void *srcv, void *dstv, void arc4_skip ( const void *key, size_t keylen, size_t skip, const void *src, void *dst, size_t msglen ) { + struct cipher_algorithm *cipher = &arc4_algorithm; struct arc4_ctx ctx; - arc4_setkey ( &ctx, key, keylen ); - arc4_xor ( &ctx, NULL, NULL, skip ); - arc4_xor ( &ctx, src, dst, msglen ); + + arc4_setkey ( cipher, &ctx, key, keylen ); + arc4_xor ( cipher, &ctx, NULL, NULL, skip ); + arc4_xor ( cipher, &ctx, src, dst, msglen ); } struct cipher_algorithm arc4_algorithm = { diff --git a/src/crypto/cbc.c b/src/crypto/cbc.c index ddba7abd9..ff45dd9e8 100644 --- a/src/crypto/cbc.c +++ b/src/crypto/cbc.c @@ -35,6 +35,43 @@ FILE_SECBOOT ( PERMITTED ); * */ +/** + * Set key + * + * @v cipher Cipher algorithm + * @v ctx Context + * @v key Key + * @v keylen Key length + * @ret rc Return status code + */ +int cbc_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + size_t blocksize = cipher->blocksize; + size_t ctxsize = cipher->ctxsize; + cbc_context_t ( blocksize, ctxsize ) *context = ctx; + + return cipher_setkey ( raw_cipher, context->raw, key, keylen ); +} + +/** + * Set initialisation vector + * + * @v cipher Cipher algorithm + * @v ctx Context + * @v iv Initialisation vector + * @v ivlen Initialisation vector length + */ +void cbc_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ) { + size_t blocksize = cipher->blocksize; + size_t ctxsize = cipher->ctxsize; + cbc_context_t ( blocksize, ctxsize ) *context = ctx; + + assert ( ivlen == sizeof ( context->cbc ) ); + memcpy ( context->cbc, iv, sizeof ( context->cbc ) ); +} + /** * XOR data blocks * @@ -57,23 +94,26 @@ static void cbc_xor ( const void *src, void *dst, size_t len ) { /** * Encrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to encrypt * @v dst Buffer for encrypted data * @v len Length of data - * @v raw_cipher Underlying cipher algorithm - * @v cbc_ctx CBC context */ -void cbc_encrypt ( void *ctx, const void *src, void *dst, size_t len, - struct cipher_algorithm *raw_cipher, void *cbc_ctx ) { - size_t blocksize = raw_cipher->blocksize; +void cbc_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + size_t blocksize = cipher->blocksize; + size_t ctxsize = cipher->ctxsize; + cbc_context_t ( blocksize, ctxsize ) *context = ctx; assert ( ( len % blocksize ) == 0 ); while ( len ) { - cbc_xor ( src, cbc_ctx, blocksize ); - cipher_encrypt ( raw_cipher, ctx, cbc_ctx, dst, blocksize ); - memcpy ( cbc_ctx, dst, blocksize ); + cbc_xor ( src, context->cbc, blocksize ); + cipher_encrypt ( raw_cipher, context->raw, context->cbc, dst, + blocksize ); + memcpy ( context->cbc, dst, blocksize ); dst += blocksize; src += blocksize; len -= blocksize; @@ -83,25 +123,28 @@ void cbc_encrypt ( void *ctx, const void *src, void *dst, size_t len, /** * Decrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to decrypt * @v dst Buffer for decrypted data * @v len Length of data - * @v raw_cipher Underlying cipher algorithm - * @v cbc_ctx CBC context */ -void cbc_decrypt ( void *ctx, const void *src, void *dst, size_t len, - struct cipher_algorithm *raw_cipher, void *cbc_ctx ) { - size_t blocksize = raw_cipher->blocksize; +void cbc_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + size_t blocksize = cipher->blocksize; + size_t ctxsize = cipher->ctxsize; + cbc_context_t ( blocksize, ctxsize ) *context = ctx; uint8_t next_cbc_ctx[blocksize]; assert ( ( len % blocksize ) == 0 ); while ( len ) { memcpy ( next_cbc_ctx, src, blocksize ); - cipher_decrypt ( raw_cipher, ctx, src, dst, blocksize ); - cbc_xor ( cbc_ctx, dst, blocksize ); - memcpy ( cbc_ctx, next_cbc_ctx, blocksize ); + cipher_decrypt ( raw_cipher, context->raw, src, dst, + blocksize ); + cbc_xor ( context->cbc, dst, blocksize ); + memcpy ( context->cbc, next_cbc_ctx, blocksize ); dst += blocksize; src += blocksize; len -= blocksize; diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index 93580bb88..5d0531f11 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -60,28 +60,33 @@ struct digest_algorithm digest_null = { .final = digest_null_final, }; -int cipher_null_setkey ( void *ctx __unused, const void *key __unused, +int cipher_null_setkey ( struct cipher_algorithm *cipher __unused, + void *ctx __unused, const void *key __unused, size_t keylen __unused ) { /* Do nothing */ return 0; } -void cipher_null_setiv ( void *ctx __unused, const void *iv __unused, +void cipher_null_setiv ( struct cipher_algorithm *cipher __unused, + void *ctx __unused, const void *iv __unused, size_t ivlen __unused ) { /* Do nothing */ } -void cipher_null_encrypt ( void *ctx __unused, const void *src, void *dst, +void cipher_null_encrypt ( struct cipher_algorithm *cipher __unused, + void *ctx __unused, const void *src, void *dst, size_t len ) { memcpy ( dst, src, len ); } -void cipher_null_decrypt ( void *ctx __unused, const void *src, void *dst, +void cipher_null_decrypt ( struct cipher_algorithm *cipher __unused, + void *ctx __unused, const void *src, void *dst, size_t len ) { memcpy ( dst, src, len ); } -void cipher_null_auth ( void *ctx __unused, void *auth __unused ) { +void cipher_null_auth ( struct cipher_algorithm *cipher __unused, + void *ctx __unused, void *auth __unused ) { /* Do nothing */ } diff --git a/src/crypto/des.c b/src/crypto/des.c index a7fad9829..938643e1b 100644 --- a/src/crypto/des.c +++ b/src/crypto/des.c @@ -580,12 +580,14 @@ static uint32_t des_rol28 ( uint32_t dword ) { /** * Set key * + * @v cipher Cipher algorithm * @v ctx Context * @v key Key * @v keylen Key length * @ret rc Return status code */ -static int des_setkey ( void *ctx, const void *key, size_t keylen ) { +static int des_setkey ( struct cipher_algorithm *cipher __unused, void *ctx, + const void *key, size_t keylen ) { struct des_context *des = ctx; union des_round_key *rkey = des->rkey; union des_block reg; @@ -640,12 +642,14 @@ static int des_setkey ( void *ctx, const void *key, size_t keylen ) { /** * Encrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to encrypt * @v dst Buffer for encrypted data * @v len Length of data */ -static void des_encrypt ( void *ctx, const void *src, void *dst, size_t len ) { +static void des_encrypt ( struct cipher_algorithm *cipher __unused, void *ctx, + const void *src, void *dst, size_t len ) { struct des_context *des = ctx; /* Sanity check */ @@ -658,12 +662,14 @@ static void des_encrypt ( void *ctx, const void *src, void *dst, size_t len ) { /** * Decrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to decrypt * @v dst Buffer for decrypted data * @v len Length of data */ -static void des_decrypt ( void *ctx, const void *src, void *dst, size_t len ) { +static void des_decrypt ( struct cipher_algorithm *cipher __unused, void *ctx, + const void *src, void *dst, size_t len ) { struct des_context *des = ctx; /* Sanity check */ diff --git a/src/crypto/ecb.c b/src/crypto/ecb.c index 73eef09c2..754900cae 100644 --- a/src/crypto/ecb.c +++ b/src/crypto/ecb.c @@ -34,17 +34,34 @@ FILE_SECBOOT ( PERMITTED ); * */ +/** + * Set key + * + * @v cipher Cipher algorithm + * @v ctx Context + * @v key Key + * @v keylen Key length + * @ret rc Return status code + */ +int ecb_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + + return cipher_setkey ( raw_cipher, ctx, key, keylen ); +} + /** * Encrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to encrypt * @v dst Buffer for encrypted data * @v len Length of data - * @v raw_cipher Underlying cipher algorithm */ -void ecb_encrypt ( void *ctx, const void *src, void *dst, size_t len, - struct cipher_algorithm *raw_cipher ) { +void ecb_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + struct cipher_algorithm *raw_cipher = cipher->priv; size_t blocksize = raw_cipher->blocksize; assert ( ( len % blocksize ) == 0 ); @@ -60,14 +77,15 @@ void ecb_encrypt ( void *ctx, const void *src, void *dst, size_t len, /** * Decrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to decrypt * @v dst Buffer for decrypted data * @v len Length of data - * @v raw_cipher Underlying cipher algorithm */ -void ecb_decrypt ( void *ctx, const void *src, void *dst, size_t len, - struct cipher_algorithm *raw_cipher ) { +void ecb_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + struct cipher_algorithm *raw_cipher = cipher->priv; size_t blocksize = raw_cipher->blocksize; assert ( ( len % blocksize ) == 0 ); diff --git a/src/crypto/gcm.c b/src/crypto/gcm.c index b9c9d3a39..c0e32a320 100644 --- a/src/crypto/gcm.c +++ b/src/crypto/gcm.c @@ -309,30 +309,55 @@ static void gcm_multiply_key ( const union gcm_block *key, } /** - * Encrypt/decrypt/authenticate data + * Construct hash * * @v context Context + * @v hash Hash to fill in + */ +static void gcm_hash ( struct gcm_context *context, union gcm_block *hash ) { + + /* Construct big-endian lengths block */ + hash->len.add = cpu_to_be64 ( context->len.len.add ); + hash->len.data = cpu_to_be64 ( context->len.len.data ); + DBGC2 ( context, "GCM %p len(A)||len(C):\n", context ); + DBGC2_HDA ( context, 0, hash, sizeof ( *hash ) ); + + /* Update hash */ + gcm_xor_block ( &context->hash, hash ); + gcm_multiply_key ( &context->key, hash ); + DBGC2 ( context, "GCM %p GHASH(H,A,C):\n", context ); + DBGC2_HDA ( context, 0, hash, sizeof ( *hash ) ); +} + +/** + * Encrypt/decrypt/authenticate data + * + * @v cipher Cipher algorithm + * @v ctx Context * @v src Input data * @v dst Output data, or NULL to process additional data * @v len Length of data * @v flags Operation flags */ -static void gcm_process ( struct gcm_context *context, const void *src, - void *dst, size_t len, unsigned int flags ) { +static void gcm_process ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + gcm_context_t ( cipher->ctxsize ) *context = ctx; + unsigned int flags = context->gcm.flags; union gcm_block tmp; uint64_t *total; size_t frag_len; unsigned int block; /* Calculate block number (for debugging) */ - block = ( ( ( context->len.len.add + 8 * sizeof ( tmp ) - 1 ) / + block = ( ( ( context->gcm.len.len.add + 8 * sizeof ( tmp ) - 1 ) / ( 8 * sizeof ( tmp ) ) ) + - ( ( context->len.len.data + 8 * sizeof ( tmp ) - 1 ) / + ( ( context->gcm.len.len.data + 8 * sizeof ( tmp ) - 1 ) / ( 8 * sizeof ( tmp ) ) ) + 1 ); /* Update total length (in bits) */ total = ( ( dst || ( flags & GCM_FL_IV ) ) ? - &context->len.len.data : &context->len.len.add ); + &context->gcm.len.len.data : &context->gcm.len.len.add ); *total += ( len * 8 ); /* Process data */ @@ -344,20 +369,22 @@ static void gcm_process ( struct gcm_context *context, const void *src, frag_len = sizeof ( tmp ); /* Update hash with input data */ - gcm_xor ( src, &context->hash, &context->hash, frag_len ); + gcm_xor ( src, &context->gcm.hash, &context->gcm.hash, + frag_len ); /* Encrypt/decrypt block, if applicable */ if ( dst ) { /* Increment counter */ - gcm_count ( &context->ctr, 1 ); + gcm_count ( &context->gcm.ctr, 1 ); /* Encrypt counter */ DBGC2 ( context, "GCM %p Y[%d]:\n", context, block ); - DBGC2_HDA ( context, 0, &context->ctr, - sizeof ( context->ctr ) ); - cipher_encrypt ( context->raw_cipher, &context->raw_ctx, - &context->ctr, &tmp, sizeof ( tmp ) ); + DBGC2_HDA ( context, 0, &context->gcm.ctr, + sizeof ( context->gcm.ctr ) ); + cipher_encrypt ( raw_cipher, &context->raw, + &context->gcm.ctr, &tmp, + sizeof ( tmp ) ); DBGC2 ( context, "GCM %p E(K,Y[%d]):\n", context, block ); DBGC2_HDA ( context, 0, &tmp, sizeof ( tmp ) ); @@ -367,100 +394,53 @@ static void gcm_process ( struct gcm_context *context, const void *src, dst += frag_len; /* Update hash with encrypted data, if applicable */ - gcm_xor ( &tmp, &context->hash, &context->hash, + gcm_xor ( &tmp, &context->gcm.hash, &context->gcm.hash, ( frag_len & flags ) ); } /* Update hash */ - gcm_multiply_key ( &context->key, &context->hash ); + gcm_multiply_key ( &context->gcm.key, &context->gcm.hash ); DBGC2 ( context, "GCM %p X[%d]:\n", context, block ); - DBGC2_HDA ( context, 0, &context->hash, - sizeof ( context->hash ) ); + DBGC2_HDA ( context, 0, &context->gcm.hash, + sizeof ( context->gcm.hash ) ); } } -/** - * Construct hash - * - * @v context Context - * @v hash Hash to fill in - */ -static void gcm_hash ( struct gcm_context *context, union gcm_block *hash ) { - - /* Construct big-endian lengths block */ - hash->len.add = cpu_to_be64 ( context->len.len.add ); - hash->len.data = cpu_to_be64 ( context->len.len.data ); - DBGC2 ( context, "GCM %p len(A)||len(C):\n", context ); - DBGC2_HDA ( context, 0, hash, sizeof ( *hash ) ); - - /* Update hash */ - gcm_xor_block ( &context->hash, hash ); - gcm_multiply_key ( &context->key, hash ); - DBGC2 ( context, "GCM %p GHASH(H,A,C):\n", context ); - DBGC2_HDA ( context, 0, hash, sizeof ( *hash ) ); -} - -/** - * Construct tag - * - * @v context Context - * @v tag Tag - */ -void gcm_tag ( struct gcm_context *context, union gcm_block *tag ) { - union gcm_block tmp; - uint32_t offset; - - /* Construct hash */ - gcm_hash ( context, tag ); - - /* Construct encrypted initial counter value */ - memcpy ( &tmp, &context->ctr, sizeof ( tmp ) ); - offset = ( ( -context->len.len.data ) / ( 8 * sizeof ( tmp ) ) ); - gcm_count ( &tmp, offset ); - cipher_encrypt ( context->raw_cipher, &context->raw_ctx, &tmp, - &tmp, sizeof ( tmp ) ); - DBGC2 ( context, "GCM %p E(K,Y[0]):\n", context ); - DBGC2_HDA ( context, 0, &tmp, sizeof ( tmp ) ); - - /* Construct tag */ - gcm_xor_block ( &tmp, tag ); - DBGC2 ( context, "GCM %p T:\n", context ); - DBGC2_HDA ( context, 0, tag, sizeof ( *tag ) ); -} - /** * Set key * - * @v context Context + * @v cipher Cipher algorithm + * @v ctx Context * @v key Key * @v keylen Key length - * @v raw_cipher Underlying cipher * @ret rc Return status code */ -int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen, - struct cipher_algorithm *raw_cipher ) { +int gcm_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + gcm_context_t ( cipher->ctxsize ) *context = ctx; int rc; /* Initialise GCM context */ - memset ( context, 0, sizeof ( *context ) ); - context->raw_cipher = raw_cipher; + memset ( &context->gcm, 0, sizeof ( context->gcm ) ); /* Set underlying block cipher key */ - if ( ( rc = cipher_setkey ( raw_cipher, context->raw_ctx, key, + if ( ( rc = cipher_setkey ( raw_cipher, context->raw, key, keylen ) ) != 0 ) return rc; /* Construct GCM hash key */ - cipher_encrypt ( raw_cipher, context->raw_ctx, &context->ctr, - &context->key, sizeof ( context->key ) ); + cipher_encrypt ( raw_cipher, context->raw, &context->gcm.ctr, + &context->gcm.key, sizeof ( context->gcm.key ) ); DBGC2 ( context, "GCM %p H:\n", context ); - DBGC2_HDA ( context, 0, &context->key, sizeof ( context->key ) ); + DBGC2_HDA ( context, 0, &context->gcm.key, + sizeof ( context->gcm.key ) ); /* Reset counter */ - context->ctr.ctr.value = cpu_to_be32 ( 1 ); + context->gcm.ctr.ctr.value = cpu_to_be32 ( 1 ); /* Construct cached tables */ - gcm_cache ( &context->key ); + gcm_cache ( &context->gcm.key ); return 0; } @@ -468,75 +448,114 @@ int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen, /** * Set initialisation vector * + * @v cipher Cipher algorithm * @v ctx Context * @v iv Initialisation vector * @v ivlen Initialisation vector length */ -void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) { +void gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ) { + gcm_context_t ( cipher->ctxsize ) *context = ctx; /* Reset non-key state */ - memset ( context, 0, gcm_offset ( key ) ); + memset ( &context->gcm, 0, gcm_offset ( key ) ); build_assert ( gcm_offset ( key ) > gcm_offset ( hash ) ); build_assert ( gcm_offset ( key ) > gcm_offset ( len ) ); build_assert ( gcm_offset ( key ) > gcm_offset ( ctr ) ); - build_assert ( gcm_offset ( key ) < gcm_offset ( raw_cipher ) ); - build_assert ( gcm_offset ( key ) < gcm_offset ( raw_ctx ) ); /* Reset counter */ - context->ctr.ctr.value = cpu_to_be32 ( 1 ); + context->gcm.ctr.ctr.value = cpu_to_be32 ( 1 ); /* Process initialisation vector */ - if ( ivlen == sizeof ( context->ctr.ctr.iv ) ) { + if ( ivlen == sizeof ( context->gcm.ctr.ctr.iv ) ) { /* Initialisation vector is exactly 96 bits, use it as-is */ - memcpy ( context->ctr.ctr.iv, iv, ivlen ); + memcpy ( context->gcm.ctr.ctr.iv, iv, ivlen ); } else { /* Calculate hash over initialisation vector */ - gcm_process ( context, iv, NULL, ivlen, GCM_FL_IV ); - gcm_hash ( context, &context->ctr ); - assert ( context->len.len.add == 0 ); + context->gcm.flags = GCM_FL_IV; + gcm_process ( cipher, ctx, iv, NULL, ivlen ); + gcm_hash ( &context->gcm, &context->gcm.ctr ); + assert ( context->gcm.len.len.add == 0 ); /* Reset non-key, non-counter state */ - memset ( context, 0, gcm_offset ( ctr ) ); + memset ( &context->gcm, 0, gcm_offset ( ctr ) ); build_assert ( gcm_offset ( ctr ) > gcm_offset ( hash ) ); build_assert ( gcm_offset ( ctr ) > gcm_offset ( len ) ); build_assert ( gcm_offset ( ctr ) < gcm_offset ( key ) ); - build_assert ( gcm_offset ( ctr ) < gcm_offset ( raw_cipher ) ); - build_assert ( gcm_offset ( ctr ) < gcm_offset ( raw_ctx ) ); } DBGC2 ( context, "GCM %p Y[0]:\n", context ); - DBGC2_HDA ( context, 0, &context->ctr, sizeof ( context->ctr ) ); + DBGC2_HDA ( context, 0, &context->gcm.ctr, + sizeof ( context->gcm.ctr ) ); } /** * Encrypt data * - * @v context Context + * @v cipher Cipher algorithm + * @v ctx Context * @v src Data to encrypt * @v dst Buffer for encrypted data, or NULL for additional data * @v len Length of data */ -void gcm_encrypt ( struct gcm_context *context, const void *src, void *dst, - size_t len ) { +void gcm_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + gcm_context_t ( cipher->ctxsize ) *context = ctx; /* Process data */ - gcm_process ( context, src, dst, len, GCM_FL_ENCRYPT ); + context->gcm.flags = GCM_FL_ENCRYPT; + gcm_process ( cipher, ctx, src, dst, len ); } /** * Decrypt data * - * @v context Context + * @v cipher Cipher algorithm + * @v ctx Context * @v src Data to decrypt * @v dst Buffer for decrypted data, or NULL for additional data * @v len Length of data */ -void gcm_decrypt ( struct gcm_context *context, const void *src, void *dst, - size_t len ) { +void gcm_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ) { + gcm_context_t ( cipher->ctxsize ) *context = ctx; /* Process data */ - gcm_process ( context, src, dst, len, 0 ); + context->gcm.flags = 0; + gcm_process ( cipher, ctx, src, dst, len ); +} + +/** + * Generate authentication tag + * + * @v cipher Cipher algorithm + * @v ctx Context + * @v auth Authentication tag + */ +void gcm_auth ( struct cipher_algorithm *cipher, void *ctx, void *auth ) { + struct cipher_algorithm *raw_cipher = cipher->priv; + gcm_context_t ( cipher->ctxsize ) *context = ctx; + union gcm_block *tag = auth; + union gcm_block tmp; + uint32_t offset; + + /* Construct hash */ + gcm_hash ( &context->gcm, tag ); + + /* Construct encrypted initial counter value */ + memcpy ( &tmp, &context->gcm.ctr, sizeof ( tmp ) ); + offset = ( ( -context->gcm.len.len.data ) / ( 8 * sizeof ( tmp ) ) ); + gcm_count ( &tmp, offset ); + cipher_encrypt ( raw_cipher, &context->raw, &tmp, &tmp, + sizeof ( tmp ) ); + DBGC2 ( context, "GCM %p E(K,Y[0]):\n", context ); + DBGC2_HDA ( context, 0, &tmp, sizeof ( tmp ) ); + + /* Construct tag */ + gcm_xor_block ( &tmp, tag ); + DBGC2 ( context, "GCM %p T:\n", context ); + DBGC2_HDA ( context, 0, tag, sizeof ( *tag ) ); } diff --git a/src/include/ipxe/cbc.h b/src/include/ipxe/cbc.h index 154fc5666..11979f2e2 100644 --- a/src/include/ipxe/cbc.h +++ b/src/include/ipxe/cbc.h @@ -12,46 +12,21 @@ FILE_SECBOOT ( PERMITTED ); #include -/** - * Set key - * - * @v ctx Context - * @v key Key - * @v keylen Key length - * @v raw_cipher Underlying cipher algorithm - * @v cbc_ctx CBC context - * @ret rc Return status code - */ -static inline int cbc_setkey ( void *ctx, const void *key, size_t keylen, - struct cipher_algorithm *raw_cipher, - void *cbc_ctx __unused ) { - - return cipher_setkey ( raw_cipher, ctx, key, keylen ); -} - -/** - * Set initialisation vector - * - * @v ctx Context - * @v iv Initialisation vector - * @v ivlen Initialisation vector length - * @v raw_cipher Underlying cipher algorithm - * @v cbc_ctx CBC context - */ -static inline void cbc_setiv ( void *ctx __unused, - const void *iv, size_t ivlen, - struct cipher_algorithm *raw_cipher, - void *cbc_ctx ) { - assert ( ivlen == raw_cipher->blocksize ); - memcpy ( cbc_ctx, iv, raw_cipher->blocksize ); -} - -extern void cbc_encrypt ( void *ctx, const void *src, void *dst, - size_t len, struct cipher_algorithm *raw_cipher, - void *cbc_ctx ); -extern void cbc_decrypt ( void *ctx, const void *src, void *dst, - size_t len, struct cipher_algorithm *raw_cipher, - void *cbc_ctx ); +/** A cipher-block chaining mode context */ +#define cbc_context_t( blocksize, ctxsize ) \ + struct { \ + uint8_t cbc[ (blocksize) ]; \ + uint8_t raw[ (ctxsize) - (blocksize) ]; \ + } + +extern int cbc_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ); +extern void cbc_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ); +extern void cbc_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); +extern void cbc_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); /** * Create a cipher-block chaining mode of behaviour of an existing cipher @@ -64,45 +39,18 @@ extern void cbc_decrypt ( void *ctx, const void *src, void *dst, */ #define CBC_CIPHER( _cbc_name, _cbc_cipher, _raw_cipher, _raw_context, \ _blocksize ) \ -struct _cbc_name ## _context { \ - _raw_context raw_ctx; \ - uint8_t cbc_ctx[_blocksize]; \ -}; \ -static int _cbc_name ## _setkey ( void *ctx, const void *key, \ - size_t keylen ) { \ - struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ - return cbc_setkey ( &_cbc_name ## _ctx->raw_ctx, key, keylen, \ - &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx );\ -} \ -static void _cbc_name ## _setiv ( void *ctx, const void *iv, \ - size_t ivlen ) { \ - struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ - cbc_setiv ( &_cbc_name ## _ctx->raw_ctx, iv, ivlen, \ - &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx ); \ -} \ -static void _cbc_name ## _encrypt ( void *ctx, const void *src, \ - void *dst, size_t len ) { \ - struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ - cbc_encrypt ( &_cbc_name ## _ctx->raw_ctx, src, dst, len, \ - &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx ); \ -} \ -static void _cbc_name ## _decrypt ( void *ctx, const void *src, \ - void *dst, size_t len ) { \ - struct _cbc_name ## _context * _cbc_name ## _ctx = ctx; \ - cbc_decrypt ( &_cbc_name ## _ctx->raw_ctx, src, dst, len, \ - &_raw_cipher, &_cbc_name ## _ctx->cbc_ctx ); \ -} \ struct cipher_algorithm _cbc_cipher = { \ .name = #_cbc_name, \ - .ctxsize = sizeof ( struct _cbc_name ## _context ), \ + .ctxsize = ( _blocksize + sizeof ( _raw_context ) ), \ .blocksize = _blocksize, \ .alignsize = _blocksize, \ .authsize = 0, \ - .setkey = _cbc_name ## _setkey, \ - .setiv = _cbc_name ## _setiv, \ - .encrypt = _cbc_name ## _encrypt, \ - .decrypt = _cbc_name ## _decrypt, \ + .setkey = cbc_setkey, \ + .setiv = cbc_setiv, \ + .encrypt = cbc_encrypt, \ + .decrypt = cbc_decrypt, \ .auth = cipher_null_auth, \ + .priv = &_raw_cipher, \ }; #endif /* _IPXE_CBC_H */ diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index bf5bcc811..933103dfb 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -82,21 +82,26 @@ struct cipher_algorithm { size_t authsize; /** Set key * + * @v cipher Cipher algorithm * @v ctx Context * @v key Key * @v keylen Key length * @ret rc Return status code */ - int ( * setkey ) ( void *ctx, const void *key, size_t keylen ); + int ( * setkey ) ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ); /** Set initialisation vector * + * @v cipher Cipher algorithm * @v ctx Context * @v iv Initialisation vector * @v ivlen Initialisation vector length */ - void ( * setiv ) ( void *ctx, const void *iv, size_t ivlen ); + void ( * setiv ) ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ); /** Encrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to encrypt * @v dst Buffer for encrypted data, or NULL for additional data @@ -104,10 +109,11 @@ struct cipher_algorithm { * * @v len is guaranteed to be a multiple of @c blocksize. */ - void ( * encrypt ) ( void *ctx, const void *src, void *dst, - size_t len ); + void ( * encrypt ) ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); /** Decrypt data * + * @v cipher Cipher algorithm * @v ctx Context * @v src Data to decrypt * @v dst Buffer for decrypted data, or NULL for additional data @@ -115,14 +121,18 @@ struct cipher_algorithm { * * @v len is guaranteed to be a multiple of @c blocksize. */ - void ( * decrypt ) ( void *ctx, const void *src, void *dst, - size_t len ); + void ( * decrypt ) ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); /** Generate authentication tag * + * @v cipher Cipher algorithm * @v ctx Context * @v auth Authentication tag */ - void ( * auth ) ( void *ctx, void *auth ); + void ( * auth ) ( struct cipher_algorithm *cipher, void *ctx, + void *auth ); + /** Algorithm private data */ + void *priv; }; /** A public key algorithm */ @@ -283,19 +293,19 @@ digest_final ( struct digest_algorithm *digest, void *ctx, void *out ) { static inline __attribute__ (( always_inline )) int cipher_setkey ( struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen ) { - return cipher->setkey ( ctx, key, keylen ); + return cipher->setkey ( cipher, ctx, key, keylen ); } static inline __attribute__ (( always_inline )) void cipher_setiv ( struct cipher_algorithm *cipher, void *ctx, const void *iv, size_t ivlen ) { - cipher->setiv ( ctx, iv, ivlen ); + cipher->setiv ( cipher, ctx, iv, ivlen ); } static inline __attribute__ (( always_inline )) void cipher_encrypt ( struct cipher_algorithm *cipher, void *ctx, const void *src, void *dst, size_t len ) { - cipher->encrypt ( ctx, src, dst, len ); + cipher->encrypt ( cipher, ctx, src, dst, len ); } #define cipher_encrypt( cipher, ctx, src, dst, len ) do { \ assert ( ( (len) & ( (cipher)->blocksize - 1 ) ) == 0 ); \ @@ -305,7 +315,7 @@ cipher_encrypt ( struct cipher_algorithm *cipher, void *ctx, static inline __attribute__ (( always_inline )) void cipher_decrypt ( struct cipher_algorithm *cipher, void *ctx, const void *src, void *dst, size_t len ) { - cipher->decrypt ( ctx, src, dst, len ); + cipher->decrypt ( cipher, ctx, src, dst, len ); } #define cipher_decrypt( cipher, ctx, src, dst, len ) do { \ assert ( ( (len) & ( (cipher)->blocksize - 1 ) ) == 0 ); \ @@ -314,7 +324,7 @@ cipher_decrypt ( struct cipher_algorithm *cipher, void *ctx, static inline __attribute__ (( always_inline )) void cipher_auth ( struct cipher_algorithm *cipher, void *ctx, void *auth ) { - cipher->auth ( ctx, auth ); + cipher->auth ( cipher, ctx, auth ); } static inline __attribute__ (( always_inline )) int @@ -402,13 +412,16 @@ extern void digest_null_update ( struct digest_algorithm *digest, void *ctx, extern void digest_null_final ( struct digest_algorithm *digest, void *ctx, void *out ); -extern int cipher_null_setkey ( void *ctx, const void *key, size_t keylen ); -extern void cipher_null_setiv ( void *ctx, const void *iv, size_t ivlen ); -extern void cipher_null_encrypt ( void *ctx, const void *src, void *dst, - size_t len ); -extern void cipher_null_decrypt ( void *ctx, const void *src, void *dst, - size_t len ); -extern void cipher_null_auth ( void *ctx, void *auth ); +extern int cipher_null_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ); +extern void cipher_null_setiv ( struct cipher_algorithm *cipehr, void *ctx, + const void *iv, size_t ivlen ); +extern void cipher_null_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); +extern void cipher_null_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); +extern void cipher_null_auth ( struct cipher_algorithm *cipher, void *ctx, + void *auth ); extern int pubkey_null_encrypt ( const struct asn1_cursor *key, const struct asn1_cursor *plaintext, diff --git a/src/include/ipxe/ecb.h b/src/include/ipxe/ecb.h index c29602fca..791ab067c 100644 --- a/src/include/ipxe/ecb.h +++ b/src/include/ipxe/ecb.h @@ -12,13 +12,15 @@ FILE_SECBOOT ( PERMITTED ); #include -extern void ecb_encrypt ( void *ctx, const void *src, void *dst, - size_t len, struct cipher_algorithm *raw_cipher ); -extern void ecb_decrypt ( void *ctx, const void *src, void *dst, - size_t len, struct cipher_algorithm *raw_cipher ); +extern int ecb_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ); +extern void ecb_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); +extern void ecb_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); /** - * Create a cipher-block chaining mode of behaviour of an existing cipher + * Create an electronic codebook mode of behaviour of an existing cipher * * @v _ecb_name Name for the new ECB cipher * @v _ecb_cipher New cipher algorithm @@ -28,33 +30,18 @@ extern void ecb_decrypt ( void *ctx, const void *src, void *dst, */ #define ECB_CIPHER( _ecb_name, _ecb_cipher, _raw_cipher, _raw_context, \ _blocksize ) \ -static int _ecb_name ## _setkey ( void *ctx, const void *key, \ - size_t keylen ) { \ - return cipher_setkey ( &_raw_cipher, ctx, key, keylen ); \ -} \ -static void _ecb_name ## _setiv ( void *ctx, const void *iv, \ - size_t ivlen ) { \ - cipher_setiv ( &_raw_cipher, ctx, iv, ivlen ); \ -} \ -static void _ecb_name ## _encrypt ( void *ctx, const void *src, \ - void *dst, size_t len ) { \ - ecb_encrypt ( ctx, src, dst, len, &_raw_cipher ); \ -} \ -static void _ecb_name ## _decrypt ( void *ctx, const void *src, \ - void *dst, size_t len ) { \ - ecb_decrypt ( ctx, src, dst, len, &_raw_cipher ); \ -} \ struct cipher_algorithm _ecb_cipher = { \ .name = #_ecb_name, \ .ctxsize = sizeof ( _raw_context ), \ .blocksize = _blocksize, \ .alignsize = _blocksize, \ .authsize = 0, \ - .setkey = _ecb_name ## _setkey, \ - .setiv = _ecb_name ## _setiv, \ - .encrypt = _ecb_name ## _encrypt, \ - .decrypt = _ecb_name ## _decrypt, \ + .setkey = ecb_setkey, \ + .setiv = cipher_null_setiv, \ + .encrypt = ecb_encrypt, \ + .decrypt = ecb_decrypt, \ .auth = cipher_null_auth, \ + .priv = &_raw_cipher, \ }; #endif /* _IPXE_ECB_H */ diff --git a/src/include/ipxe/gcm.h b/src/include/ipxe/gcm.h index 5635a1031..d794a7283 100644 --- a/src/include/ipxe/gcm.h +++ b/src/include/ipxe/gcm.h @@ -53,21 +53,28 @@ struct gcm_context { union gcm_block ctr; /** Hash key (H) */ union gcm_block key; - /** Underlying block cipher */ - struct cipher_algorithm *raw_cipher; - /** Underlying block cipher context */ - uint8_t raw_ctx[0]; + /** Processing flags */ + unsigned int flags; }; -extern void gcm_tag ( struct gcm_context *context, union gcm_block *tag ); -extern int gcm_setkey ( struct gcm_context *context, const void *key, - size_t keylen, struct cipher_algorithm *raw_cipher ); -extern void gcm_setiv ( struct gcm_context *context, const void *iv, - size_t ivlen ); -extern void gcm_encrypt ( struct gcm_context *context, const void *src, - void *dst, size_t len ); -extern void gcm_decrypt ( struct gcm_context *context, const void *src, - void *dst, size_t len ); +/** A GCM mode context */ +#define gcm_context_t( ctxsize ) \ + struct { \ + struct gcm_context gcm; \ + uint8_t raw[ (ctxsize) - \ + sizeof ( struct gcm_context ) ]; \ + } + +extern int gcm_setkey ( struct cipher_algorithm *cipher, void *ctx, + const void *key, size_t keylen ); +extern void gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ); +extern void gcm_encrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); +extern void gcm_decrypt ( struct cipher_algorithm *cipher, void *ctx, + const void *src, void *dst, size_t len ); +extern void gcm_auth ( struct cipher_algorithm *cipher, void *ctx, + void *auth ); /** * Create a GCM mode of behaviour of an existing cipher @@ -80,52 +87,20 @@ extern void gcm_decrypt ( struct gcm_context *context, const void *src, */ #define GCM_CIPHER( _gcm_name, _gcm_cipher, _raw_cipher, _raw_context, \ _blocksize ) \ -struct _gcm_name ## _context { \ - /** GCM context */ \ - struct gcm_context gcm; \ - /** Underlying block cipher context */ \ - _raw_context raw; \ -}; \ -static int _gcm_name ## _setkey ( void *ctx, const void *key, \ - size_t keylen ) { \ - struct _gcm_name ## _context *context = ctx; \ - build_assert ( _blocksize == sizeof ( context->gcm.key ) ); \ - build_assert ( offsetof ( typeof ( *context ), gcm ) == 0 ); \ - build_assert ( offsetof ( typeof ( *context ), raw ) == \ - offsetof ( typeof ( *context ), gcm.raw_ctx ) ); \ - return gcm_setkey ( &context->gcm, key, keylen, &_raw_cipher ); \ -} \ -static void _gcm_name ## _setiv ( void *ctx, const void *iv, \ - size_t ivlen ) { \ - struct _gcm_name ## _context *context = ctx; \ - gcm_setiv ( &context->gcm, iv, ivlen ); \ -} \ -static void _gcm_name ## _encrypt ( void *ctx, const void *src, \ - void *dst, size_t len ) { \ - struct _gcm_name ## _context *context = ctx; \ - gcm_encrypt ( &context->gcm, src, dst, len ); \ -} \ -static void _gcm_name ## _decrypt ( void *ctx, const void *src, \ - void *dst, size_t len ) { \ - struct _gcm_name ## _context *context = ctx; \ - gcm_decrypt ( &context->gcm, src, dst, len ); \ -} \ -static void _gcm_name ## _auth ( void *ctx, void *auth ) { \ - struct _gcm_name ## _context *context = ctx; \ - union gcm_block *tag = auth; \ - gcm_tag ( &context->gcm, tag ); \ -} \ +static_assert ( _blocksize == sizeof ( union gcm_block ) ); \ struct cipher_algorithm _gcm_cipher = { \ .name = #_gcm_name, \ - .ctxsize = sizeof ( struct _gcm_name ## _context ), \ + .ctxsize = ( sizeof ( struct gcm_context ) + \ + sizeof ( _raw_context ) ), \ .blocksize = 1, \ .alignsize = sizeof ( union gcm_block ), \ .authsize = sizeof ( union gcm_block ), \ - .setkey = _gcm_name ## _setkey, \ - .setiv = _gcm_name ## _setiv, \ - .encrypt = _gcm_name ## _encrypt, \ - .decrypt = _gcm_name ## _decrypt, \ - .auth = _gcm_name ## _auth, \ + .setkey = gcm_setkey, \ + .setiv = gcm_setiv, \ + .encrypt = gcm_encrypt, \ + .decrypt = gcm_decrypt, \ + .auth = gcm_auth, \ + .priv = &_raw_cipher, \ }; #endif /* _IPXE_GCM_H */