diff options
Diffstat (limited to 'crypto/sha512.h')
-rw-r--r-- | crypto/sha512.h | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/crypto/sha512.h b/crypto/sha512.h new file mode 100644 index 00000000..98145558 --- /dev/null +++ b/crypto/sha512.h @@ -0,0 +1,131 @@ +/* + * 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"); +} |