Logo Search packages:      
Sourcecode: openssl version File versions  Download package

wp_dgst.c
/**
 * The Whirlpool hashing function.
 *
 * <P>
 * <b>References</b>
 *
 * <P>
 * The Whirlpool algorithm was developed by
 * <a href="mailto:pbarreto@scopus.com.br">Paulo S. L. M. Barreto</a> and
 * <a href="mailto:vincent.rijmen@cryptomathic.com">Vincent Rijmen</a>.
 *
 * See
 *      P.S.L.M. Barreto, V. Rijmen,
 *      ``The Whirlpool hashing function,''
 *      NESSIE submission, 2000 (tweaked version, 2001),
 *      <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
 *
 * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and
 * Vincent Rijmen. Lookup "reference implementations" on
 * <http://planeta.terra.com.br/informatica/paulobarreto/>
 *
 * =============================================================================
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/*
 * OpenSSL-specific implementation notes.
 *
 * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect
 * number of *bytes* as input length argument. Bit-oriented routine
 * as specified by authors is called WHIRLPOOL_BitUpdate[!] and
 * does not have one-stroke counterpart.
 *
 * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially
 * to serve WHIRLPOOL_Update. This is done for performance.
 *
 * Unlike authors' reference implementation, block processing
 * routine whirlpool_block is designed to operate on multi-block
 * input. This is done for perfomance.
 */

#include "wp_locl.h"
#include <string.h>

int WHIRLPOOL_Init      (WHIRLPOOL_CTX *c)
      {
      memset (c,0,sizeof(*c));
      return(1);
      }

int WHIRLPOOL_Update    (WHIRLPOOL_CTX *c,const void *_inp,size_t bytes)
      {
      /* Well, largest suitable chunk size actually is
       * (1<<(sizeof(size_t)*8-3))-64, but below number
       * is large enough for not to care about excessive
       * calls to WHIRLPOOL_BitUpdate... */
      size_t chunk = ((size_t)1)<<(sizeof(size_t)*8-4);
      const unsigned char *inp = _inp;

      while (bytes>=chunk)
            {
            WHIRLPOOL_BitUpdate(c,inp,chunk*8);
            bytes -= chunk;
            inp   += chunk;
            }
      if (bytes)
            WHIRLPOOL_BitUpdate(c,inp,bytes*8);

      return(1);
      }

