mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
110 lines
3.4 KiB
C
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");
|
||
|
}
|