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