void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c,const void *_inp,size_t bits)
      {
      size_t            n;
      unsigned int      bitoff = c->bitoff,
                  bitrem = bitoff%8,
                  inpgap = (8-(unsigned int)bits%8)&7;
      const unsigned char *inp=_inp;

      /* This 256-bit increment procedure relies on the size_t
       * being natural size of CPU register, so that we don't
       * have to mask the value in order to detect overflows. */
      c->bitlen[0] += bits;
      if (c->bitlen[0] < bits)      /* overflow */
            {
            n = 1;
            do  {       c->bitlen[n]++;
                } while(c->bitlen[n]==0
                      && ++n<(WHIRLPOOL_COUNTER/sizeof(size_t)));
            }

#ifndef OPENSSL_SMALL_FOOTPRINT
      reconsider:
      if (inpgap==0 && bitrem==0)   /* byte-oriented loop */
            {
            while (bits)
                  {
                  if (bitoff==0 && (n=bits/WHIRLPOOL_BBLOCK))
                        {
                        whirlpool_block(c,inp,n);
                        inp  += n*WHIRLPOOL_BBLOCK/8;
                        bits %= WHIRLPOOL_BBLOCK;
                        }
                  else
                        {
                        unsigned int byteoff = bitoff/8;

                        bitrem = WHIRLPOOL_BBLOCK - bitoff;/* re-use bitrem */
                        if (bits >= bitrem)
                              {
                              bits -= bitrem;
                              bitrem /= 8;
                              memcpy(c->data+byteoff,inp,bitrem);
                              inp  += bitrem;
                              whirlpool_block(c,c->data,1);
                              bitoff = 0;
                              }
                        else
                              {
                              memcpy(c->data+byteoff,inp,bits/8);
                              bitoff += (unsigned int)bits;
                              bits = 0;
                              }
                        c->bitoff = bitoff;
                        }
                  }
            }
      else                    /* bit-oriented loop */
#endif
            {
            /*
                     inp
                     |
                     +-------+-------+-------
                        |||||||||||||||||||||
                     +-------+-------+-------
            +-------+-------+-------+-------+-------
            ||||||||||||||                      c->data
            +-------+-------+-------+-------+-------
                  |
                  c->bitoff/8
            */
            while (bits)
                  {
                  unsigned int      byteoff     = bitoff/8;
                  unsigned char     b;

#ifndef OPENSSL_SMALL_FOOTPRINT
                  if (bitrem==inpgap)
                        {
                        c->data[byteoff++] |= inp[0] & (0xff>>inpgap);
                        inpgap = 8-inpgap;
                        bitoff += inpgap;  bitrem = 0;      /* bitoff%8 */
                        bits   -= inpgap;  inpgap = 0;      /* bits%8   */
                        inp++;
                        if (bitoff==WHIRLPOOL_BBLOCK)
                              {
                              whirlpool_block(c,c->data,1);
                              bitoff = 0;
                              }
                        c->bitoff = bitoff;
                        goto reconsider;
                        }
                  else
#endif
                  if (bits>=8)
                        {
                        b  = ((inp[0]<<inpgap) | (inp[1]>>(8-inpgap)));
                        b &= 0xff;
                        if (bitrem) c->data[byteoff++] |= b>>bitrem;
                        else        c->data[byteoff++]  = b;
                        bitoff += 8;
                        bits   -= 8;
                        inp++;
                        if (bitoff>=WHIRLPOOL_BBLOCK)
                              {
                              whirlpool_block(c,c->data,1);
                              byteoff  = 0;
                              bitoff  %= WHIRLPOOL_BBLOCK;
                              }
                        if (bitrem) c->data[byteoff] = b<<(8-bitrem);
                        }
                  else  /* remaining less than 8 bits */
                        {
                        b = (inp[0]<<inpgap)&0xff;
                        if (bitrem) c->data[byteoff++] |= b>>bitrem;
                        else        c->data[byteoff++]  = b;
                        bitoff += (unsigned int)bits;
                        if (bitoff==WHIRLPOOL_BBLOCK)
                              {
                              whirlpool_block(c,c->data,1);
                              byteoff  = 0;
                              bitoff  %= WHIRLPOOL_BBLOCK;
                              }
                        if (bitrem) c->data[byteoff] = b<<(8-bitrem);
                        bits = 0;
                        }
                  c->bitoff = bitoff;
                  }
            }
      }

int WHIRLPOOL_Final     (unsigned char *md,WHIRLPOOL_CTX *c)
      {
      unsigned int      bitoff  = c->bitoff,
                  byteoff = bitoff/8;
      size_t            i,j,v;
      unsigned char  *p;

      bitoff %= 8;
      if (bitoff) c->data[byteoff] |= 0x80>>bitoff;
      else        c->data[byteoff]  = 0x80;
      byteoff++;

      /* pad with zeros */
      if (byteoff > (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER))
            {
            if (byteoff<WHIRLPOOL_BBLOCK/8)
                  memset(&c->data[byteoff],0,WHIRLPOOL_BBLOCK/8-byteoff);
            whirlpool_block(c,c->data,1);
            byteoff = 0;
            }
      if (byteoff < (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER))
            memset(&c->data[byteoff],0,
                  (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER)-byteoff);
      /* smash 256-bit c->bitlen in big-endian order */
      p = &c->data[WHIRLPOOL_BBLOCK/8-1]; /* last byte in c->data */
      for(i=0;i<WHIRLPOOL_COUNTER/sizeof(size_t);i++)
            for(v=c->bitlen[i],j=0;j<sizeof(size_t);j++,v>>=8)
                  *p-- = (unsigned char)(v&0xff);

      whirlpool_block(c,c->data,1);

      if (md)     {
            memcpy(md,c->H.c,WHIRLPOOL_DIGEST_LENGTH);
            memset(c,0,sizeof(*c));
            return(1);
            }
      return(0);
      }

unsigned char *WHIRLPOOL(const void *inp, size_t bytes,unsigned char *md)
      {
      WHIRLPOOL_CTX ctx;
      static unsigned char m[WHIRLPOOL_DIGEST_LENGTH];

      if (md == NULL) md=m;
      WHIRLPOOL_Init(&ctx);
      WHIRLPOOL_Update(&ctx,inp,bytes);
      WHIRLPOOL_Final(md,&ctx);
      return(md);
      }

Generated by  Doxygen 1.6.0   Back to index