mirror of
https://github.com/ipxe/ipxe
synced 2026-04-04 03:00:20 +03:00
[crypto] Simplify internal HMAC API
Simplify the internal HMAC API so that the key is provided only at the point of calling hmac_init(), and the (potentially reduced) key is stored as part of the context for later use by hmac_final(). This simplifies the calling code, and avoids the need for callers such as TLS to allocate a potentially variable length block in order to retain a copy of the unmodified key. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -46,94 +46,62 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/crypto.h>
|
||||
#include <ipxe/hmac.h>
|
||||
|
||||
/**
|
||||
* Reduce HMAC key length
|
||||
*
|
||||
* @v digest Digest algorithm to use
|
||||
* @v digest_ctx Digest context
|
||||
* @v key Key
|
||||
* @v key_len Length of key
|
||||
*/
|
||||
static void hmac_reduce_key ( struct digest_algorithm *digest,
|
||||
void *key, size_t *key_len ) {
|
||||
uint8_t digest_ctx[digest->ctxsize];
|
||||
|
||||
digest_init ( digest, digest_ctx );
|
||||
digest_update ( digest, digest_ctx, key, *key_len );
|
||||
digest_final ( digest, digest_ctx, key );
|
||||
*key_len = digest->digestsize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise HMAC
|
||||
*
|
||||
* @v digest Digest algorithm to use
|
||||
* @v digest_ctx Digest context
|
||||
* @v ctx HMAC context
|
||||
* @v key Key
|
||||
* @v key_len Length of key
|
||||
*
|
||||
* The length of the key should be less than the block size of the
|
||||
* digest algorithm being used. (If the key length is greater, it
|
||||
* will be replaced with its own digest, and key_len will be updated
|
||||
* accordingly).
|
||||
*/
|
||||
void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
|
||||
void *key, size_t *key_len ) {
|
||||
unsigned char k_ipad[digest->blocksize];
|
||||
void hmac_init ( struct digest_algorithm *digest, void *ctx, const void *key,
|
||||
size_t key_len ) {
|
||||
hmac_context_t ( digest ) *hctx = ctx;
|
||||
unsigned int i;
|
||||
|
||||
/* Reduce key if necessary */
|
||||
if ( *key_len > sizeof ( k_ipad ) )
|
||||
hmac_reduce_key ( digest, key, key_len );
|
||||
|
||||
/* Construct input pad */
|
||||
memset ( k_ipad, 0, sizeof ( k_ipad ) );
|
||||
memcpy ( k_ipad, key, *key_len );
|
||||
for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
memset ( hctx->pad, 0, sizeof ( hctx->pad ) );
|
||||
if ( key_len <= sizeof ( hctx->pad ) ) {
|
||||
memcpy ( hctx->pad, key, key_len );
|
||||
} else {
|
||||
digest_init ( digest, hctx->ctx );
|
||||
digest_update ( digest, hctx->ctx, key, key_len );
|
||||
digest_final ( digest, hctx->ctx, hctx->pad );
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < sizeof ( hctx->pad ) ; i++ ) {
|
||||
hctx->pad[i] ^= 0x36;
|
||||
}
|
||||
|
||||
/* Start inner hash */
|
||||
digest_init ( digest, digest_ctx );
|
||||
digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
|
||||
digest_init ( digest, hctx->ctx );
|
||||
digest_update ( digest, hctx->ctx, hctx->pad, sizeof ( hctx->pad ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise HMAC
|
||||
*
|
||||
* @v digest Digest algorithm to use
|
||||
* @v digest_ctx Digest context
|
||||
* @v key Key
|
||||
* @v key_len Length of key
|
||||
* @v ctx HMAC context
|
||||
* @v hmac HMAC digest to fill in
|
||||
*
|
||||
* The length of the key should be less than the block size of the
|
||||
* digest algorithm being used. (If the key length is greater, it
|
||||
* will be replaced with its own digest, and key_len will be updated
|
||||
* accordingly).
|
||||
*/
|
||||
void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
|
||||
void *key, size_t *key_len, void *hmac ) {
|
||||
unsigned char k_opad[digest->blocksize];
|
||||
void hmac_final ( struct digest_algorithm *digest, void *ctx, void *hmac ) {
|
||||
hmac_context_t ( digest ) *hctx = ctx;
|
||||
unsigned int i;
|
||||
|
||||
/* Reduce key if necessary */
|
||||
if ( *key_len > sizeof ( k_opad ) )
|
||||
hmac_reduce_key ( digest, key, key_len );
|
||||
|
||||
/* Construct output pad */
|
||||
memset ( k_opad, 0, sizeof ( k_opad ) );
|
||||
memcpy ( k_opad, key, *key_len );
|
||||
for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
|
||||
k_opad[i] ^= 0x5c;
|
||||
/* Construct output pad from input pad */
|
||||
for ( i = 0 ; i < sizeof ( hctx->pad ) ; i++ ) {
|
||||
hctx->pad[i] ^= 0x6a;
|
||||
}
|
||||
|
||||
|
||||
/* Finish inner hash */
|
||||
digest_final ( digest, digest_ctx, hmac );
|
||||
digest_final ( digest, hctx->ctx, hmac );
|
||||
|
||||
/* Perform outer hash */
|
||||
digest_init ( digest, digest_ctx );
|
||||
digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
|
||||
digest_update ( digest, digest_ctx, hmac, digest->digestsize );
|
||||
digest_final ( digest, digest_ctx, hmac );
|
||||
digest_init ( digest, hctx->ctx );
|
||||
digest_update ( digest, hctx->ctx, hctx->pad, sizeof ( hctx->pad ) );
|
||||
digest_update ( digest, hctx->ctx, hmac, digest->digestsize );
|
||||
digest_final ( digest, hctx->ctx, hmac );
|
||||
|
||||
/* Erase output pad (from which the key may be derivable) */
|
||||
memset ( hctx->pad, 0, sizeof ( hctx->pad ) );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user