:: limine / common / crypt / blake2b.c 8.5 KB raw

1
// This blake2b implementation comes from the GNU coreutils project.
2
// https://github.com/coreutils/coreutils/blob/master/src/blake2/blake2b-ref.c
3
4
#include <stdbool.h>
5
#include <stdint.h>
6
#include <stddef.h>
7
#include <crypt/blake2b.h>
8
#include <lib/libc.h>
9
#include <lib/misc.h>
10
#include <mm/pmm.h>
11
12
#define BLAKE2B_BLOCK_BYTES 128
13
#define BLAKE2B_KEY_BYTES 64
14
#define BLAKE2B_SALT_BYTES 16
15
#define BLAKE2B_PERSONAL_BYTES 16
16
17
static const uint64_t blake2b_iv[8] = {
18
    0x6a09e667f3bcc908,
19
    0xbb67ae8584caa73b,
20
    0x3c6ef372fe94f82b,
21
    0xa54ff53a5f1d36f1,
22
    0x510e527fade682d1,
23
    0x9b05688c2b3e6c1f,
24
    0x1f83d9abfb41bd6b,
25
    0x5be0cd19137e2179,
26
};
27
28
static const uint8_t blake2b_sigma[12][16] = {
29
    {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 },
30
    { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 },
31
    { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 },
32
    {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 },
33
    {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 },
34
    {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 },
35
    { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 },
36
    { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 },
37
    {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 },
38
    { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13,  0 },
39
    {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 },
40
    { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 },
41
};
42
43
struct blake2b_state {
44
    uint64_t h[8];
45
    uint64_t t[2];
46
    uint64_t f[2];
47
    uint8_t buf[BLAKE2B_BLOCK_BYTES];
48
    size_t buf_len;
49
    uint8_t last_node;
50
};
51
52
struct blake2b_param {
53
    uint8_t digest_length;
54
    uint8_t key_length;
55
    uint8_t fan_out;
56
    uint8_t depth;
57
    uint32_t leaf_length;
58
    uint32_t node_offset;
59
    uint32_t xof_length;
60
    uint8_t node_depth;
61
    uint8_t inner_length;
62
    uint8_t reserved[14];
63
    uint8_t salt[BLAKE2B_SALT_BYTES];
64
    uint8_t personal[BLAKE2B_PERSONAL_BYTES];
65
} __attribute__((packed));
66
67
// Safe unaligned load/store helpers for architectures with strict alignment (ARM64, RISC-V)
68
static inline uint64_t load64_le(const void *src) {
69
    uint64_t val;
70
    memcpy(&val, src, sizeof(val));
71
    return val;
72
}
73
74
static inline void store64_le(void *dst, uint64_t val) {
75
    memcpy(dst, &val, sizeof(val));
76
}
77
78
static void blake2b_increment_counter(struct blake2b_state *state, uint64_t inc) {
79
    state->t[0] += inc;
80
    state->t[1] += state->t[0] < inc;
81
}
82
83
static inline uint64_t rotr64(uint64_t w, unsigned c) {
84
    return (w >> c) | (w << (64 - c));
85
}
86
87
#define G(r, i, a, b, c, d) do { \
88
        a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \
89
        d = rotr64(d ^ a, 32); \
90
        c = c + d; \
91
        b = rotr64(b ^ c, 24); \
92
        a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \
93
        d = rotr64(d ^ a, 16); \
94
        c = c + d; \
95
        b = rotr64(b ^ c, 63); \
96
    } while (0)
97
98
#define ROUND(r) do { \
99
        G(r, 0, v[0], v[4], v[8], v[12]); \
100
        G(r, 1, v[1], v[5], v[9], v[13]); \
101
        G(r, 2, v[2], v[6], v[10], v[14]); \
102
        G(r, 3, v[3], v[7], v[11], v[15]); \
103
        G(r, 4, v[0], v[5], v[10], v[15]); \
104
        G(r, 5, v[1], v[6], v[11], v[12]); \
105
        G(r, 6, v[2], v[7], v[8], v[13]); \
106
        G(r, 7, v[3], v[4], v[9], v[14]); \
107
    } while (0)
