Welcome to mirror list, hosted at ThFree Co, Russian Federation.

sha512.h « crypto - github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 98145558e3db7818ac3161adf4a4fee5f2bb9ba1 (plain)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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");
}