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