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