108
109
static void blake2b_compress(struct blake2b_state *state, const uint8_t block[static BLAKE2B_BLOCK_BYTES]) {
110
    uint64_t m[16];
111
    uint64_t v[16];
112
113
    for (int i = 0; i < 16; i++) {
114
        m[i] = load64_le(block + i * sizeof(m[i]));
115
    }
116
117
    for (int i = 0; i < 8; i++) {
118
        v[i] = state->h[i];
119
    }
120
121
    v[8] = blake2b_iv[0];
122
    v[9] = blake2b_iv[1];
123
    v[10] = blake2b_iv[2];
124
    v[11] = blake2b_iv[3];
125
    v[12] = blake2b_iv[4] ^ state->t[0];
126
    v[13] = blake2b_iv[5] ^ state->t[1];
127
    v[14] = blake2b_iv[6] ^ state->f[0];
128
    v[15] = blake2b_iv[7] ^ state->f[1];
129
130
    ROUND(0);
131
    ROUND(1);
132
    ROUND(2);
133
    ROUND(3);
134
    ROUND(4);
135
    ROUND(5);
136
    ROUND(6);
137
    ROUND(7);
138
    ROUND(8);
139
    ROUND(9);
140
    ROUND(10);
141
    ROUND(11);
142
143
    for (int i = 0; i < 8; i++) {
144
        state->h[i] = state->h[i] ^ v[i] ^ v[i + 8];
145
    }
146
}
147
148
#undef G
149
#undef ROUND
150
151
static void blake2b_init(struct blake2b_state *state) {
152
    struct blake2b_param param = {0};
153
154
    param.digest_length = BLAKE2B_OUT_BYTES;
155
    param.fan_out = 1;
156
    param.depth = 1;
157
158
    memset(state, 0, sizeof(struct blake2b_state));
159
160
    for (int i = 0; i < 8; i++) {
161
        state->h[i] = blake2b_iv[i];
162
    }
163
164
    for (int i = 0; i < 8; i++) {
165
        state->h[i] ^= load64_le((uint8_t *)&param + sizeof(state->h[i]) * i);
166
    }
167
}
168
169
static void blake2b_update(struct blake2b_state *state, const void *in, size_t in_len) {
170
    if (in_len == 0) {
171
        return;
172
    }
173
174
    size_t left = state->buf_len;
175
    size_t fill = BLAKE2B_BLOCK_BYTES - left;
176
177
    if (in_len > fill) {
178
        state->buf_len = 0;
179
180
        memcpy(state->buf + left, in, fill);
181
        blake2b_increment_counter(state, BLAKE2B_BLOCK_BYTES);
182
        blake2b_compress(state, state->buf);
183
184
        in += fill;
185
        in_len -= fill;
186
187
        while (in_len > BLAKE2B_BLOCK_BYTES) {
188
            blake2b_increment_counter(state, BLAKE2B_BLOCK_BYTES);
189
            blake2b_compress(state, in);
190
191
            in += BLAKE2B_BLOCK_BYTES;
192
            in_len -= BLAKE2B_BLOCK_BYTES;
193
        }
194
    }
195
196
    memcpy(state->buf + state->buf_len, in, in_len);
197
    state->buf_len += in_len;
198
}
199
200
static void blake2b_final(struct blake2b_state *state, void *out) {
201
    uint8_t buffer[BLAKE2B_OUT_BYTES] = {0};
202
203
    blake2b_increment_counter(state, state->buf_len);
204
    state->f[0] = (uint64_t)-1;
205
    memset(state->buf + state->buf_len, 0, BLAKE2B_BLOCK_BYTES - state->buf_len);
206
    blake2b_compress(state, state->buf);
207
208
    for (int i = 0; i < 8; i++) {
209
        store64_le(buffer + sizeof(state->h[i]) * i, state->h[i]);
210
    }
211
212
    memcpy(out, buffer, BLAKE2B_OUT_BYTES);
213
    memset(buffer, 0, sizeof(buffer));
214
}
215
216
void blake2b(void *out, const void *in, size_t in_len) {
217
    struct blake2b_state state = {0};
218
219
    blake2b_init(&state);
220
    blake2b_update(&state, in, in_len);
221
    blake2b_final(&state, out);
222
}
223
224
/*  Streaming filter: wraps a source file_handle and hashes bytes as
225
    they are read sequentially. The hash is finalized and compared via
226
    blake2b_check_hash(). Non-sequential reads panic -- the filter is
227
    meant to sit underneath the gzip bitreader or uri_open's drain loop,
228
    both of which advance monotonically.  */
229
struct blake2b_handle {
230
    struct file_handle  *source;
231
    struct blake2b_state state;
232
    uint64_t             pos;
233
    bool                 finalized;
234
    uint8_t              digest[BLAKE2B_OUT_BYTES];
235
};
236
237
static uint64_t blake2b_read(struct file_handle *fh, void *buf, uint64_t loc, uint64_t count) {
238
    struct blake2b_handle *h = fh->fd;
239
    if (loc != h->pos) {
240
        panic(false, "blake2b filter: non-sequential read (pos=%x, loc=%x)",
241
              (uint64_t)h->pos, loc);
242
    }
243
    uint64_t got = fread(h->source, buf, loc, count);
244
    blake2b_update(&h->state, buf, got);
245
    h->pos += got;
246
    return got;
247
}
248
249
static void blake2b_close(struct file_handle *fh) {
250
    struct blake2b_handle *h = fh->fd;
251
    fclose(h->source);
252
    pmm_free(h, sizeof(struct blake2b_handle));
253
}
254
255
struct file_handle *blake2b_open(struct file_handle *source) {
256
    struct blake2b_handle *h = ext_mem_alloc(sizeof(struct blake2b_handle));
257
    blake2b_init(&h->state);
258
    h->source = source;
259
    h->pos = 0;
260
    h->finalized = false;
261
262
    struct file_handle *ret = ext_mem_alloc(sizeof(struct file_handle));
263
    ret->fd = h;
264
    ret->read = (void *)blake2b_read;
265
    ret->close = (void *)blake2b_close;
266
    ret->size = source->size;
267
    ret->vol = source->vol;
268
    if (source->path != NULL && source->path_len > 0) {
269
        ret->path = ext_mem_alloc(source->path_len);
270
        memcpy(ret->path, source->path, source->path_len);
271
        ret->path_len = source->path_len;
272
    }
273
#if defined (UEFI)
274
    ret->efi_part_handle = source->efi_part_handle;
275
#endif
276
    ret->pxe = source->pxe;
277
    ret->pxe_ip = source->pxe_ip;
278
    ret->pxe_port = source->pxe_port;
279
    return ret;
280
}
281
282
bool blake2b_check_hash(struct file_handle *fh, void *reference_hash) {
283
    if (fh->read != (void *)blake2b_read) {
284
        panic(false, "blake2b_check_hash: not a blake2b filter handle");
285
    }
286
    struct blake2b_handle *h = fh->fd;
287
    if (!h->finalized) {
288
        blake2b_final(&h->state, h->digest);
289
        h->finalized = true;
290
    }
291
    return memcmp(h->digest, reference_hash, BLAKE2B_OUT_BYTES) == 0;
292
}
tab: 248 wrap: offon