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