1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00
putty-source/crypto/sha1.h
Simon Tatham fca13a17b1 Break up crypto modules containing HW acceleration.
This applies to all of AES, SHA-1, SHA-256 and SHA-512. All those
source files previously contained multiple implementations of the
algorithm, enabled or disabled by ifdefs detecting whether they would
work on a given compiler. And in order to get advanced machine
instructions like AES-NI or NEON crypto into the output file when the
compile flags hadn't enabled them, we had to do nasty stuff with
compiler-specific pragmas or attributes.

Now we can do the detection at cmake time, and enable advanced
instructions in the more sensible way, by compile-time flags. So I've
broken up each of these modules into lots of sub-pieces: a file called
(e.g.) 'foo-common.c' containing common definitions across all
implementations (such as round constants), one called 'foo-select.c'
containing the top-level vtable(s), and a separate file for each
implementation exporting just the vtable(s) for that implementation.

One advantage of this is that it depends a lot less on compiler-
specific bodgery. My particular least favourite part of the previous
setup was the part where I had to _manually_ define some Arm ACLE
feature macros before including <arm_neon.h>, so that it would define
the intrinsics I wanted. Now I'm enabling interesting architecture
features in the normal way, on the compiler command line, there's no
need for that kind of trick: the right feature macros are already
defined and <arm_neon.h> does the right thing.

Another change in this reorganisation is that I've stopped assuming
there's just one hardware implementation per platform. Previously, the
accelerated vtables were called things like sha256_hw, and varied
between FOO-NI and NEON depending on platform; and the selection code
would simply ask 'is hw available? if so, use hw, else sw'. Now, each
HW acceleration strategy names its vtable its own way, and the
selection vtable has a whole list of possibilities to iterate over
looking for a supported one. So if someone feels like writing a second
accelerated implementation of something for a given platform - for
example, I've heard you can use plain NEON to speed up AES somewhat
even without the crypto extension - then it will now have somewhere to
drop in alongside the existing ones.
2021-04-21 21:55:26 +01:00

110 lines
3.4 KiB
C

/*
* Definitions likely to be helpful to multiple SHA-1 implementations.
*/
/*
* The 'extra' structure used by SHA-1 implementations is used to
* include information about how to check if a given implementation is
* available at run time, and whether we've already checked.
*/
struct sha1_extra_mutable;
struct sha1_extra {
/* Function to check availability. Might be expensive, so we don't
* want to call it more than once. */
bool (*check_available)(void);
/* Point to a writable substructure. */
struct sha1_extra_mutable *mut;
};
struct sha1_extra_mutable {
bool checked_availability;
bool is_available;
};
static inline bool check_availability(const struct sha1_extra *extra)
{
if (!extra->mut->checked_availability) {
extra->mut->is_available = extra->check_available();
extra->mut->checked_availability = true;
}
return extra->mut->is_available;
}
/*
* Macro to define a SHA-1 vtable together with its 'extra'
* structure.
*/
#define SHA1_VTABLE(impl_c, impl_display) \
static struct sha1_extra_mutable sha1_ ## impl_c ## _extra_mut; \
static const struct sha1_extra sha1_ ## impl_c ## _extra = { \
.check_available = sha1_ ## impl_c ## _available, \
.mut = &sha1_ ## impl_c ## _extra_mut, \
}; \
const ssh_hashalg ssh_sha1_ ## impl_c = { \
.new = sha1_ ## impl_c ## _new, \
.reset = sha1_ ## impl_c ## _reset, \
.copyfrom = sha1_ ## impl_c ## _copyfrom, \
.digest = sha1_ ## impl_c ## _digest, \
.free = sha1_ ## impl_c ## _free, \
.hlen = 20, \
.blocklen = 64, \
HASHALG_NAMES_ANNOTATED("SHA-1", impl_display), \
.extra = &sha1_ ## impl_c ## _extra, \
}
extern const uint32_t sha1_initial_state[5];
#define SHA1_ROUNDS_PER_STAGE 20
#define SHA1_STAGE0_CONSTANT 0x5a827999
#define SHA1_STAGE1_CONSTANT 0x6ed9eba1
#define SHA1_STAGE2_CONSTANT 0x8f1bbcdc
#define SHA1_STAGE3_CONSTANT 0xca62c1d6
#define SHA1_ROUNDS (4 * SHA1_ROUNDS_PER_STAGE)
typedef struct sha1_block sha1_block;
struct sha1_block {
uint8_t block[64];
size_t used;
uint64_t len;
};
static inline void sha1_block_setup(sha1_block *blk)
{
blk->used = 0;
blk->len = 0;
}
static inline bool sha1_block_write(
sha1_block *blk, const void **vdata, size_t *len)
{
size_t blkleft = sizeof(blk->block) - blk->used;
size_t chunk = *len < blkleft ? *len : blkleft;
const uint8_t *p = *vdata;
memcpy(blk->block + blk->used, p, chunk);
*vdata = p + chunk;
*len -= chunk;
blk->used += chunk;
blk->len += chunk;
if (blk->used == sizeof(blk->block)) {
blk->used = 0;
return true;
}
return false;
}
static inline void sha1_block_pad(sha1_block *blk, BinarySink *bs)
{
uint64_t final_len = blk->len << 3;
size_t pad = 1 + (63 & (55 - blk->used));
put_byte(bs, 0x80);
for (size_t i = 1; i < pad; i++)
put_byte(bs, 0);
put_uint64(bs, final_len);
assert(blk->used == 0 && "Should have exactly hit a block boundary");
}