// 
// sha.cxx
//
// Abstract base class for the two versions of the
// NIST/NSA's Secure Hash Algorithm
// (first defined in FIPS180 but modified in FIPS180-1)
//
// this implementation
// Copyright (C) 1996-7 by Leonard Janke (janke@unixg.ubc.ca)

#include <chnhash/sha.hxx>
#include <lmisc/lmisc.hxx>
#include <iostream.h>
#include <iomanip.h>
#include <cstring>
#include <cassert>

SHA::SHA() : ChainHash(512,160)
{
  H[0]=H0;
  H[1]=H1;
  H[2]=H2;
  H[3]=H3;
  H[4]=H4;
}

SHA::~SHA()
{
}

void SHA::ProcessMiddleBlock(const void* block)
{
  memcpy(buf,block,64);
  LMisc::MemSwap(buf,16);
  ProcessBuf();
  _bitCount+=512;
}

void SHA::ProcessFinalBlock(const void* block, const int size)
{
  assert ( size>=0 && size<=64);

  _bitCount+=(size*8);

  int zeroBytesInPad=( size<= 55 ) ? 55-size: 119-size;

  int numBytes=(size+9+zeroBytesInPad);

  if ( numBytes==128 )
    {
      u32 preBuf[32];
      u8* curByte=(u8*) preBuf;

      memcpy(curByte,block,size); curByte+=size;

      *(curByte++)=0x80;
 
      LMisc::MemZero(curByte,zeroBytesInPad); curByte+=zeroBytesInPad;

      preBuf[30]=LMisc::High32Of64(_bitCount);
      preBuf[31]=LMisc::Low32Of64(_bitCount);

      LMisc::MemSwap(preBuf,30);

      LMisc::MemCopy(buf,preBuf,16);
      ProcessBuf();
      LMisc::MemCopy(buf,preBuf+16,16);
      ProcessBuf();
    }
  else //  numBytes == 64 
    {
      u8* curByte=(u8*) buf;
      memcpy(curByte,block,size); curByte+=size;

      *(curByte++)=0x80;
 
      LMisc::MemZero(curByte,zeroBytesInPad); curByte+=zeroBytesInPad;

      buf[14]=LMisc::High32Of64(_bitCount);
      buf[15]=LMisc::Low32Of64(_bitCount);

      LMisc::MemSwap(buf,14);
      ProcessBuf();
    }
}

void SHA::Reset()
{
  H[0]=H0;
  H[1]=H1;
  H[2]=H2;
  H[3]=H3;
  H[4]=H4;

  _bitCount=0;
}

void SHA::ChainVariables(void* buffer) const
{
  u32 cvCopy[5];
  LMisc::MemCopy(cvCopy,H,5);
  LMisc::MemSwap(cvCopy,5);
  memcpy(buffer,cvCopy,20);
}
