From 327378a764064b5edbc8bbebbb95980234892d04 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 23 Jun 2026 12:46:55 +0100 Subject: [PATCH] =?UTF-8?q?[crypto]=20Generalise=20implementation=20of=20M?= =?UTF-8?q?erkle-Damg=C3=A5rd=20hash=20algorithms?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of our current digest algorithms (MD4, MD5, SHA-1, and the SHA-2 family) use a Merkle-Damgård construction, with only the compression function, the initial digest values, the field sizes, and the endianness differing between algorithms. Provide a common implementation for Merkle-Damgård hash algorithms to reduce code size. Values are now held as host-endian quantities, with any swapping performed byte-by-byte as data is accumulated (using a compile-time constant that is XORed with the byte index). For the SHA family of algorithms, the values w[] are now calculated iteratively as we progress through the main loop: this substantially reduces the stack space required for the compression function. Signed-off-by: Michael Brown --- src/crypto/md4.c | 164 ++++++------------------------ src/crypto/md5.c | 164 ++++++------------------------ src/crypto/mdhash.c | 151 ++++++++++++++++++++++++++++ src/crypto/sha1.c | 182 ++++++++-------------------------- src/crypto/sha224.c | 19 +--- src/crypto/sha256.c | 199 +++++++++---------------------------- src/crypto/sha384.c | 21 ++-- src/crypto/sha512.c | 203 ++++++++++---------------------------- src/crypto/sha512_224.c | 22 ++--- src/crypto/sha512_256.c | 22 ++--- src/include/ipxe/md4.h | 20 +--- src/include/ipxe/md5.h | 20 +--- src/include/ipxe/mdhash.h | 171 ++++++++++++++++++++++++++++++++ src/include/ipxe/sha1.h | 20 +--- src/include/ipxe/sha256.h | 52 ++-------- src/include/ipxe/sha512.h | 63 +++--------- 16 files changed, 585 insertions(+), 908 deletions(-) create mode 100644 src/crypto/mdhash.c create mode 100644 src/include/ipxe/mdhash.h diff --git a/src/crypto/md4.c b/src/crypto/md4.c index e644bb195..7a3aa2c7b 100644 --- a/src/crypto/md4.c +++ b/src/crypto/md4.c @@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED ); */ #include -#include -#include #include #include #include @@ -40,9 +38,7 @@ FILE_SECBOOT ( PERMITTED ); /** MD4 variables */ struct md4_variables { - /* This layout matches that of struct md4_digest_data, - * allowing for efficient endianness-conversion, - */ + /* This layout matches that of struct md4_digest_data */ uint32_t a; uint32_t b; uint32_t c; @@ -109,7 +105,7 @@ struct md4_step { }; /** MD4 steps */ -static struct md4_step md4_steps[4] = { +static const struct md4_step md4_steps[4] = { /** 0 to 15 */ { .f = md4_f_0_15, .constant = 0x00000000UL }, /** 16 to 31 */ @@ -118,158 +114,62 @@ static struct md4_step md4_steps[4] = { { .f = md4_f_32_47, .constant = 0x6ed9eba1UL }, }; -/** - * Initialise MD4 algorithm - * - * @v digest Digest algorithm - * @v ctx MD4 context - */ -static void md4_init ( struct digest_algorithm *digest __unused, void *ctx ) { - struct md4_context *context = ctx; - - context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 ); - context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 ); - context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe ); - context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 ); - context->len = 0; -} +/** MD4 initial digest values */ +static const struct md4_digest md4_init = { + .h = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 } +}; /** * Calculate MD4 digest of accumulated data * - * @v context MD4 context + * @v dd Digest and data block + * @v digest Copy of current digest value */ -static void md4_digest ( struct md4_context *context ) { +static void md4_compress ( struct md4_digest_data *dd, + const struct md4_digest *digest ) { union { - union md4_digest_data_dwords ddd; + struct md4_digest_data dd; struct md4_variables v; - } u; - uint32_t *a = &u.v.a; - uint32_t *b = &u.v.b; - uint32_t *c = &u.v.c; - uint32_t *d = &u.v.d; - uint32_t *w = u.v.w; + } *u = container_of ( dd, typeof ( *u ), dd ); + struct md4_variables *v = &u->v; + const struct md4_step *step; + uint32_t *a = &v->a; + uint32_t *b = &v->b; + uint32_t *c = &v->c; + uint32_t *d = &v->d; + uint32_t *w = v->w; uint32_t f; uint32_t temp; - struct md4_step *step; unsigned int round; unsigned int i; /* Sanity checks */ - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - build_assert ( &u.ddd.dd.digest.h[0] == a ); - build_assert ( &u.ddd.dd.digest.h[1] == b ); - build_assert ( &u.ddd.dd.digest.h[2] == c ); - build_assert ( &u.ddd.dd.digest.h[3] == d ); - build_assert ( &u.ddd.dd.data.dword[0] == w ); - - DBGC ( context, "MD4 digesting:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); - DBGC_HDA ( context, context->len, &context->ddd.dd.data, - sizeof ( context->ddd.dd.data ) ); - - /* Convert h[0..3] to host-endian, and initialise a, b, c, d, - * and x[0..15] - */ - for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / - sizeof ( u.ddd.dword[0] ) ) ; i++ ) { - le32_to_cpus ( &context->ddd.dword[i] ); - u.ddd.dword[i] = context->ddd.dword[i]; - } + build_assert ( &u->dd.digest.h[0] == a ); + build_assert ( &u->dd.digest.h[1] == b ); + build_assert ( &u->dd.digest.h[2] == c ); + build_assert ( &u->dd.digest.h[3] == d ); + build_assert ( &u->dd.data.dword[0] == w ); + build_assert ( sizeof ( u->dd ) == sizeof ( u->v ) ); /* Main loop */ for ( i = 0 ; i < 48 ; i++ ) { round = ( i / 16 ); step = &md4_steps[round]; - f = step->f ( &u.v, ( i % 16 ) ); + f = step->f ( v, ( i % 16 ) ); temp = *d; *d = *c; *c = *b; *b = rol32 ( ( *a + f + step->constant ), r[round][ i % 4 ] ); *a = temp; - DBGC2 ( context, "%2d : %08x %08x %08x %08x\n", + DBGC2 ( &md4_algorithm, "%2d : %08x %08x %08x %08x\n", i, *a, *b, *c, *d ); } - /* Add chunk to hash and convert back to little-endian */ - for ( i = 0 ; i < 4 ; i++ ) { - context->ddd.dd.digest.h[i] = - cpu_to_le32 ( context->ddd.dd.digest.h[i] + - u.ddd.dd.digest.h[i] ); - } - - DBGC ( context, "MD4 digested:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); -} - -/** - * Accumulate data with MD4 algorithm - * - * @v digest Digest algorithm - * @v ctx MD4 context - * @v data Data - * @v len Length of data - */ -static void md4_update ( struct digest_algorithm *digest __unused, void *ctx, - const void *data, size_t len ) { - struct md4_context *context = ctx; - const uint8_t *byte = data; - size_t offset; - - /* Accumulate data a byte at a time, performing the digest - * whenever we fill the data buffer - */ - while ( len-- ) { - offset = ( context->len % sizeof ( context->ddd.dd.data ) ); - context->ddd.dd.data.byte[offset] = *(byte++); - context->len++; - if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) - md4_digest ( context ); - } -} - -/** - * Generate MD4 digest - * - * @v digest Digest algorithm - * @v ctx MD4 context - * @v out Output buffer - */ -static void md4_final ( struct digest_algorithm *digest, void *ctx, - void *out ) { - struct md4_context *context = ctx; - uint64_t len_bits; - uint8_t pad; - - /* Record length before pre-processing */ - len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 ); - - /* Pad with a single "1" bit followed by as many "0" bits as required */ - pad = 0x80; - do { - md4_update ( digest, ctx, &pad, sizeof ( pad ) ); - pad = 0x00; - } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != - offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); - - /* Append length (in bits) */ - md4_update ( digest, ctx, &len_bits, sizeof ( len_bits ) ); - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - - /* Copy out final digest */ - memcpy ( out, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); + /* Add chunk to hash */ + for ( i = 0 ; i < 4 ; i++ ) + dd->digest.h[i] += digest->h[i]; } /** MD4 algorithm */ -struct digest_algorithm md4_algorithm = { - .name = "md4", - .ctxsize = sizeof ( struct md4_context ), - .blocksize = sizeof ( union md4_block ), - .digestsize = sizeof ( struct md4_digest ), - .init = md4_init, - .update = md4_update, - .final = md4_final, -}; +MDHASH_ALGORITHM ( md4, md4_algorithm, md4_compress, __LITTLE_ENDIAN, + struct md4_digest_data, md4_init, MD4_DIGEST_SIZE ); diff --git a/src/crypto/md5.c b/src/crypto/md5.c index 06d4c9528..ce467559e 100644 --- a/src/crypto/md5.c +++ b/src/crypto/md5.c @@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED ); */ #include -#include -#include #include #include #include @@ -40,9 +38,7 @@ FILE_SECBOOT ( PERMITTED ); /** MD5 variables */ struct md5_variables { - /* This layout matches that of struct md5_digest_data, - * allowing for efficient endianness-conversion, - */ + /* This layout matches that of struct md5_digest_data */ uint32_t a; uint32_t b; uint32_t c; @@ -129,7 +125,7 @@ struct md5_step { }; /** MD5 steps */ -static struct md5_step md5_steps[4] = { +static const struct md5_step md5_steps[4] = { /** 0 to 15 */ { .f = md5_f_0_15, .coefficient = 1, .constant = 0 }, /** 16 to 31 */ @@ -140,72 +136,49 @@ static struct md5_step md5_steps[4] = { { .f = md5_f_48_63, .coefficient = 7, .constant = 0 }, }; -/** - * Initialise MD5 algorithm - * - * @v digest Digest algorithm - * @v ctx MD5 context - */ -static void md5_init ( struct digest_algorithm *digest __unused, void *ctx ) { - struct md5_context *context = ctx; - - context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 ); - context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 ); - context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe ); - context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 ); - context->len = 0; -} +/** MD5 initial digest values */ +static const struct md5_digest md5_init = { + .h = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 } +}; /** * Calculate MD5 digest of accumulated data * - * @v context MD5 context + * @v dd Digest and data block + * @v digest Copy of current digest value */ -static void md5_digest ( struct md5_context *context ) { +static void md5_compress ( struct md5_digest_data *dd, + const struct md5_digest *digest ) { union { - union md5_digest_data_dwords ddd; + struct md5_digest_data dd; struct md5_variables v; - } u; - uint32_t *a = &u.v.a; - uint32_t *b = &u.v.b; - uint32_t *c = &u.v.c; - uint32_t *d = &u.v.d; - uint32_t *w = u.v.w; + } *u = container_of ( dd, typeof ( *u ), dd ); + struct md5_variables *v = &u->v; + const struct md5_step *step; + uint32_t *a = &v->a; + uint32_t *b = &v->b; + uint32_t *c = &v->c; + uint32_t *d = &v->d; + uint32_t *w = v->w; uint32_t f; uint32_t g; uint32_t temp; - struct md5_step *step; unsigned int round; unsigned int i; /* Sanity checks */ - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - build_assert ( &u.ddd.dd.digest.h[0] == a ); - build_assert ( &u.ddd.dd.digest.h[1] == b ); - build_assert ( &u.ddd.dd.digest.h[2] == c ); - build_assert ( &u.ddd.dd.digest.h[3] == d ); - build_assert ( &u.ddd.dd.data.dword[0] == w ); - - DBGC ( context, "MD5 digesting:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); - DBGC_HDA ( context, context->len, &context->ddd.dd.data, - sizeof ( context->ddd.dd.data ) ); - - /* Convert h[0..3] to host-endian, and initialise a, b, c, d, - * and w[0..15] - */ - for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / - sizeof ( u.ddd.dword[0] ) ) ; i++ ) { - le32_to_cpus ( &context->ddd.dword[i] ); - u.ddd.dword[i] = context->ddd.dword[i]; - } + build_assert ( &u->dd.digest.h[0] == a ); + build_assert ( &u->dd.digest.h[1] == b ); + build_assert ( &u->dd.digest.h[2] == c ); + build_assert ( &u->dd.digest.h[3] == d ); + build_assert ( &u->dd.data.dword[0] == w ); + build_assert ( sizeof ( u->dd ) == sizeof ( u->v ) ); /* Main loop */ for ( i = 0 ; i < 64 ; i++ ) { round = ( i / 16 ); step = &md5_steps[round]; - f = step->f ( &u.v ); + f = step->f ( v ); g = ( ( ( step->coefficient * i ) + step->constant ) % 16 ); temp = *d; *d = *c; @@ -213,88 +186,15 @@ static void md5_digest ( struct md5_context *context ) { *b = ( *b + rol32 ( ( *a + f + k[i] + w[g] ), r[round][ i % 4 ] ) ); *a = temp; - DBGC2 ( context, "%2d : %08x %08x %08x %08x\n", + DBGC2 ( &md5_algorithm, "%2d : %08x %08x %08x %08x\n", i, *a, *b, *c, *d ); } - /* Add chunk to hash and convert back to little-endian */ - for ( i = 0 ; i < 4 ; i++ ) { - context->ddd.dd.digest.h[i] = - cpu_to_le32 ( context->ddd.dd.digest.h[i] + - u.ddd.dd.digest.h[i] ); - } - - DBGC ( context, "MD5 digested:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); -} - -/** - * Accumulate data with MD5 algorithm - * - * @v digest Digest algorithm - * @v ctx MD5 context - * @v data Data - * @v len Length of data - */ -static void md5_update ( struct digest_algorithm *digest __unused, void *ctx, - const void *data, size_t len ) { - struct md5_context *context = ctx; - const uint8_t *byte = data; - size_t offset; - - /* Accumulate data a byte at a time, performing the digest - * whenever we fill the data buffer - */ - while ( len-- ) { - offset = ( context->len % sizeof ( context->ddd.dd.data ) ); - context->ddd.dd.data.byte[offset] = *(byte++); - context->len++; - if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) - md5_digest ( context ); - } -} - -/** - * Generate MD5 digest - * - * @v digest Digest algorithm - * @v ctx MD5 context - * @v out Output buffer - */ -static void md5_final ( struct digest_algorithm *digest, void *ctx, - void *out ) { - struct md5_context *context = ctx; - uint64_t len_bits; - uint8_t pad; - - /* Record length before pre-processing */ - len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 ); - - /* Pad with a single "1" bit followed by as many "0" bits as required */ - pad = 0x80; - do { - md5_update ( digest, ctx, &pad, sizeof ( pad ) ); - pad = 0x00; - } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != - offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); - - /* Append length (in bits) */ - md5_update ( digest, ctx, &len_bits, sizeof ( len_bits ) ); - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - - /* Copy out final digest */ - memcpy ( out, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); + /* Add chunk to hash */ + for ( i = 0 ; i < 4 ; i++ ) + dd->digest.h[i] += digest->h[i]; } /** MD5 algorithm */ -struct digest_algorithm md5_algorithm = { - .name = "md5", - .ctxsize = sizeof ( struct md5_context ), - .blocksize = sizeof ( union md5_block ), - .digestsize = sizeof ( struct md5_digest ), - .init = md5_init, - .update = md5_update, - .final = md5_final, -}; +MDHASH_ALGORITHM ( md5, md5_algorithm, md5_compress, __LITTLE_ENDIAN, + struct md5_digest_data, md5_init, MD5_DIGEST_SIZE ); diff --git a/src/crypto/mdhash.c b/src/crypto/mdhash.c new file mode 100644 index 000000000..f282e473f --- /dev/null +++ b/src/crypto/mdhash.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2026 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +/** @file + * + * Merkle-Damgård hash algorithms + * + */ + +#include +#include +#include +#include +#include + +/** + * Initialise algorithm + * + * @v digest Digest algorithm + * @v ctx MD hash context + */ +void mdhash_init ( struct digest_algorithm *digest, void *ctx ) { + const struct mdhash_algorithm *mdhash = digest->priv; + size_t blocksize = digest->blocksize; + size_t digestsize = mdhash->digestsize; + mdhash_context_t ( digestsize, blocksize ) *context = ctx; + + /* Zero accumulated data length */ + context->len = 0; + + /* Copy initial digest values */ + memcpy ( &context->dd.digest, mdhash->init, digestsize ); +} + +/** + * Accumulate data + * + * @v digest Digest algorithm + * @v ctx MD hash context + * @v data Data + * @v len Length of data + */ +void mdhash_update ( struct digest_algorithm *digest, void *ctx, + const void *data, size_t len ) { + const struct mdhash_algorithm *mdhash = digest->priv; + size_t blocksize = digest->blocksize; + size_t digestsize = mdhash->digestsize; + mdhash_context_t ( digestsize, blocksize ) *context = ctx; + const uint8_t *byte = data; + uint8_t copy[digestsize]; + unsigned int toggle; + unsigned int mask; + size_t offset; + + /* Accumulate data a byte at a time, swapping endianness as we + * go and performing the digest whenever we fill the data + * buffer. + */ + toggle = mdhash->toggle; + mask = ( blocksize - 1 ); + while ( len-- ) { + offset = ( ( context->len++ ^ toggle ) & mask ); + context->dd.data[offset] = *(byte++); + if ( ( context->len & mask ) == 0 ) { + DBGC2 ( digest, "MDHASH %s compressing:\n", + digest->name ); + DBGC2_HDA ( digest, 0, &context->dd.digest, + sizeof ( context->dd.digest ) ); + DBGC2_HDA ( digest, 0, &context->dd.data, + sizeof ( context->dd.data ) ); + memcpy ( copy, &context->dd.digest, digestsize ); + mdhash->compress ( &context->dd, copy ); + DBGC2 ( digest, "MDHASH %s compressed:\n", + digest->name ); + DBGC2_HDA ( digest, 0, &context->dd.digest, + sizeof ( context->dd.digest ) ); + } + } +} + +/** + * Generate digest + * + * @v digest Digest algorithm + * @v ctx MD hash context + * @v out Output buffer + */ +void mdhash_final ( struct digest_algorithm *digest, void *ctx, void *out ) { + const struct mdhash_algorithm *mdhash = digest->priv; + size_t blocksize = digest->blocksize; + size_t digestsize = mdhash->digestsize; + mdhash_context_t ( digestsize, blocksize ) *context = ctx; + uint8_t *byte = out; + union mdhash_len len; + unsigned int toggle; + unsigned int mask; + unsigned int stop; + unsigned int i; + uint8_t pad; + + /* Record length before pre-processing */ + len.qword.bits = ( ( ( uint64_t ) context->len ) * 8 ); + len.qword.pad = 0; + + /* Pad with a single "1" bit followed by as many "0" bits as required */ + mask = ( blocksize - 1 ); + stop = ( blocksize - mdhash->len_len ); + pad = 0x80; + do { + mdhash_update ( digest, ctx, &pad, sizeof ( pad ) ); + pad = 0x00; + } while ( ( context->len & mask ) != stop ); + + /* Append length (in bits) */ + toggle = mdhash->len_toggle; + for ( i = 0 ; i < mdhash->len_len ; i++ ) { + mdhash_update ( digest, ctx, &len.byte[ i ^ toggle ], + sizeof ( len.byte[ i ^ toggle ] ) ); + } + assert ( ( context->len & mask ) == 0 ); + + /* Copy out final digest */ + toggle = mdhash->toggle; + for ( i = 0 ; i < digest->digestsize ; i++ ) + byte[i] = context->dd.digest[ i ^ toggle ]; + DBGC ( digest, "MDHASH %s digested:\n", digest->name ); + DBGC_HDA ( digest, 0, out, digest->digestsize ); +} diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c index d2b3c62ea..359dc4b93 100644 --- a/src/crypto/sha1.c +++ b/src/crypto/sha1.c @@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED ); */ #include -#include -#include #include #include #include @@ -40,15 +38,14 @@ FILE_SECBOOT ( PERMITTED ); /** SHA-1 variables */ struct sha1_variables { - /* This layout matches that of struct sha1_digest_data, - * allowing for efficient endianness-conversion, - */ + /* This layout matches that of struct sha1_digest_data */ uint32_t a; uint32_t b; uint32_t c; uint32_t d; uint32_t e; - uint32_t w[80]; + /* We reuse w[0..15] to construct w[16..79] on demand */ + uint32_t w[16]; } __attribute__ (( packed )); /** @@ -95,7 +92,7 @@ struct sha1_step { }; /** SHA-1 steps */ -static struct sha1_step sha1_steps[4] = { +static const struct sha1_step sha1_steps[4] = { /** 0 to 19 */ { .f = sha1_f_0_19, .k = 0x5a827999 }, /** 20 to 39 */ @@ -106,166 +103,69 @@ static struct sha1_step sha1_steps[4] = { { .f = sha1_f_20_39_60_79, .k = 0xca62c1d6 }, }; -/** - * Initialise SHA-1 algorithm - * - * @v digest Digest algorithm - * @v ctx SHA-1 context - */ -static void sha1_init ( struct digest_algorithm *digest __unused, void *ctx ) { - struct sha1_context *context = ctx; - - context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x67452301 ); - context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xefcdab89 ); - context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x98badcfe ); - context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0x10325476 ); - context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0xc3d2e1f0 ); - context->len = 0; -} +/** SHA-1 initial digest values */ +static const struct sha1_digest sha1_init = { + .h = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 } +}; /** * Calculate SHA-1 digest of accumulated data * - * @v context SHA-1 context + * @v dd Digest and data block + * @v digest Copy of current digest value */ -static void sha1_digest ( struct sha1_context *context ) { +static void sha1_compress ( struct sha1_digest_data *dd, + const struct sha1_digest *digest ) { union { - union sha1_digest_data_dwords ddd; + struct sha1_digest_data dd; struct sha1_variables v; - } u; - uint32_t *a = &u.v.a; - uint32_t *b = &u.v.b; - uint32_t *c = &u.v.c; - uint32_t *d = &u.v.d; - uint32_t *e = &u.v.e; - uint32_t *w = u.v.w; + } *u = container_of ( dd, typeof ( *u ), dd ); + struct sha1_variables *v = &u->v; + const struct sha1_step *step; + uint32_t *a = &v->a; + uint32_t *b = &v->b; + uint32_t *c = &v->c; + uint32_t *d = &v->d; + uint32_t *e = &v->e; + uint32_t *w = v->w; uint32_t f; uint32_t k; uint32_t temp; - struct sha1_step *step; unsigned int i; /* Sanity checks */ - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - build_assert ( &u.ddd.dd.digest.h[0] == a ); - build_assert ( &u.ddd.dd.digest.h[1] == b ); - build_assert ( &u.ddd.dd.digest.h[2] == c ); - build_assert ( &u.ddd.dd.digest.h[3] == d ); - build_assert ( &u.ddd.dd.digest.h[4] == e ); - build_assert ( &u.ddd.dd.data.dword[0] == w ); - - DBGC ( context, "SHA1 digesting:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); - DBGC_HDA ( context, context->len, &context->ddd.dd.data, - sizeof ( context->ddd.dd.data ) ); - - /* Convert h[0..4] to host-endian, and initialise a, b, c, d, - * e, and w[0..15] - */ - for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / - sizeof ( u.ddd.dword[0] ) ) ; i++ ) { - be32_to_cpus ( &context->ddd.dword[i] ); - u.ddd.dword[i] = context->ddd.dword[i]; - } - - /* Initialise w[16..79] */ - for ( i = 16 ; i < 80 ; i++ ) - w[i] = rol32 ( ( w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ), 1 ); + build_assert ( &u->dd.digest.h[0] == a ); + build_assert ( &u->dd.digest.h[1] == b ); + build_assert ( &u->dd.digest.h[2] == c ); + build_assert ( &u->dd.digest.h[3] == d ); + build_assert ( &u->dd.digest.h[4] == e ); + build_assert ( &u->dd.data.dword[0] == w ); + build_assert ( sizeof ( u->dd ) == sizeof ( u->v ) ); /* Main loop */ for ( i = 0 ; i < 80 ; i++ ) { step = &sha1_steps[ i / 20 ]; - f = step->f ( &u.v ); + f = step->f ( v ); k = step->k; - temp = ( rol32 ( *a, 5 ) + f + *e + k + w[i] ); + temp = ( rol32 ( *a, 5 ) + f + *e + k + w[ i % 16 ] ); *e = *d; *d = *c; *c = rol32 ( *b, 30 ); *b = *a; *a = temp; - DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x\n", + w[ i % 16 ] = rol32 ( ( w[ ( i - 3 ) % 16 ] ^ + w[ ( i - 8 ) % 16 ] ^ + w[ ( i - 14 ) % 16 ] ^ + w[ ( i - 16 ) % 16 ] ), 1 ); + DBGC2 ( &sha1_algorithm, "%2d : %08x %08x %08x %08x %08x\n", i, *a, *b, *c, *d, *e ); } - /* Add chunk to hash and convert back to big-endian */ - for ( i = 0 ; i < 5 ; i++ ) { - context->ddd.dd.digest.h[i] = - cpu_to_be32 ( context->ddd.dd.digest.h[i] + - u.ddd.dd.digest.h[i] ); - } - - DBGC ( context, "SHA1 digested:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); -} - -/** - * Accumulate data with SHA-1 algorithm - * - * @v digest Digest algorithm - * @v ctx SHA-1 context - * @v data Data - * @v len Length of data - */ -static void sha1_update ( struct digest_algorithm *digest __unused, - void *ctx, const void *data, size_t len ) { - struct sha1_context *context = ctx; - const uint8_t *byte = data; - size_t offset; - - /* Accumulate data a byte at a time, performing the digest - * whenever we fill the data buffer - */ - while ( len-- ) { - offset = ( context->len % sizeof ( context->ddd.dd.data ) ); - context->ddd.dd.data.byte[offset] = *(byte++); - context->len++; - if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) - sha1_digest ( context ); - } -} - -/** - * Generate SHA-1 digest - * - * @v digest Digest algorithm - * @v ctx SHA-1 context - * @v out Output buffer - */ -static void sha1_final ( struct digest_algorithm *digest, void *ctx, - void *out ) { - struct sha1_context *context = ctx; - uint64_t len_bits; - uint8_t pad; - - /* Record length before pre-processing */ - len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 ); - - /* Pad with a single "1" bit followed by as many "0" bits as required */ - pad = 0x80; - do { - sha1_update ( digest, ctx, &pad, sizeof ( pad ) ); - pad = 0x00; - } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != - offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); - - /* Append length (in bits) */ - sha1_update ( digest, ctx, &len_bits, sizeof ( len_bits ) ); - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - - /* Copy out final digest */ - memcpy ( out, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); + /* Add chunk to hash */ + for ( i = 0 ; i < 5 ; i++ ) + dd->digest.h[i] += digest->h[i]; } /** SHA-1 algorithm */ -struct digest_algorithm sha1_algorithm = { - .name = "sha1", - .ctxsize = sizeof ( struct sha1_context ), - .blocksize = sizeof ( union sha1_block ), - .digestsize = sizeof ( struct sha1_digest ), - .init = sha1_init, - .update = sha1_update, - .final = sha1_final, -}; +MDHASH_ALGORITHM ( sha1, sha1_algorithm, sha1_compress, __BIG_ENDIAN, + struct sha1_digest_data, sha1_init, SHA1_DIGEST_SIZE ); diff --git a/src/crypto/sha224.c b/src/crypto/sha224.c index 4eb55051e..a71b3dc10 100644 --- a/src/crypto/sha224.c +++ b/src/crypto/sha224.c @@ -30,25 +30,16 @@ FILE_SECBOOT ( PERMITTED ); * */ -#include -#include #include #include /** SHA-224 initial digest values */ -static const struct sha256_digest sha224_init_digest = { +static const struct sha256_digest sha224_init = { .h = { - cpu_to_be32 ( 0xc1059ed8 ), - cpu_to_be32 ( 0x367cd507 ), - cpu_to_be32 ( 0x3070dd17 ), - cpu_to_be32 ( 0xf70e5939 ), - cpu_to_be32 ( 0xffc00b31 ), - cpu_to_be32 ( 0x68581511 ), - cpu_to_be32 ( 0x64f98fa7 ), - cpu_to_be32 ( 0xbefa4fa4 ), - }, + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, + 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, + } }; /** SHA-224 algorithm */ -SHA256_ALGORITHM ( sha224, sha224_algorithm, SHA224_DIGEST_SIZE, - &sha224_init_digest ); +SHA256_ALGORITHM ( sha224, sha224_algorithm, sha224_init, SHA224_DIGEST_SIZE ); diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index 9d87ca10a..6e203d428 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED ); */ #include -#include -#include #include #include #include @@ -40,9 +38,7 @@ FILE_SECBOOT ( PERMITTED ); /** SHA-256 variables */ struct sha256_variables { - /* This layout matches that of struct sha256_digest_data, - * allowing for efficient endianness-conversion, - */ + /* This layout matches that of struct sha256_digest_data */ uint32_t a; uint32_t b; uint32_t c; @@ -51,7 +47,8 @@ struct sha256_variables { uint32_t f; uint32_t g; uint32_t h; - uint32_t w[SHA256_ROUNDS]; + /* We reuse w[0..15] to construct w[16..63] on demand */ + uint32_t w[16]; } __attribute__ (( packed )); /** SHA-256 constants */ @@ -70,53 +67,35 @@ static const uint32_t k[SHA256_ROUNDS] = { }; /** SHA-256 initial digest values */ -static const struct sha256_digest sha256_init_digest = { +static const struct sha256_digest sha256_init = { .h = { - cpu_to_be32 ( 0x6a09e667 ), - cpu_to_be32 ( 0xbb67ae85 ), - cpu_to_be32 ( 0x3c6ef372 ), - cpu_to_be32 ( 0xa54ff53a ), - cpu_to_be32 ( 0x510e527f ), - cpu_to_be32 ( 0x9b05688c ), - cpu_to_be32 ( 0x1f83d9ab ), - cpu_to_be32 ( 0x5be0cd19 ), - }, + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, + } }; -/** - * Initialise SHA-256 algorithm - * - * @v digest Digest algorithm - * @v ctx SHA-256 context - */ -void sha256_init ( struct digest_algorithm *digest, void *ctx ) { - struct sha256_algorithm *sha = digest->priv; - struct sha256_context *context = ctx; - - context->len = 0; - memcpy ( &context->ddd.dd.digest, sha->init, - sizeof ( context->ddd.dd.digest ) ); -} - /** * Calculate SHA-256 digest of accumulated data * - * @v context SHA-256 context + * @v dd Digest and data block + * @v digest Copy of current digest value */ -static void sha256_digest ( struct sha256_context *context ) { +void sha256_compress ( struct sha256_digest_data *dd, + const struct sha256_digest *digest ) { union { - union sha256_digest_data_dwords ddd; + struct sha256_digest_data dd; struct sha256_variables v; - } u; - uint32_t *a = &u.v.a; - uint32_t *b = &u.v.b; - uint32_t *c = &u.v.c; - uint32_t *d = &u.v.d; - uint32_t *e = &u.v.e; - uint32_t *f = &u.v.f; - uint32_t *g = &u.v.g; - uint32_t *h = &u.v.h; - uint32_t *w = u.v.w; + } *u = container_of ( dd, typeof ( *u ), dd ); + struct sha256_variables *v = &u->v; + uint32_t *a = &v->a; + uint32_t *b = &v->b; + uint32_t *c = &v->c; + uint32_t *d = &v->d; + uint32_t *e = &v->e; + uint32_t *f = &v->f; + uint32_t *g = &v->g; + uint32_t *h = &v->h; + uint32_t *w = v->w; uint32_t s0; uint32_t s1; uint32_t maj; @@ -126,40 +105,16 @@ static void sha256_digest ( struct sha256_context *context ) { unsigned int i; /* Sanity checks */ - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - build_assert ( &u.ddd.dd.digest.h[0] == a ); - build_assert ( &u.ddd.dd.digest.h[1] == b ); - build_assert ( &u.ddd.dd.digest.h[2] == c ); - build_assert ( &u.ddd.dd.digest.h[3] == d ); - build_assert ( &u.ddd.dd.digest.h[4] == e ); - build_assert ( &u.ddd.dd.digest.h[5] == f ); - build_assert ( &u.ddd.dd.digest.h[6] == g ); - build_assert ( &u.ddd.dd.digest.h[7] == h ); - build_assert ( &u.ddd.dd.data.dword[0] == w ); - - DBGC ( context, "SHA256 digesting:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); - DBGC_HDA ( context, context->len, &context->ddd.dd.data, - sizeof ( context->ddd.dd.data ) ); - - /* Convert h[0..7] to host-endian, and initialise a, b, c, d, - * e, f, g, h, and w[0..15] - */ - for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / - sizeof ( u.ddd.dword[0] ) ) ; i++ ) { - be32_to_cpus ( &context->ddd.dword[i] ); - u.ddd.dword[i] = context->ddd.dword[i]; - } - - /* Initialise w[16..63] */ - for ( i = 16 ; i < SHA256_ROUNDS ; i++ ) { - s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^ - ( w[i-15] >> 3 ) ); - s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^ - ( w[i-2] >> 10 ) ); - w[i] = ( w[i-16] + s0 + w[i-7] + s1 ); - } + build_assert ( &u->dd.digest.h[0] == a ); + build_assert ( &u->dd.digest.h[1] == b ); + build_assert ( &u->dd.digest.h[2] == c ); + build_assert ( &u->dd.digest.h[3] == d ); + build_assert ( &u->dd.digest.h[4] == e ); + build_assert ( &u->dd.digest.h[5] == f ); + build_assert ( &u->dd.digest.h[6] == g ); + build_assert ( &u->dd.digest.h[7] == h ); + build_assert ( &u->dd.data.dword[0] == w ); + build_assert ( sizeof ( u->dd ) == sizeof ( u->v ) ); /* Main loop */ for ( i = 0 ; i < SHA256_ROUNDS ; i++ ) { @@ -168,7 +123,7 @@ static void sha256_digest ( struct sha256_context *context ) { t2 = ( s0 + maj ); s1 = ( ror32 ( *e, 6 ) ^ ror32 ( *e, 11 ) ^ ror32 ( *e, 25 ) ); ch = ( ( *e & *f ) ^ ( (~*e) & *g ) ); - t1 = ( *h + s1 + ch + k[i] + w[i] ); + t1 = ( *h + s1 + ch + k[i] + w[ i % 16 ] ); *h = *g; *g = *f; *f = *e; @@ -177,79 +132,23 @@ static void sha256_digest ( struct sha256_context *context ) { *c = *b; *b = *a; *a = ( t1 + t2 ); - DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x %08x %08x " - "%08x\n", i, *a, *b, *c, *d, *e, *f, *g, *h ); + s0 = ( ror32 ( w[ ( i - 15 ) % 16 ], 7 ) ^ + ror32 ( w[ ( i - 15 ) % 16 ], 18 ) ^ + ( w[ ( i - 15 ) % 16 ] >> 3 ) ); + s1 = ( ror32 ( w[ ( i - 2 ) % 16 ], 17 ) ^ + ror32 ( w[ ( i - 2 ) % 16 ], 19 ) ^ + ( w[ ( i - 2 ) % 16 ] >> 10 ) ); + w[ i % 16 ] = ( w[ ( i - 16 ) % 16 ] + s0 + + w[ ( i - 7 ) % 16 ] + s1 ); + DBGC2 ( &sha256_algorithm, + "%2d : %08x %08x %08x %08x %08x %08x %08x %08x\n", + i, *a, *b, *c, *d, *e, *f, *g, *h ); } - /* Add chunk to hash and convert back to big-endian */ - for ( i = 0 ; i < 8 ; i++ ) { - context->ddd.dd.digest.h[i] = - cpu_to_be32 ( context->ddd.dd.digest.h[i] + - u.ddd.dd.digest.h[i] ); - } - - DBGC ( context, "SHA256 digested:\n" ); - DBGC_HDA ( context, 0, &context->ddd.dd.digest, - sizeof ( context->ddd.dd.digest ) ); -} - -/** - * Accumulate data with SHA-256 algorithm - * - * @v digest Digest algorithm - * @v ctx SHA-256 context - * @v data Data - * @v len Length of data - */ -void sha256_update ( struct digest_algorithm *digest __unused, void *ctx, - const void *data, size_t len ) { - struct sha256_context *context = ctx; - const uint8_t *byte = data; - size_t offset; - - /* Accumulate data a byte at a time, performing the digest - * whenever we fill the data buffer - */ - while ( len-- ) { - offset = ( context->len % sizeof ( context->ddd.dd.data ) ); - context->ddd.dd.data.byte[offset] = *(byte++); - context->len++; - if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) - sha256_digest ( context ); - } -} - -/** - * Generate SHA-256 digest - * - * @v digest Digest algorithm - * @v ctx SHA-256 context - * @v out Output buffer - */ -void sha256_final ( struct digest_algorithm *digest, void *ctx, void *out ) { - struct sha256_context *context = ctx; - uint64_t len_bits; - uint8_t pad; - - /* Record length before pre-processing */ - len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 ); - - /* Pad with a single "1" bit followed by as many "0" bits as required */ - pad = 0x80; - do { - sha256_update ( digest, ctx, &pad, sizeof ( pad ) ); - pad = 0x00; - } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != - offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); - - /* Append length (in bits) */ - sha256_update ( digest, ctx, &len_bits, sizeof ( len_bits ) ); - assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); - - /* Copy out final digest */ - memcpy ( out, &context->ddd.dd.digest, digest->digestsize ); + /* Add chunk to hash */ + for ( i = 0 ; i < 8 ; i++ ) + dd->digest.h[i] += digest->h[i]; } /** SHA-256 algorithm */ -SHA256_ALGORITHM ( sha256, sha256_algorithm, SHA256_DIGEST_SIZE, - &sha256_init_digest ); +SHA256_ALGORITHM ( sha256, sha256_algorithm, sha256_init, SHA256_DIGEST_SIZE ); diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c index fd624cc51..5c3384436 100644 --- a/src/crypto/sha384.c +++ b/src/crypto/sha384.c @@ -30,25 +30,18 @@ FILE_SECBOOT ( PERMITTED ); * */ -#include -#include #include #include /** SHA-384 initial digest values */ -static const struct sha512_digest sha384_init_digest = { +static const struct sha512_digest sha384_init = { .h = { - cpu_to_be64 ( 0xcbbb9d5dc1059ed8ULL ), - cpu_to_be64 ( 0x629a292a367cd507ULL ), - cpu_to_be64 ( 0x9159015a3070dd17ULL ), - cpu_to_be64 ( 0x152fecd8f70e5939ULL ), - cpu_to_be64 ( 0x67332667ffc00b31ULL ), - cpu_to_be64 ( 0x8eb44a8768581511ULL ), - cpu_to_be64 ( 0xdb0c2e0d64f98fa7ULL ), - cpu_to_be64 ( 0x47b5481dbefa4fa4ULL ), - }, + 0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL, + } }; /** SHA-384 algorithm */ -SHA512_ALGORITHM ( sha384, sha384_algorithm, SHA384_DIGEST_SIZE, - &sha384_init_digest ); +SHA512_ALGORITHM ( sha384, sha384_algorithm, sha384_init, SHA384_DIGEST_SIZE ); diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c index 5f6276095..12bc881a2 100644 --- a/src/crypto/sha512.c +++ b/src/crypto/sha512.c @@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED ); */ #include -#include -#include #include #include #include @@ -40,9 +38,7 @@ FILE_SECBOOT ( PERMITTED ); /** SHA-512 variables */ struct sha512_variables { - /* This layout matches that of struct sha512_digest_data, - * allowing for efficient endianness-conversion, - */ + /* This layout matches that of struct sha512_digest_data */ uint64_t a; uint64_t b; uint64_t c; @@ -51,7 +47,8 @@ struct sha512_variables { uint64_t f; uint64_t g; uint64_t h; - uint64_t w[SHA512_ROUNDS]; + /* We reuse w[0..15] to construct w[16..79] on demand */ + uint64_t w[16]; } __attribute__ (( packed )); /** SHA-512 constants */ @@ -86,53 +83,37 @@ static const uint64_t k[SHA512_ROUNDS] = { }; /** SHA-512 initial digest values */ -static const struct sha512_digest sha512_init_digest = { +static const struct sha512_digest sha512_init = { .h = { - cpu_to_be64 ( 0x6a09e667f3bcc908ULL ), - cpu_to_be64 ( 0xbb67ae8584caa73bULL ), - cpu_to_be64 ( 0x3c6ef372fe94f82bULL ), - cpu_to_be64 ( 0xa54ff53a5f1d36f1ULL ), - cpu_to_be64 ( 0x510e527fade682d1ULL ), - cpu_to_be64 ( 0x9b05688c2b3e6c1fULL ), - cpu_to_be64 ( 0x1f83d9abfb41bd6bULL ), - cpu_to_be64 ( 0x5be0cd19137e2179ULL ), - }, + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL, + } }; -/** - * Initialise SHA-512 algorithm - * - * @v digest Digest algorithm - * @v ctx SHA-512 context - */ -void sha512_init ( struct digest_algorithm *digest, void *ctx ) { - const struct sha512_algorithm *sha = digest->priv; - struct sha512_context *context = ctx; - - context->len = 0; - memcpy ( &context->ddq.dd.digest, sha->init, - sizeof ( context->ddq.dd.digest ) ); -} - /** * Calculate SHA-512 digest of accumulated data * - * @v context SHA-512 context + * @v dd Digest and data block + * @v digest Copy of current digest value */ -static void sha512_digest ( struct sha512_context *context ) { +void sha512_compress ( struct sha512_digest_data *dd, + const struct sha512_digest *digest ) { union { - union sha512_digest_data_qwords ddq; + struct sha512_digest_data dd; struct sha512_variables v; - } u; - uint64_t *a = &u.v.a; - uint64_t *b = &u.v.b; - uint64_t *c = &u.v.c; - uint64_t *d = &u.v.d; - uint64_t *e = &u.v.e; - uint64_t *f = &u.v.f; - uint64_t *g = &u.v.g; - uint64_t *h = &u.v.h; - uint64_t *w = u.v.w; + } *u = container_of ( dd, typeof ( *u ), dd ); + struct sha512_variables *v = &u->v; + uint64_t *a = &v->a; + uint64_t *b = &v->b; + uint64_t *c = &v->c; + uint64_t *d = &v->d; + uint64_t *e = &v->e; + uint64_t *f = &v->f; + uint64_t *g = &v->g; + uint64_t *h = &v->h; + uint64_t *w = v->w; uint64_t s0; uint64_t s1; uint64_t maj; @@ -142,40 +123,16 @@ static void sha512_digest ( struct sha512_context *context ) { unsigned int i; /* Sanity checks */ - assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 ); - build_assert ( &u.ddq.dd.digest.h[0] == a ); - build_assert ( &u.ddq.dd.digest.h[1] == b ); - build_assert ( &u.ddq.dd.digest.h[2] == c ); - build_assert ( &u.ddq.dd.digest.h[3] == d ); - build_assert ( &u.ddq.dd.digest.h[4] == e ); - build_assert ( &u.ddq.dd.digest.h[5] == f ); - build_assert ( &u.ddq.dd.digest.h[6] == g ); - build_assert ( &u.ddq.dd.digest.h[7] == h ); - build_assert ( &u.ddq.dd.data.qword[0] == w ); - - DBGC ( context, "SHA512 digesting:\n" ); - DBGC_HDA ( context, 0, &context->ddq.dd.digest, - sizeof ( context->ddq.dd.digest ) ); - DBGC_HDA ( context, context->len, &context->ddq.dd.data, - sizeof ( context->ddq.dd.data ) ); - - /* Convert h[0..7] to host-endian, and initialise a, b, c, d, - * e, f, g, h, and w[0..15] - */ - for ( i = 0 ; i < ( sizeof ( u.ddq.qword ) / - sizeof ( u.ddq.qword[0] ) ) ; i++ ) { - be64_to_cpus ( &context->ddq.qword[i] ); - u.ddq.qword[i] = context->ddq.qword[i]; - } - - /* Initialise w[16..79] */ - for ( i = 16 ; i < SHA512_ROUNDS ; i++ ) { - s0 = ( ror64 ( w[i-15], 1 ) ^ ror64 ( w[i-15], 8 ) ^ - ( w[i-15] >> 7 ) ); - s1 = ( ror64 ( w[i-2], 19 ) ^ ror64 ( w[i-2], 61 ) ^ - ( w[i-2] >> 6 ) ); - w[i] = ( w[i-16] + s0 + w[i-7] + s1 ); - } + build_assert ( &u->dd.digest.h[0] == a ); + build_assert ( &u->dd.digest.h[1] == b ); + build_assert ( &u->dd.digest.h[2] == c ); + build_assert ( &u->dd.digest.h[3] == d ); + build_assert ( &u->dd.digest.h[4] == e ); + build_assert ( &u->dd.digest.h[5] == f ); + build_assert ( &u->dd.digest.h[6] == g ); + build_assert ( &u->dd.digest.h[7] == h ); + build_assert ( &u->dd.data.qword[0] == w ); + build_assert ( sizeof ( u->dd ) == sizeof ( u->v ) ); /* Main loop */ for ( i = 0 ; i < SHA512_ROUNDS ; i++ ) { @@ -184,7 +141,7 @@ static void sha512_digest ( struct sha512_context *context ) { t2 = ( s0 + maj ); s1 = ( ror64 ( *e, 14 ) ^ ror64 ( *e, 18 ) ^ ror64 ( *e, 41 ) ); ch = ( ( *e & *f ) ^ ( (~*e) & *g ) ); - t1 = ( *h + s1 + ch + k[i] + w[i] ); + t1 = ( *h + s1 + ch + k[i] + w[ i % 16 ] ); *h = *g; *g = *f; *f = *e; @@ -193,83 +150,23 @@ static void sha512_digest ( struct sha512_context *context ) { *c = *b; *b = *a; *a = ( t1 + t2 ); - DBGC2 ( context, "%2d : %016llx %016llx %016llx %016llx " - "%016llx %016llx %016llx %016llx\n", + s0 = ( ror64 ( w[ ( i - 15 ) % 16 ], 1 ) ^ + ror64 ( w[ ( i - 15 ) % 16 ], 8 ) ^ + ( w[ ( i - 15 ) % 16 ] >> 7 ) ); + s1 = ( ror64 ( w[ ( i - 2 ) % 16 ], 19 ) ^ + ror64 ( w[ ( i - 2 ) % 16 ], 61 ) ^ + ( w[ ( i - 2 ) % 16 ] >> 6 ) ); + w[ i % 16 ] = ( w[ ( i - 16 ) % 16 ] + s0 + + w[ ( i - 7 ) % 16 ] + s1 ); + DBGC2 ( &sha512_algorithm, "%2d : %016llx %016llx %016llx " + "%016llx %016llx %016llx %016llx %016llx\n", i, *a, *b, *c, *d, *e, *f, *g, *h ); } - /* Add chunk to hash and convert back to big-endian */ - for ( i = 0 ; i < 8 ; i++ ) { - context->ddq.dd.digest.h[i] = - cpu_to_be64 ( context->ddq.dd.digest.h[i] + - u.ddq.dd.digest.h[i] ); - } - - DBGC ( context, "SHA512 digested:\n" ); - DBGC_HDA ( context, 0, &context->ddq.dd.digest, - sizeof ( context->ddq.dd.digest ) ); -} - -/** - * Accumulate data with SHA-512 algorithm - * - * @v digest Digest - * @v ctx SHA-512 context - * @v data Data - * @v len Length of data - */ -void sha512_update ( struct digest_algorithm *digest __unused, void *ctx, - const void *data, size_t len ) { - struct sha512_context *context = ctx; - const uint8_t *byte = data; - size_t offset; - - /* Accumulate data a byte at a time, performing the digest - * whenever we fill the data buffer - */ - while ( len-- ) { - offset = ( context->len % sizeof ( context->ddq.dd.data ) ); - context->ddq.dd.data.byte[offset] = *(byte++); - context->len++; - if ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 ) - sha512_digest ( context ); - } -} - -/** - * Generate SHA-512 digest - * - * @v digest Digest algorithm - * @v ctx SHA-512 context - * @v out Output buffer - */ -void sha512_final ( struct digest_algorithm *digest, void *ctx, void *out ) { - struct sha512_context *context = ctx; - uint64_t len_bits_hi; - uint64_t len_bits_lo; - uint8_t pad; - - /* Record length before pre-processing */ - len_bits_hi = 0; - len_bits_lo = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 ); - - /* Pad with a single "1" bit followed by as many "0" bits as required */ - pad = 0x80; - do { - sha512_update ( digest, ctx, &pad, sizeof ( pad ) ); - pad = 0x00; - } while ( ( context->len % sizeof ( context->ddq.dd.data ) ) != - offsetof ( typeof ( context->ddq.dd.data ), final.len_hi ) ); - - /* Append length (in bits) */ - sha512_update ( digest, ctx, &len_bits_hi, sizeof ( len_bits_hi ) ); - sha512_update ( digest, ctx, &len_bits_lo, sizeof ( len_bits_lo ) ); - assert ( ( context->len % sizeof ( context->ddq.dd.data ) ) == 0 ); - - /* Copy out final digest */ - memcpy ( out, &context->ddq.dd.digest, digest->digestsize ); + /* Add chunk to hash */ + for ( i = 0 ; i < 8 ; i++ ) + dd->digest.h[i] += digest->h[i]; } /** SHA-512 algorithm */ -SHA512_ALGORITHM ( sha512, sha512_algorithm, SHA512_DIGEST_SIZE, - &sha512_init_digest ); +SHA512_ALGORITHM ( sha512, sha512_algorithm, sha512_init, SHA512_DIGEST_SIZE ); diff --git a/src/crypto/sha512_224.c b/src/crypto/sha512_224.c index d9e0eb18d..c622ff33a 100644 --- a/src/crypto/sha512_224.c +++ b/src/crypto/sha512_224.c @@ -30,25 +30,19 @@ FILE_SECBOOT ( PERMITTED ); * */ -#include -#include #include #include /** SHA-512/224 initial digest values */ -static const struct sha512_digest sha512_224_init_digest = { +static const struct sha512_digest sha512_224_init = { .h = { - cpu_to_be64 ( 0x8c3d37c819544da2ULL ), - cpu_to_be64 ( 0x73e1996689dcd4d6ULL ), - cpu_to_be64 ( 0x1dfab7ae32ff9c82ULL ), - cpu_to_be64 ( 0x679dd514582f9fcfULL ), - cpu_to_be64 ( 0x0f6d2b697bd44da8ULL ), - cpu_to_be64 ( 0x77e36f7304c48942ULL ), - cpu_to_be64 ( 0x3f9d85a86a1d36c8ULL ), - cpu_to_be64 ( 0x1112e6ad91d692a1ULL ), - }, + 0x8c3d37c819544da2ULL, 0x73e1996689dcd4d6ULL, + 0x1dfab7ae32ff9c82ULL, 0x679dd514582f9fcfULL, + 0x0f6d2b697bd44da8ULL, 0x77e36f7304c48942ULL, + 0x3f9d85a86a1d36c8ULL, 0x1112e6ad91d692a1ULL, + } }; /** SHA-512/224 algorithm */ -SHA512_ALGORITHM ( sha512_224, sha512_224_algorithm, SHA512_224_DIGEST_SIZE, - &sha512_224_init_digest ); +SHA512_ALGORITHM ( sha512_224, sha512_224_algorithm, sha512_224_init, + SHA512_224_DIGEST_SIZE ); diff --git a/src/crypto/sha512_256.c b/src/crypto/sha512_256.c index c8fd1a47f..4c0b0418d 100644 --- a/src/crypto/sha512_256.c +++ b/src/crypto/sha512_256.c @@ -30,25 +30,19 @@ FILE_SECBOOT ( PERMITTED ); * */ -#include -#include #include #include /** SHA-512/256 initial digest values */ -static const struct sha512_digest sha512_256_init_digest = { +static const struct sha512_digest sha512_256_init = { .h = { - cpu_to_be64 ( 0x22312194fc2bf72cULL ), - cpu_to_be64 ( 0x9f555fa3c84c64c2ULL ), - cpu_to_be64 ( 0x2393b86b6f53b151ULL ), - cpu_to_be64 ( 0x963877195940eabdULL ), - cpu_to_be64 ( 0x96283ee2a88effe3ULL ), - cpu_to_be64 ( 0xbe5e1e2553863992ULL ), - cpu_to_be64 ( 0x2b0199fc2c85b8aaULL ), - cpu_to_be64 ( 0x0eb72ddc81c52ca2ULL ), - }, + 0x22312194fc2bf72cULL, 0x9f555fa3c84c64c2ULL, + 0x2393b86b6f53b151ULL, 0x963877195940eabdULL, + 0x96283ee2a88effe3ULL, 0xbe5e1e2553863992ULL, + 0x2b0199fc2c85b8aaULL, 0x0eb72ddc81c52ca2ULL, + } }; /** SHA-512/256 algorithm */ -SHA512_ALGORITHM ( sha512_256, sha512_256_algorithm, SHA512_256_DIGEST_SIZE, - &sha512_256_init_digest ); +SHA512_ALGORITHM ( sha512_256, sha512_256_algorithm, sha512_256_init, + SHA512_256_DIGEST_SIZE ); diff --git a/src/include/ipxe/md4.h b/src/include/ipxe/md4.h index 60512993b..bd863ba21 100644 --- a/src/include/ipxe/md4.h +++ b/src/include/ipxe/md4.h @@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED ); #include #include +#include /** An MD4 digest */ struct md4_digest { @@ -46,25 +47,8 @@ struct md4_digest_data { union md4_block data; } __attribute__ (( packed )); -/** MD4 digest and data block */ -union md4_digest_data_dwords { - /** Digest and data block */ - struct md4_digest_data dd; - /** Raw dwords */ - uint32_t dword[ sizeof ( struct md4_digest_data ) / - sizeof ( uint32_t ) ]; -}; - -/** An MD4 context */ -struct md4_context { - /** Amount of accumulated data */ - size_t len; - /** Digest and accumulated data */ - union md4_digest_data_dwords ddd; -} __attribute__ (( packed )); - /** MD4 context size */ -#define MD4_CTX_SIZE sizeof ( struct md4_context ) +#define MD4_CTX_SIZE MDHASH_CTX_SIZE ( struct md4_digest_data ) /** MD4 block size */ #define MD4_BLOCK_SIZE sizeof ( union md4_block ) diff --git a/src/include/ipxe/md5.h b/src/include/ipxe/md5.h index 275e63824..cad594e12 100644 --- a/src/include/ipxe/md5.h +++ b/src/include/ipxe/md5.h @@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED ); #include #include +#include /** An MD5 digest */ struct md5_digest { @@ -46,25 +47,8 @@ struct md5_digest_data { union md5_block data; } __attribute__ (( packed )); -/** MD5 digest and data block */ -union md5_digest_data_dwords { - /** Digest and data block */ - struct md5_digest_data dd; - /** Raw dwords */ - uint32_t dword[ sizeof ( struct md5_digest_data ) / - sizeof ( uint32_t ) ]; -}; - -/** An MD5 context */ -struct md5_context { - /** Amount of accumulated data */ - size_t len; - /** Digest and accumulated data */ - union md5_digest_data_dwords ddd; -} __attribute__ (( packed )); - /** MD5 context size */ -#define MD5_CTX_SIZE sizeof ( struct md5_context ) +#define MD5_CTX_SIZE MDHASH_CTX_SIZE ( struct md5_digest_data ) /** MD5 block size */ #define MD5_BLOCK_SIZE sizeof ( union md5_block ) diff --git a/src/include/ipxe/mdhash.h b/src/include/ipxe/mdhash.h new file mode 100644 index 000000000..3589b4e62 --- /dev/null +++ b/src/include/ipxe/mdhash.h @@ -0,0 +1,171 @@ +#ifndef _IPXE_MDHASH_H +#define _IPXE_MDHASH_H + +/** @file + * + * Merkle-Damgård hash algorithms + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +FILE_SECBOOT ( PERMITTED ); + +#include +#include +#include +#include + +/** Merkle-Damgård hash algorithm digest and data block */ +#define mdhash_dd_t( digestsize, blocksize ) \ + struct { \ + /** Digest of data already processed */ \ + uint8_t digest[ (digestsize) ]; \ + /** Accumulated data */ \ + uint8_t data[ (blocksize) ]; \ + } __attribute__ (( packed )) + +/** Merkle-Damgård hash algorithm context */ +#define mdhash_context_t( digestsize, blocksize ) \ + struct { \ + /** Amount of accumulated data */ \ + size_t len; \ + /** Digest and accumulated data */ \ + mdhash_dd_t ( (digestsize), (blocksize) ) dd; \ + } + +/** Merkle-Damgård trailing bit-length count */ +union mdhash_len { + /** Raw bytes */ + uint8_t byte[16]; + /** Host-endian qwords */ + struct { + /** Bit length */ + uint64_t bits; + /** Padding */ + uint64_t pad; + } __attribute__ (( packed )) qword; +}; + +/** Merkle-Damgård hash algorithm */ +struct mdhash_algorithm { + /** + * Compression function + * + * @v dd Digest and accumulated data + * @v digest Copy of current digest value + * + * We provide a read-only copy of the current digest value + * since most compression functions would otherwise have to + * make this copy themselves. + */ + void ( * compress ) ( void *dd, const void *digest ); + /** Initial digest value (as host-endian words) */ + const void *init; + /** Digest size (before any final truncation) */ + uint8_t digestsize; + /** Data toggle (for endianness swapping) + * + * This is the value to be XORed with a byte offset in the + * input data stream to obtain the byte offset within the + * internal word array. + * + * This same value is also XORed with a byte offset in the + * internal word array to obtain the byte offset within the + * digest output. + */ + uint8_t toggle; + /** Length field length + * + * This is the length (in bytes) of the trailing bit-length + * field (used for Merkle-Damgård strengthening). + */ + uint8_t len_len; + /** Length field toggle (for endianness swapping) + * + * This is the value to be XORed with the byte offset within a + * host-endian 64-bit integer to obtain the byte offset within + * the trailing bit-length field. + */ + uint8_t len_toggle; +}; + +/** Merkle-Damgård hash algorithm digest and data block sample pointer */ +#define MDHASH_DD_PTR( _dd ) ( ( typeof (_dd) * ) NULL ) + +/** Merkle-Damgård hash algorithm compression function sample pointer */ +#define MDHASH_COMPRESS_PTR( _dd ) \ + ( ( void ( * ) \ + ( _dd *, const typeof ( MDHASH_DD_PTR (_dd)->digest ) * ) ) \ + NULL ) + +/** Merkle-Damgård hash algorithm digest size */ +#define MDHASH_DIGEST_SIZE( _dd ) \ + ( sizeof ( MDHASH_DD_PTR (_dd)->digest ) ) + +/** Merkle-Damgård hash algorithm data toggle */ +#define MDHASH_TOGGLE( _dd, _byteorder ) \ + ( ( (_byteorder) == __BYTE_ORDER ) ? 0 : \ + ( sizeof ( MDHASH_DD_PTR (_dd)->digest.h[0] ) - 1 ) ) + +/** Merkle-Damgård hash algorithm length field length */ +#define MDHASH_LEN_LEN( _dd ) \ + ( sizeof ( MDHASH_DD_PTR (_dd)->data.final.len ) ) + +/** Merkle-Damgård hash algorithm length field toggle */ +#define MDHASH_LEN_TOGGLE( _dd, _byteorder ) \ + ( ( ( (_byteorder) == __BYTE_ORDER ) ? 0 : \ + ( sizeof ( uint64_t ) - 1 ) ) | \ + ( sizeof ( MDHASH_DD_PTR (_dd)->data.final.len ) - \ + sizeof ( uint64_t ) ) ) + +/** Merkle-Damgård hash algorithm block size */ +#define MDHASH_BLOCK_SIZE( _dd ) \ + ( sizeof ( MDHASH_DD_PTR (_dd)->data ) ) + +/** Merkle-Damgård hash algorithm context size */ +#define MDHASH_CTX_SIZE( _dd ) \ + ( sizeof ( mdhash_context_t ( MDHASH_DIGEST_SIZE (_dd), \ + MDHASH_BLOCK_SIZE (_dd) ) ) ) + +extern void mdhash_init ( struct digest_algorithm *digest, void *ctx ); +extern void mdhash_update ( struct digest_algorithm *digest, void *ctx, + const void *src, size_t len ); +extern void mdhash_final ( struct digest_algorithm *digest, void *ctx, + void *out ); + +/** Define a Merkle-Damgård hash algorithm */ +#define MDHASH_ALGORITHM( _name, _digest, _compress, _byteorder, \ + _dd, _init, _digestsize ) \ + static_assert ( sizeof (_init) == MDHASH_DIGEST_SIZE (_dd) ); \ + static_assert ( (_digestsize) <= MDHASH_DIGEST_SIZE (_dd) ); \ + static_assert ( offsetof ( _dd, digest ) == 0 ); \ + static_assert ( offsetof ( _dd, data ) == \ + MDHASH_DIGEST_SIZE (_dd) ); \ + static_assert ( sizeof ( * MDHASH_DD_PTR (_dd) ) == \ + ( MDHASH_DIGEST_SIZE (_dd) + \ + MDHASH_BLOCK_SIZE (_dd) ) ); \ + struct mdhash_algorithm _name ## _mdhash = { \ + .compress = ( ( MDHASH_COMPRESS_PTR (_dd) \ + == (_compress) ) \ + ? ( ( void * ) (_compress) ) \ + : ( ( void * ) (_compress) ) ), \ + .init = ( ( &( MDHASH_DD_PTR (_dd)->digest ) \ + == &(_init) ) \ + ? &(_init) : &(_init) ), \ + .digestsize = MDHASH_DIGEST_SIZE (_dd), \ + .toggle = MDHASH_TOGGLE (_dd, _byteorder), \ + .len_len = MDHASH_LEN_LEN (_dd), \ + .len_toggle = MDHASH_LEN_TOGGLE (_dd, _byteorder), \ + }; \ + struct digest_algorithm _digest = { \ + .name = #_name, \ + .ctxsize = MDHASH_CTX_SIZE (_dd), \ + .blocksize = MDHASH_BLOCK_SIZE (_dd), \ + .digestsize = (_digestsize), \ + .init = mdhash_init, \ + .update = mdhash_update, \ + .final = mdhash_final, \ + .priv = &_name ## _mdhash, \ + } + +#endif /* _IPXE_MDHASH_H */ diff --git a/src/include/ipxe/sha1.h b/src/include/ipxe/sha1.h index 33b07ecc3..56c5146d1 100644 --- a/src/include/ipxe/sha1.h +++ b/src/include/ipxe/sha1.h @@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED ); #include #include +#include /** An SHA-1 digest */ struct sha1_digest { @@ -46,25 +47,8 @@ struct sha1_digest_data { union sha1_block data; } __attribute__ (( packed )); -/** SHA-1 digest and data block */ -union sha1_digest_data_dwords { - /** Digest and data block */ - struct sha1_digest_data dd; - /** Raw dwords */ - uint32_t dword[ sizeof ( struct sha1_digest_data ) / - sizeof ( uint32_t ) ]; -}; - -/** An SHA-1 context */ -struct sha1_context { - /** Amount of accumulated data */ - size_t len; - /** Digest and accumulated data */ - union sha1_digest_data_dwords ddd; -} __attribute__ (( packed )); - /** SHA-1 context size */ -#define SHA1_CTX_SIZE sizeof ( struct sha1_context ) +#define SHA1_CTX_SIZE MDHASH_CTX_SIZE ( struct sha1_digest_data ) /** SHA-1 block size */ #define SHA1_BLOCK_SIZE sizeof ( union sha1_block ) diff --git a/src/include/ipxe/sha256.h b/src/include/ipxe/sha256.h index 9f8864806..6cf65ec90 100644 --- a/src/include/ipxe/sha256.h +++ b/src/include/ipxe/sha256.h @@ -11,7 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); FILE_SECBOOT ( PERMITTED ); #include +#include #include +#include /** SHA-256 number of rounds */ #define SHA256_ROUNDS 64 @@ -49,31 +51,8 @@ struct sha256_digest_data { union sha256_block data; } __attribute__ (( packed )); -/** SHA-256 digest and data block */ -union sha256_digest_data_dwords { - /** Digest and data block */ - struct sha256_digest_data dd; - /** Raw dwords */ - uint32_t dword[ sizeof ( struct sha256_digest_data ) / - sizeof ( uint32_t ) ]; -}; - -/** An SHA-256 context */ -struct sha256_context { - /** Amount of accumulated data */ - size_t len; - /** Digest and accumulated data */ - union sha256_digest_data_dwords ddd; -} __attribute__ (( packed )); - -/** A SHA-256 family algorithm */ -struct sha256_algorithm { - /** Initial digest values */ - const struct sha256_digest *init; -}; - /** SHA-256 context size */ -#define SHA256_CTX_SIZE sizeof ( struct sha256_context ) +#define SHA256_CTX_SIZE MDHASH_CTX_SIZE ( struct sha256_digest_data ) /** SHA-256 block size */ #define SHA256_BLOCK_SIZE sizeof ( union sha256_block ) @@ -84,27 +63,14 @@ struct sha256_algorithm { /** SHA-224 digest size */ #define SHA224_DIGEST_SIZE ( SHA256_DIGEST_SIZE * 224 / 256 ) -extern void sha256_init ( struct digest_algorithm *digest, void *ctx ); -extern void sha256_update ( struct digest_algorithm *digest, void *ctx, - const void *data, size_t len ); -extern void sha256_final ( struct digest_algorithm *digest, void *ctx, - void *out ); +extern void sha256_compress ( struct sha256_digest_data *dd, + const struct sha256_digest *digest ); /** Define a SHA-256 family digest algorithm */ -#define SHA256_ALGORITHM( _name, _digest, _digestsize, _init ) \ - static struct sha256_algorithm _name ## _sha256 = { \ - .init = (_init), \ - }; \ - struct digest_algorithm _digest = { \ - .name = #_name, \ - .ctxsize = sizeof ( struct sha256_context ), \ - .blocksize = sizeof ( union sha256_block ), \ - .digestsize = (_digestsize), \ - .init = sha256_init, \ - .update = sha256_update, \ - .final = sha256_final, \ - .priv = &_name ## _sha256, \ - } +#define SHA256_ALGORITHM( _name, _digest, _init, _digestsize ) \ + MDHASH_ALGORITHM( _name, _digest, sha256_compress, \ + __BIG_ENDIAN, struct sha256_digest_data, \ + _init, _digestsize ) extern struct digest_algorithm sha256_algorithm; extern struct digest_algorithm sha224_algorithm; diff --git a/src/include/ipxe/sha512.h b/src/include/ipxe/sha512.h index e7ac87389..fc3d8596b 100644 --- a/src/include/ipxe/sha512.h +++ b/src/include/ipxe/sha512.h @@ -11,7 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); FILE_SECBOOT ( PERMITTED ); #include +#include #include +#include /** SHA-512 number of rounds */ #define SHA512_ROUNDS 80 @@ -32,10 +34,13 @@ union sha512_block { struct { /** Padding */ uint8_t pad[112]; - /** High 64 bits of length in bits */ - uint64_t len_hi; - /** Low 64 bits of length in bits */ - uint64_t len_lo; + /** Length in bits */ + struct { + /** High 64 bits (unused by iPXE) */ + uint64_t hi; + /** Low 64 bits (unused by iPXE) */ + uint64_t lo; + } __attribute__ (( packed )) len; } final; }; @@ -51,31 +56,8 @@ struct sha512_digest_data { union sha512_block data; } __attribute__ (( packed )); -/** SHA-512 digest and data block */ -union sha512_digest_data_qwords { - /** Digest and data block */ - struct sha512_digest_data dd; - /** Raw qwords */ - uint64_t qword[ sizeof ( struct sha512_digest_data ) / - sizeof ( uint64_t ) ]; -}; - -/** An SHA-512 context */ -struct sha512_context { - /** Amount of accumulated data */ - size_t len; - /** Digest and accumulated data */ - union sha512_digest_data_qwords ddq; -} __attribute__ (( packed )); - -/** A SHA-512 family algorithm */ -struct sha512_algorithm { - /** Initial digest values */ - const struct sha512_digest *init; -}; - /** SHA-512 context size */ -#define SHA512_CTX_SIZE sizeof ( struct sha512_context ) +#define SHA512_CTX_SIZE MDHASH_CTX_SIZE ( struct sha512_digest_data ) /** SHA-512 block size */ #define SHA512_BLOCK_SIZE sizeof ( union sha512_block ) @@ -92,27 +74,14 @@ struct sha512_algorithm { /** SHA-512/224 digest size */ #define SHA512_224_DIGEST_SIZE ( SHA512_DIGEST_SIZE * 224 / 512 ) -extern void sha512_init ( struct digest_algorithm *digest, void *ctx ); -extern void sha512_update ( struct digest_algorithm *digest, void *ctx, - const void *data, size_t len ); -extern void sha512_final ( struct digest_algorithm *digest, void *ctx, - void *out ); +extern void sha512_compress ( struct sha512_digest_data *dd, + const struct sha512_digest *digest ); /** Define a SHA-512 family digest algorithm */ -#define SHA512_ALGORITHM( _name, _digest, _digestsize, _init ) \ - static struct sha512_algorithm _name ## _sha512 = { \ - .init = (_init), \ - }; \ - struct digest_algorithm _digest = { \ - .name = #_name, \ - .ctxsize = sizeof ( struct sha512_context ), \ - .blocksize = sizeof ( union sha512_block ), \ - .digestsize = (_digestsize), \ - .init = sha512_init, \ - .update = sha512_update, \ - .final = sha512_final, \ - .priv = &_name ## _sha512, \ - } +#define SHA512_ALGORITHM( _name, _digest, _init, _digestsize ) \ + MDHASH_ALGORITHM( _name, _digest, sha512_compress, \ + __BIG_ENDIAN, struct sha512_digest_data, \ + _init, _digestsize ) extern struct digest_algorithm sha512_algorithm; extern struct digest_algorithm sha384_algorithm;