2 * The Whirlpool hashing function.
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>.
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>
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/>
22 * =============================================================================
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.
39 * OpenSSL-specific implementation notes.
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.
46 * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially
47 * to serve WHIRLPOOL_Update. This is done for performance.
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.
55 #include <openssl/crypto.h>
58 fips_md_init(WHIRLPOOL
)
60 memset(c
, 0, sizeof(*c
));
64 int WHIRLPOOL_Update(WHIRLPOOL_CTX
*c
, const void *_inp
, size_t bytes
)
67 * Well, largest suitable chunk size actually is
68 * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not
69 * to care about excessive calls to WHIRLPOOL_BitUpdate...
71 size_t chunk
= ((size_t)1) << (sizeof(size_t) * 8 - 4);
72 const unsigned char *inp
= _inp
;
74 while (bytes
>= chunk
) {
75 WHIRLPOOL_BitUpdate(c
, inp
, chunk
* 8);
80 WHIRLPOOL_BitUpdate(c
, inp
, bytes
* 8);
85 void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX
*c
, const void *_inp
, size_t bits
)
88 unsigned int bitoff
= c
->bitoff
,
89 bitrem
= bitoff
% 8, inpgap
= (8 - (unsigned int)bits
% 8) & 7;
90 const unsigned char *inp
= _inp
;
93 * This 256-bit increment procedure relies on the size_t being natural
94 * size of CPU register, so that we don't have to mask the value in order
95 * to detect overflows.
98 if (c
->bitlen
[0] < bits
) { /* overflow */
102 } while (c
->bitlen
[n
] == 0
103 && ++n
< (WHIRLPOOL_COUNTER
/ sizeof(size_t)));
105 #ifndef OPENSSL_SMALL_FOOTPRINT
107 if (inpgap
== 0 && bitrem
== 0) { /* byte-oriented loop */
109 if (bitoff
== 0 && (n
= bits
/ WHIRLPOOL_BBLOCK
)) {
110 whirlpool_block(c
, inp
, n
);
111 inp
+= n
* WHIRLPOOL_BBLOCK
/ 8;
112 bits
%= WHIRLPOOL_BBLOCK
;
114 unsigned int byteoff
= bitoff
/ 8;
116 bitrem
= WHIRLPOOL_BBLOCK
- bitoff
; /* re-use bitrem */
117 if (bits
>= bitrem
) {
120 memcpy(c
->data
+ byteoff
, inp
, bitrem
);
122 whirlpool_block(c
, c
->data
, 1);
125 memcpy(c
->data
+ byteoff
, inp
, bits
/ 8);
126 bitoff
+= (unsigned int)bits
;
132 } else /* bit-oriented loop */
138 +-------+-------+-------
139 |||||||||||||||||||||
140 +-------+-------+-------
141 +-------+-------+-------+-------+-------
142 |||||||||||||| c->data
143 +-------+-------+-------+-------+-------
148 unsigned int byteoff
= bitoff
/ 8;
151 #ifndef OPENSSL_SMALL_FOOTPRINT
152 if (bitrem
== inpgap
) {
153 c
->data
[byteoff
++] |= inp
[0] & (0xff >> inpgap
);
156 bitrem
= 0; /* bitoff%8 */
158 inpgap
= 0; /* bits%8 */
160 if (bitoff
== WHIRLPOOL_BBLOCK
) {
161 whirlpool_block(c
, c
->data
, 1);
169 b
= ((inp
[0] << inpgap
) | (inp
[1] >> (8 - inpgap
)));
172 c
->data
[byteoff
++] |= b
>> bitrem
;
174 c
->data
[byteoff
++] = b
;
178 if (bitoff
>= WHIRLPOOL_BBLOCK
) {
179 whirlpool_block(c
, c
->data
, 1);
181 bitoff
%= WHIRLPOOL_BBLOCK
;
184 c
->data
[byteoff
] = b
<< (8 - bitrem
);
185 } else { /* remaining less than 8 bits */
187 b
= (inp
[0] << inpgap
) & 0xff;
189 c
->data
[byteoff
++] |= b
>> bitrem
;
191 c
->data
[byteoff
++] = b
;
192 bitoff
+= (unsigned int)bits
;
193 if (bitoff
== WHIRLPOOL_BBLOCK
) {
194 whirlpool_block(c
, c
->data
, 1);
196 bitoff
%= WHIRLPOOL_BBLOCK
;
199 c
->data
[byteoff
] = b
<< (8 - bitrem
);
207 int WHIRLPOOL_Final(unsigned char *md
, WHIRLPOOL_CTX
*c
)
209 unsigned int bitoff
= c
->bitoff
, byteoff
= bitoff
/ 8;
215 c
->data
[byteoff
] |= 0x80 >> bitoff
;
217 c
->data
[byteoff
] = 0x80;
221 if (byteoff
> (WHIRLPOOL_BBLOCK
/ 8 - WHIRLPOOL_COUNTER
)) {
222 if (byteoff
< WHIRLPOOL_BBLOCK
/ 8)
223 memset(&c
->data
[byteoff
], 0, WHIRLPOOL_BBLOCK
/ 8 - byteoff
);
224 whirlpool_block(c
, c
->data
, 1);
227 if (byteoff
< (WHIRLPOOL_BBLOCK
/ 8 - WHIRLPOOL_COUNTER
))
228 memset(&c
->data
[byteoff
], 0,
229 (WHIRLPOOL_BBLOCK
/ 8 - WHIRLPOOL_COUNTER
) - byteoff
);
230 /* smash 256-bit c->bitlen in big-endian order */
231 p
= &c
->data
[WHIRLPOOL_BBLOCK
/ 8 - 1]; /* last byte in c->data */
232 for (i
= 0; i
< WHIRLPOOL_COUNTER
/ sizeof(size_t); i
++)
233 for (v
= c
->bitlen
[i
], j
= 0; j
< sizeof(size_t); j
++, v
>>= 8)
234 *p
-- = (unsigned char)(v
& 0xff);
236 whirlpool_block(c
, c
->data
, 1);
239 memcpy(md
, c
->H
.c
, WHIRLPOOL_DIGEST_LENGTH
);
240 memset(c
, 0, sizeof(*c
));
246 unsigned char *WHIRLPOOL(const void *inp
, size_t bytes
, unsigned char *md
)
249 static unsigned char m
[WHIRLPOOL_DIGEST_LENGTH
];
253 WHIRLPOOL_Init(&ctx
);
254 WHIRLPOOL_Update(&ctx
, inp
, bytes
);
255 WHIRLPOOL_Final(md
, &ctx
);