[crypto] Generalise implementation of Merkle-Damgård hash algorithms

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 <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2026-06-23 12:46:55 +01:00
parent 449d2acf3d
commit 327378a764
16 changed files with 585 additions and 908 deletions
+32 -132
View File
@@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED );
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
@@ -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 );
+32 -132
View File
@@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED );
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
@@ -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 );
+151
View File
@@ -0,0 +1,151 @@
/*
* Copyright (C) 2026 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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 <stdint.h>
#include <string.h>
#include <assert.h>
#include <ipxe/crypto.h>
#include <ipxe/mdhash.h>
/**
* 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 );
}
+41 -141
View File
@@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED );
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
@@ -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 );
+5 -14
View File
@@ -30,25 +30,16 @@ FILE_SECBOOT ( PERMITTED );
*
*/
#include <stdint.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/sha256.h>
/** 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 );
+49 -150
View File
@@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED );
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
@@ -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 ),
},
};
/**
* 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 ) );
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
}
};
/**
* 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 );
+7 -14
View File
@@ -30,25 +30,18 @@ FILE_SECBOOT ( PERMITTED );
*
*/
#include <stdint.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/sha512.h>
/** 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 );
+50 -153
View File
@@ -31,8 +31,6 @@ FILE_SECBOOT ( PERMITTED );
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <assert.h>
#include <ipxe/rotate.h>
#include <ipxe/crypto.h>
@@ -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 ),
},
};
/**
* 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 ) );
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL,
}
};
/**
* 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 );
+8 -14
View File
@@ -30,25 +30,19 @@ FILE_SECBOOT ( PERMITTED );
*
*/
#include <stdint.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/sha512.h>
/** 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 );
+8 -14
View File
@@ -30,25 +30,19 @@ FILE_SECBOOT ( PERMITTED );
*
*/
#include <stdint.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/sha512.h>
/** 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 );
+2 -18
View File
@@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/mdhash.h>
/** 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 )
+2 -18
View File
@@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/mdhash.h>
/** 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 )
+171
View File
@@ -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 <stdint.h>
#include <stddef.h>
#include <endian.h>
#include <ipxe/crypto.h>
/** 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 */
+2 -18
View File
@@ -12,6 +12,7 @@ FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <ipxe/crypto.h>
#include <ipxe/mdhash.h>
/** 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 )
+9 -43
View File
@@ -11,7 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <endian.h>
#include <ipxe/crypto.h>
#include <ipxe/mdhash.h>
/** 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;
+16 -47
View File
@@ -11,7 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
FILE_SECBOOT ( PERMITTED );
#include <stdint.h>
#include <endian.h>
#include <ipxe/crypto.h>
#include <ipxe/mdhash.h>
/** 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;