mirror of
https://github.com/ipxe/ipxe
synced 2026-06-29 00:07:28 +03:00
[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:
+32
-132
@@ -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
@@ -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 );
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 ),
|
||||
},
|
||||
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 );
|
||||
|
||||
+7
-14
@@ -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
@@ -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 ),
|
||||
},
|
||||
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 );
|
||||
|
||||
+8
-14
@@ -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
@@ -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
@@ -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
@@ -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 )
|
||||
|
||||
@@ -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
@@ -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 )
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user