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 int WHIRLPOOL_Init	(WHIRLPOOL_CTX *c)
58 	{
59 	memset (c,0,sizeof(*c));
60 	return(1);
61 	}
62 
63 int WHIRLPOOL_Update	(WHIRLPOOL_CTX *c,const void *_inp,size_t bytes)
64 	{
65 	/* Well, largest suitable chunk size actually is
66 	 * (1<<(sizeof(size_t)*8-3))-64, but below number
67 	 * is large enough for not to care about excessive
68 	 * calls to WHIRLPOOL_BitUpdate... */
69 	size_t chunk = ((size_t)1)<<(sizeof(size_t)*8-4);
70 	const unsigned char *inp = _inp;
71 
72 	while (bytes>=chunk)
73 		{
74 		WHIRLPOOL_BitUpdate(c,inp,chunk*8);
75 		bytes -= chunk;
76 		inp   += chunk;
77 		}
78 	if (bytes)
79 		WHIRLPOOL_BitUpdate(c,inp,bytes*8);
80 
81 	return(1);
82 	}
83 
84 void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c,const void *_inp,size_t bits)
85 	{
86 	size_t		n;
87 	unsigned int	bitoff = c->bitoff,
88 			bitrem = bitoff%8,
89 			inpgap = (8-(unsigned int)bits%8)&7;
90 	const unsigned char *inp=_inp;
91 
92 	/* This 256-bit increment procedure relies on the size_t
93 	 * being natural size of CPU register, so that we don't
94 	 * have to mask the value in order to detect overflows. */
95 	c->bitlen[0] += bits;
96 	if (c->bitlen[0] < bits)	/* overflow */
97 		{
98 		n = 1;
99 		do  { 	c->bitlen[n]++;
100 		    } while(c->bitlen[n]==0
101 		   	    && ++n<(WHIRLPOOL_COUNTER/sizeof(size_t)));
102 		}
103 
104 #ifndef OPENSSL_SMALL_FOOTPRINT
105 	reconsider:
106 	if (inpgap==0 && bitrem==0)	/* byte-oriented loop */
107 		{
108 		while (bits)
109 			{
110 			if (bitoff==0 && (n=bits/WHIRLPOOL_BBLOCK))
111 				{
112 				whirlpool_block(c,inp,n);
113 				inp  += n*WHIRLPOOL_BBLOCK/8;
114 				bits %= WHIRLPOOL_BBLOCK;
115 				}
116 			else
117 				{
118 				unsigned int byteoff = bitoff/8;
119 
120 				bitrem = WHIRLPOOL_BBLOCK - bitoff;/* re-use bitrem */
121 				if (bits >= bitrem)
122 					{
123 					bits -= bitrem;
124 					bitrem /= 8;
125 					memcpy(c->data+byteoff,inp,bitrem);
126 					inp  += bitrem;
127 					whirlpool_block(c,c->data,1);
128 					bitoff = 0;
129 					}
130 				else
131 					{
132 					memcpy(c->data+byteoff,inp,bits/8);
133 					bitoff += (unsigned int)bits;
134 					bits = 0;
135 					}
136 				c->bitoff = bitoff;
137 				}
138 			}
139 		}
140 	else				/* bit-oriented loop */
141 #endif
142 		{
143 		/*
144 			   inp
145 			   |
146 			   +-------+-------+-------
147 			      |||||||||||||||||||||
148 			   +-------+-------+-------
149 		+-------+-------+-------+-------+-------
150 		||||||||||||||				c->data
151 		+-------+-------+-------+-------+-------
152 			|
153 			c->bitoff/8
154 		*/
155 		while (bits)
156 			{
157 			unsigned int	byteoff	= bitoff/8;
158 			unsigned char	b;
159 
160 #ifndef OPENSSL_SMALL_FOOTPRINT
161 			if (bitrem==inpgap)
162 				{
163 				c->data[byteoff++] |= inp[0] & (0xff>>inpgap);
164 				inpgap = 8-inpgap;
165 				bitoff += inpgap;  bitrem = 0;	/* bitoff%8 */
166 				bits   -= inpgap;  inpgap = 0;	/* bits%8   */
167 				inp++;
168 				if (bitoff==WHIRLPOOL_BBLOCK)
169 					{
170 					whirlpool_block(c,c->data,1);
171 					bitoff = 0;
172 					}
173 				c->bitoff = bitoff;
174 				goto reconsider;
175 				}
176 			else
177 #endif
178 			if (bits>=8)
179 				{
180 				b  = ((inp[0]<<inpgap) | (inp[1]>>(8-inpgap)));
181 				b &= 0xff;
182 				if (bitrem)	c->data[byteoff++] |= b>>bitrem;
183 				else		c->data[byteoff++]  = b;
184 				bitoff += 8;
185 				bits   -= 8;
186 				inp++;
187 				if (bitoff>=WHIRLPOOL_BBLOCK)
188 					{
189 					whirlpool_block(c,c->data,1);
190 					byteoff  = 0;
191 					bitoff  %= WHIRLPOOL_BBLOCK;
192 					}
193 				if (bitrem)	c->data[byteoff] = b<<(8-bitrem);
194 				}
195 			else	/* remaining less than 8 bits */
196 				{
197 				b = (inp[0]<<inpgap)&0xff;
198 				if (bitrem)	c->data[byteoff++] |= b>>bitrem;
199 				else		c->data[byteoff++]  = b;
200 				bitoff += (unsigned int)bits;
201 				if (bitoff==WHIRLPOOL_BBLOCK)
202 					{
203 					whirlpool_block(c,c->data,1);
204 					byteoff  = 0;
205 			        	bitoff  %= WHIRLPOOL_BBLOCK;
206 					}
207 				if (bitrem)	c->data[byteoff] = b<<(8-bitrem);
208 				bits = 0;
209 				}
210 			c->bitoff = bitoff;
211 			}
212 		}
213 	}
214 
215 int WHIRLPOOL_Final	(unsigned char *md,WHIRLPOOL_CTX *c)
216 	{
217 	unsigned int	bitoff  = c->bitoff,
218 			byteoff = bitoff/8;
219 	size_t		i,j,v;
220 	unsigned char  *p;
221 
222 	bitoff %= 8;
223 	if (bitoff)	c->data[byteoff] |= 0x80>>bitoff;
224 	else		c->data[byteoff]  = 0x80;
225 	byteoff++;
226 
227 	/* pad with zeros */
228 	if (byteoff > (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER))
229 		{
230 		if (byteoff<WHIRLPOOL_BBLOCK/8)
231 			memset(&c->data[byteoff],0,WHIRLPOOL_BBLOCK/8-byteoff);
232 		whirlpool_block(c,c->data,1);
233 		byteoff = 0;
234 		}
235 	if (byteoff < (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER))
236 		memset(&c->data[byteoff],0,
237 			(WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER)-byteoff);
238 	/* smash 256-bit c->bitlen in big-endian order */
239 	p = &c->data[WHIRLPOOL_BBLOCK/8-1];	/* last byte in c->data */
240 	for(i=0;i<WHIRLPOOL_COUNTER/sizeof(size_t);i++)
241 		for(v=c->bitlen[i],j=0;j<sizeof(size_t);j++,v>>=8)
242 			*p-- = (unsigned char)(v&0xff);
243 
244 	whirlpool_block(c,c->data,1);
245 
246 	if (md)	{
247 		memcpy(md,c->H.c,WHIRLPOOL_DIGEST_LENGTH);
248 		memset(c,0,sizeof(*c));
249 		return(1);
250 		}
251 	return(0);
252 	}
253 
254 unsigned char *WHIRLPOOL(const void *inp, size_t bytes,unsigned char *md)
255 	{
256 	WHIRLPOOL_CTX ctx;
257 	static unsigned char m[WHIRLPOOL_DIGEST_LENGTH];
258 
259 	if (md == NULL) md=m;
260 	WHIRLPOOL_Init(&ctx);
261 	WHIRLPOOL_Update(&ctx,inp,bytes);
262 	WHIRLPOOL_Final(md,&ctx);
263 	return(md);
264 	}
265