1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
/*
* 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");
}
|