]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bearssl/src/mac/hmac_ct.c
Add libbearssl
[FreeBSD/FreeBSD.git] / contrib / bearssl / src / mac / hmac_ct.c
1 /*
2  * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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 }