cfi build fixes in x86-64 ghash assembly
[openssl.git] / crypto / whrlpool / wp_dgst.c
1 /*
2  * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 /**
11  * The Whirlpool hashing function.
12  *
13  * See
14  *      P.S.L.M. Barreto, V. Rijmen,
15  *      ``The Whirlpool hashing function,''
16  *      NESSIE submission, 2000 (tweaked version, 2001),
17  *      <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
18  *
19  * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and
20  * Vincent Rijmen. Lookup "reference implementations" on
21  * <http://planeta.terra.com.br/informatica/paulobarreto/>
22  *
23  * =============================================================================
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
26  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
29  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
34  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  */
38
39 /*
40  * OpenSSL-specific implementation notes.
41  *
42  * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect
43  * number of *bytes* as input length argument. Bit-oriented routine
44  * as specified by authors is called WHIRLPOOL_BitUpdate[!] and
45  * does not have one-stroke counterpart.
46  *
47  * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially
48  * to serve WHIRLPOOL_Update. This is done for performance.
49  *
50  * Unlike authors' reference implementation, block processing
51  * routine whirlpool_block is designed to operate on multi-block
52  * input. This is done for performance.
53  */
54
55 #include <openssl/crypto.h>
56 #include "wp_locl.h"
57 #include <string.h>
58
59 int WHIRLPOOL_Init(WHIRLPOOL_CTX *c)
60 {
61     memset(c, 0, sizeof(*c));
62     return 1;
63 }
64
65 int WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes)
66 {
67     /*
68      * Well, largest suitable chunk size actually is
69      * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not
70      * to care about excessive calls to WHIRLPOOL_BitUpdate...
71      */
72     size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4);
73     const unsigned char *inp = _inp;
74
75     while (bytes >= chunk) {
76         WHIRLPOOL_BitUpdate(c, inp, chunk * 8);
77         bytes -= chunk;
78         inp += chunk;
79     }
80     if (bytes)
81         WHIRLPOOL_BitUpdate(c, inp, bytes * 8);
82
83     return 1;
84 }
85
86 void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits)
87 {
88     size_t n;
89     unsigned int bitoff = c->bitoff,
90         bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7;
91     const unsigned char *inp = _inp;
92
93     /*
94      * This 256-bit increment procedure relies on the size_t being natural
95      * size of CPU register, so that we don't have to mask the value in order
96      * to detect overflows.
97      */
98     c->bitlen[0] += bits;
99     if (c->bitlen[0] < bits) {  /* overflow */
100         n = 1;
101         do {
102             c->bitlen[n]++;
103         } while (c->bitlen[n] == 0
104                  && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t)));
105     }
106 #ifndef OPENSSL_SMALL_FOOTPRINT
107  reconsider:
108     if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */
109         while (bits) {
110             if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) {
111                 whirlpool_block(c, inp, n);
112                 inp += n * WHIRLPOOL_BBLOCK / 8;
113                 bits %= WHIRLPOOL_BBLOCK;
114             } else {
115                 unsigned int byteoff = bitoff / 8;
116
117                 bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */
118                 if (bits >= bitrem) {
119                     bits -= bitrem;
120                     bitrem /= 8;
121                     memcpy(c->data + byteoff, inp, bitrem);
122                     inp += bitrem;
123                     whirlpool_block(c, c->data, 1);
124                     bitoff = 0;
125                 } else {
126                     memcpy(c->data + byteoff, inp, bits / 8);
127                     bitoff += (unsigned int)bits;
128                     bits = 0;
129                 }
130                 c->bitoff = bitoff;
131             }
132         }
133     } else                      /* bit-oriented loop */
134 #endif
135     {
136         /*-
137                    inp
138                    |
139                    +-------+-------+-------
140                       |||||||||||||||||||||
141                    +-------+-------+-------
142         +-------+-------+-------+-------+-------
143         ||||||||||||||                          c->data
144         +-------+-------+-------+-------+-------
145                 |
146                 c->bitoff/8
147         */
148         while (bits) {
149             unsigned int byteoff = bitoff / 8;
150             unsigned char b;
151
152 #ifndef OPENSSL_SMALL_FOOTPRINT
153             if (bitrem == inpgap) {
154                 c->data[byteoff++] |= inp[0] & (0xff >> inpgap);
155                 inpgap = 8 - inpgap;
156                 bitoff += inpgap;
157                 bitrem = 0;     /* bitoff%8 */
158                 bits -= inpgap;
159                 inpgap = 0;     /* bits%8 */
160                 inp++;
161                 if (bitoff == WHIRLPOOL_BBLOCK) {
162                     whirlpool_block(c, c->data, 1);
163                     bitoff = 0;
164                 }
165                 c->bitoff = bitoff;
166                 goto reconsider;
167             } else
168 #endif
169             if (bits > 8) {
170                 b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap)));
171                 b &= 0xff;
172                 if (bitrem)
173                     c->data[byteoff++] |= b >> bitrem;
174                 else
175                     c->data[byteoff++] = b;
176                 bitoff += 8;
177                 bits -= 8;
178                 inp++;
179                 if (bitoff >= WHIRLPOOL_BBLOCK) {
180                     whirlpool_block(c, c->data, 1);
181                     byteoff = 0;
182                     bitoff %= WHIRLPOOL_BBLOCK;
183                 }
184                 if (bitrem)
185                     c->data[byteoff] = b << (8 - bitrem);
186             } else {            /* remaining less than or equal to 8 bits */
187
188                 b = (inp[0] << inpgap) & 0xff;
189                 if (bitrem)
190                     c->data[byteoff++] |= b >> bitrem;
191                 else
192                     c->data[byteoff++] = b;
193                 bitoff += (unsigned int)bits;
194                 if (bitoff == WHIRLPOOL_BBLOCK) {
195                     whirlpool_block(c, c->data, 1);
196                     byteoff = 0;
197                     bitoff %= WHIRLPOOL_BBLOCK;
198                 }
199                 if (bitrem)
200                     c->data[byteoff] = b << (8 - bitrem);
201                 bits = 0;
202             }
203             c->bitoff = bitoff;
204         }
205     }
206 }
207
208 int WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c)
209 {
210     unsigned int bitoff = c->bitoff, byteoff = bitoff / 8;
211     size_t i, j, v;
212     unsigned char *p;
213
214     bitoff %= 8;
215     if (bitoff)
216         c->data[byteoff] |= 0x80 >> bitoff;
217     else
218         c->data[byteoff] = 0x80;
219     byteoff++;
220
221     /* pad with zeros */
222     if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) {
223         if (byteoff < WHIRLPOOL_BBLOCK / 8)
224             memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff);
225         whirlpool_block(c, c->data, 1);
226         byteoff = 0;
227     }
228     if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER))
229         memset(&c->data[byteoff], 0,
230                (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff);
231     /* smash 256-bit c->bitlen in big-endian order */
232     p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */
233     for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++)
234         for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8)
235             *p-- = (unsigned char)(v & 0xff);
236
237     whirlpool_block(c, c->data, 1);
238
239     if (md) {
240         memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH);
241         OPENSSL_cleanse(c, sizeof(*c));
242         return 1;
243     }
244     return 0;
245 }
246
247 unsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md)
248 {
249     WHIRLPOOL_CTX ctx;
250     static unsigned char m[WHIRLPOOL_DIGEST_LENGTH];
251
252     if (md == NULL)
253         md = m;
254     WHIRLPOOL_Init(&ctx);
255     WHIRLPOOL_Update(&ctx, inp, bytes);
256     WHIRLPOOL_Final(md, &ctx);
257     return md;
258 }