mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
132 lines
4.9 KiB
C
132 lines
4.9 KiB
C
|
/*
|
||
|
* Definitions likely to be helpful to multiple SHA-512 implementations.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* The 'extra' structure used by SHA-512 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 sha512_extra_mutable;
|
||
|
struct sha512_extra {
|
||
|
/* Pointer to the initial state (distinguishes SHA-384 from -512) */
|
||
|
const uint64_t *initial_state;
|
||
|
|
||
|
/* 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 sha512_extra_mutable *mut;
|
||
|
};
|
||
|
struct sha512_extra_mutable {
|
||
|
bool checked_availability;
|
||
|
bool is_available;
|
||
|
};
|
||
|
static inline bool check_availability(const struct sha512_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 pair of SHA-{384,512} vtables together with their
|
||
|
* 'extra' structure.
|
||
|
*/
|
||
|
#define SHA512_VTABLES(impl_c, impl_display) \
|
||
|
static struct sha512_extra_mutable sha512_ ## impl_c ## _extra_mut; \
|
||
|
static const struct sha512_extra sha384_ ## impl_c ## _extra = { \
|
||
|
.initial_state = sha384_initial_state, \
|
||
|
.check_available = sha512_ ## impl_c ## _available, \
|
||
|
.mut = &sha512_ ## impl_c ## _extra_mut, \
|
||
|
}; \
|
||
|
static const struct sha512_extra sha512_ ## impl_c ## _extra = { \
|
||
|
.initial_state = sha512_initial_state, \
|
||
|
.check_available = sha512_ ## impl_c ## _available, \
|
||
|
.mut = &sha512_ ## impl_c ## _extra_mut, \
|
||
|
}; \
|
||
|
const ssh_hashalg ssh_sha384_ ## impl_c = { \
|
||
|
.new = sha512_ ## impl_c ## _new, \
|
||
|
.reset = sha512_ ## impl_c ## _reset, \
|
||
|
.copyfrom = sha512_ ## impl_c ## _copyfrom, \
|
||
|
.digest = sha384_ ## impl_c ## _digest, \
|
||
|
.free = sha512_ ## impl_c ## _free, \
|
||
|
.hlen = 48, \
|
||
|
.blocklen = 128, \
|
||
|
HASHALG_NAMES_ANNOTATED("SHA-384", impl_display), \
|
||
|
.extra = &sha384_ ## impl_c ## _extra, \
|
||
|
}; \
|
||
|
const ssh_hashalg ssh_sha512_ ## impl_c = { \
|
||
|
.new = sha512_ ## impl_c ## _new, \
|
||
|
.reset = sha512_ ## impl_c ## _reset, \
|
||
|
.copyfrom = sha512_ ## impl_c ## _copyfrom, \
|
||
|
.digest = sha512_ ## impl_c ## _digest, \
|
||
|
.free = sha512_ ## impl_c ## _free, \
|
||
|
.hlen = 64, \
|
||
|
.blocklen = 128, \
|
||
|
HASHALG_NAMES_ANNOTATED("SHA-512", impl_display), \
|
||
|
.extra = &sha512_ ## impl_c ## _extra, \
|
||
|
}
|
||
|
|
||
|
extern const uint64_t sha512_initial_state[8];
|
||
|
extern const uint64_t sha384_initial_state[8];
|
||
|
extern const uint64_t sha512_round_constants[80];
|
||
|
|
||
|
#define SHA512_ROUNDS 80
|
||
|
|
||
|
typedef struct sha512_block sha512_block;
|
||
|
struct sha512_block {
|
||
|
uint8_t block[128];
|
||
|
size_t used;
|
||
|
uint64_t lenhi, lenlo;
|
||
|
};
|
||
|
|
||
|
static inline void sha512_block_setup(sha512_block *blk)
|
||
|
{
|
||
|
blk->used = 0;
|
||
|
blk->lenhi = blk->lenlo = 0;
|
||
|
}
|
||
|
|
||
|
static inline bool sha512_block_write(
|
||
|
sha512_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;
|
||
|
|
||
|
size_t chunkbits = chunk << 3;
|
||
|
|
||
|
blk->lenlo += chunkbits;
|
||
|
blk->lenhi += (blk->lenlo < chunkbits);
|
||
|
|
||
|
if (blk->used == sizeof(blk->block)) {
|
||
|
blk->used = 0;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
static inline void sha512_block_pad(sha512_block *blk, BinarySink *bs)
|
||
|
{
|
||
|
uint64_t final_lenhi = blk->lenhi;
|
||
|
uint64_t final_lenlo = blk->lenlo;
|
||
|
size_t pad = 127 & (111 - blk->used);
|
||
|
|
||
|
put_byte(bs, 0x80);
|
||
|
put_padding(bs, pad, 0);
|
||
|
put_uint64(bs, final_lenhi);
|
||
|
put_uint64(bs, final_lenlo);
|
||
|
|
||
|
assert(blk->used == 0 && "Should have exactly hit a block boundary");
|
||
|
}
|