Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bearssl/src/mac/hmac_ct.c
39482 views
1
/*
2
* Copyright (c) 2016 Thomas Pornin <[email protected]>
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining
5
* a copy of this software and associated documentation files (the
6
* "Software"), to deal in the Software without restriction, including
7
* without limitation the rights to use, copy, modify, merge, publish,
8
* distribute, sublicense, and/or sell copies of the Software, and to
9
* permit persons to whom the Software is furnished to do so, subject to
10
* the following conditions:
11
*
12
* The above copyright notice and this permission notice shall be
13
* included in all copies or substantial portions of the Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
25
#include "inner.h"
26
27
static inline size_t
28
hash_size(const br_hash_class *dig)
29
{
30
return (unsigned)(dig->desc >> BR_HASHDESC_OUT_OFF)
31
& BR_HASHDESC_OUT_MASK;
32
}
33
34
static inline size_t
35
block_size(const br_hash_class *dig)
36
{
37
unsigned ls;
38
39
ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
40
& BR_HASHDESC_LBLEN_MASK;
41
return (size_t)1 << ls;
42
}
43
44
/* see bearssl.h */
45
size_t
46
br_hmac_outCT(const br_hmac_context *ctx,
47
const void *data, size_t len, size_t min_len, size_t max_len,
48
void *out)
49
{
50
/*
51
* Method implemented here is inspired from the descriptions on:
52
* https://www.imperialviolet.org/2013/02/04/luckythirteen.html
53
*
54
* Principle: we input bytes one by one. We use a MUX to push
55
* padding bytes instead of data bytes when appropriate. At each
56
* block limit, we get the current hash function state: this is
57
* a potential output, since we handle MD padding ourselves.
58
*
59
* be 1 for big-endian, 0 for little-endian
60
* po minimal MD padding length
61
* bs block size (always a power of 2)
62
* hlen hash output size
63
*/
64
65
const br_hash_class *dig;
66
br_hash_compat_context hc;
67
int be;
68
uint32_t po, bs;
69
uint32_t kr, km, kl, kz, u;
70
uint64_t count, ncount, bit_len;
71
unsigned char tmp1[64], tmp2[64];
72
size_t hlen;
73
74
/*
75
* Copy the current hash context.
76
*/
77
hc = ctx->dig;
78
79
/*
80
* Get function-specific information.
81
*/
82
dig = hc.vtable;
83
be = (dig->desc & BR_HASHDESC_MD_PADDING_BE) != 0;
84
po = 9;
85
if (dig->desc & BR_HASHDESC_MD_PADDING_128) {
86
po += 8;
87
}
88
bs = block_size(dig);
89
hlen = hash_size(dig);
90
91
/*
92
* Get current input length and compute total bit length.
93
*/
94
count = dig->state(&hc.vtable, tmp1);
95
bit_len = (count + (uint64_t)len) << 3;
96
97
/*
98
* We can input the blocks that we are sure we will use.
99
* This offers better performance (no MUX for these blocks)
100
* and also ensures that the remaining lengths fit on 32 bits.
101
*/
102
ncount = (count + (uint64_t)min_len) & ~(uint64_t)(bs - 1);
103
if (ncount > count) {
104
size_t zlen;
105
106
zlen = (size_t)(ncount - count);
107
dig->update(&hc.vtable, data, zlen);
108
data = (const unsigned char *)data + zlen;
109
len -= zlen;
110
max_len -= zlen;
111
count = ncount;
112
}
113
114
/*
115
* At that point:
116
* -- 'count' contains the number of bytes already processed
117
* (in total).
118
* -- We must input 'len' bytes. 'min_len' is unimportant: we
119
* used it to know how many full blocks we could process
120
* directly. Now only len and max_len matter.
121
*
122
* We compute kr, kl, kz and km.
123
* kr number of input bytes already in the current block
124
* km index of the first byte after the end of the last padding
125
* block, if length is max_len
126
* kz index of the last byte of the actual last padding block
127
* kl index of the start of the encoded length
128
*
129
* km, kz and kl are counted from the current offset in the
130
* input data.
131
*/
132
kr = (uint32_t)count & (bs - 1);
133
kz = ((kr + (uint32_t)len + po + bs - 1) & ~(bs - 1)) - 1 - kr;
134
kl = kz - 7;
135
km = ((kr + (uint32_t)max_len + po + bs - 1) & ~(bs - 1)) - kr;
136
137
/*
138
* We must now process km bytes. For index u from 0 to km-1:
139
* d is from data[] if u < max_len, 0x00 otherwise
140
* e is an encoded length byte or 0x00, depending on u
141
* The tests for d and e need not be constant-time, since
142
* they relate only to u and max_len, not to the actual length.
143
*
144
* Actual input length is then:
145
* d if u < len
146
* 0x80 if u == len
147
* 0x00 if u > len and u < kl
148
* e if u >= kl
149
*
150
* Hash state is obtained whenever we reach a full block. This
151
* is the result we want if and only if u == kz.
152
*/
153
memset(tmp2, 0, sizeof tmp2);
154
for (u = 0; u < km; u ++) {
155
uint32_t v;
156
uint32_t d, e, x0, x1;
157
unsigned char x[1];
158
159
d = (u < max_len) ? ((const unsigned char *)data)[u] : 0x00;
160
v = (kr + u) & (bs - 1);
161
if (v >= (bs - 8)) {
162
unsigned j;
163
164
j = (v - (bs - 8)) << 3;
165
if (be) {
166
e = (uint32_t)(bit_len >> (56 - j));
167
} else {
168
e = (uint32_t)(bit_len >> j);
169
}
170
e &= 0xFF;
171
} else {
172
e = 0x00;
173
}
174
x0 = MUX(EQ(u, (uint32_t)len), 0x80, d);
175
x1 = MUX(LT(u, kl), 0x00, e);
176
x[0] = MUX(LE(u, (uint32_t)len), x0, x1);
177
dig->update(&hc.vtable, x, 1);
178
if (v == (bs - 1)) {
179
dig->state(&hc.vtable, tmp1);
180
CCOPY(EQ(u, kz), tmp2, tmp1, hlen);
181
}
182
}
183
184
/*
185
* Inner hash output is in tmp2[]; we finish processing.
186
*/
187
dig->init(&hc.vtable);
188
dig->set_state(&hc.vtable, ctx->kso, (uint64_t)bs);
189
dig->update(&hc.vtable, tmp2, hlen);
190
dig->out(&hc.vtable, tmp2);
191
memcpy(out, tmp2, ctx->out_len);
192
return ctx->out_len;
193
}
194
195