- Main Page
- Namespaces
- Classes
- Files

# iterhash.cpp

    00001 // iterhash.cpp - written and placed in the public domain by Wei Dai
    00002
    00003 #ifndef __GNUC__
    00004 #define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
    00005 #endif
    00006
    00007 #include "iterhash.h"
    00008 #include "misc.h"
    00009
    00010 NAMESPACE_BEGIN(CryptoPP)
    00011
    00012 template <class T, class BASE> void IteratedHashBase<T, BASE>::Update(const byte *input, size_t len)
    00013 {
    00014         HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi;
    00015         if ((m_countLo = oldCountLo + HashWordType(len)) < oldCountLo)
    00016                 m_countHi++;             // carry from low to high
    00017         m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(len);
    00018         if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(len) != 0)
    00019                 throw HashInputTooLong(this->AlgorithmName());
    00020
    00021         unsigned int blockSize = this->BlockSize();
    00022         unsigned int num = ModPowerOf2(oldCountLo, blockSize);
    00023         T* dataBuf = this->DataBuf();
    00024         byte* data = (byte *)dataBuf;
    00025
    00026         if (num != 0)   // process left over data
    00027         {
    00028                 if (num+len >= blockSize)
    00029                 {
    00030                         memcpy(data+num, input, blockSize-num);
    00031                         HashBlock(dataBuf);
    00032                         input += (blockSize-num);
    00033                         len -= (blockSize-num);
    00034                         num = 0;
    00035                         // drop through and do the rest
    00036                 }
    00037                 else
    00038                 {
    00039                         memcpy(data+num, input, len);
    00040                         return;
    00041                 }
    00042         }
    00043
    00044         // now process the input data in blocks of blockSize bytes and save the leftovers to m_data
    00045         if (len >= blockSize)
    00046         {
    00047                 if (input == data)
    00048                 {
    00049                         assert(len == blockSize);
    00050                         HashBlock(dataBuf);
    00051                         return;
    00052                 }
    00053                 else if (IsAligned<T>(input))
    00054                 {
    00055                         size_t leftOver = HashMultipleBlocks((T *)input, len);
    00056                         input += (len - leftOver);
    00057                         len = leftOver;
    00058                 }
    00059                 else
    00060                         do
    00061                         {   // copy input first if it's not aligned correctly
    00062                                 memcpy(data, input, blockSize);
    00063                                 HashBlock(dataBuf);
    00064                                 input+=blockSize;
    00065                                 len-=blockSize;
    00066                         } while (len >= blockSize);
    00067         }
    00068
    00069         memcpy(data, input, len);
    00070 }
    00071
    00072 template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size)
    00073 {
    00074         unsigned int blockSize = this->BlockSize();
    00075         unsigned int num = ModPowerOf2(m_countLo, blockSize);
    00076         size = blockSize - num;
    00077         return (byte *)DataBuf() + num;
    00078 }
    00079
    00080 template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length)
    00081 {
    00082         unsigned int blockSize = this->BlockSize();
    00083         bool noReverse = NativeByteOrderIs(this->GetByteOrder());
    00084         T* dataBuf = this->DataBuf();
    00085         do
    00086         {
    00087                 if (noReverse)
    00088                         this->HashEndianCorrectedBlock(input);
    00089                 else
    00090                 {
    00091                         ByteReverse(dataBuf, input, this->BlockSize());
    00092                         this->HashEndianCorrectedBlock(dataBuf);
    00093                 }
    00094
    00095                 input += blockSize/sizeof(T);
    00096                 length -= blockSize;
    00097         }
    00098         while (length >= blockSize);
    00099         return length;
    00100 }
    00101
    00102 template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
    00103 {
    00104         unsigned int blockSize = this->BlockSize();
    00105         unsigned int num = ModPowerOf2(m_countLo, blockSize);
    00106         T* dataBuf = this->DataBuf();
    00107         byte* data = (byte *)dataBuf;
    00108         data[num++] = padFirst;
    00109         if (num <= lastBlockSize)
    00110                 memset(data+num, 0, lastBlockSize-num);
    00111         else
    00112         {
    00113                 memset(data+num, 0, blockSize-num);
    00114                 HashBlock(dataBuf);
    00115                 memset(data, 0, lastBlockSize);
    00116         }
    00117 }
    00118
    00119 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
    00120 {
    00121         m_countLo = m_countHi = 0;
    00122         Init();
    00123 }
    00124
    00125 template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
    00126 {
    00127         this->ThrowIfInvalidTruncatedSize(size);
    00128
    00129         T* dataBuf = this->DataBuf();
    00130         T* stateBuf = this->StateBuf();
    00131         unsigned int blockSize = this->BlockSize();
    00132         ByteOrder order = this->GetByteOrder();
    00133
    00134         PadLastBlock(blockSize - 2*sizeof(HashWordType));
    00135         dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
    00136         dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
    00137
    00138         HashBlock(dataBuf);
    00139
    00140         if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
    00141                 ConditionalByteReverse<HashWordType>(order, (HashWordType *)digest, stateBuf, size);
    00142         else
    00143         {
    00144                 ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
    00145                 memcpy(digest, stateBuf, size);
    00146         }
    00147
    00148         this->Restart();                // reinit for next use
    00149 }
    00150
    00151 #ifdef __GNUC__
    00152         template class IteratedHashBase<word64, HashTransformation>;
    00153         template class IteratedHashBase<word64, MessageAuthenticationCode>;
    00154
    00155         template class IteratedHashBase<word32, HashTransformation>;
    00156         template class IteratedHashBase<word32, MessageAuthenticationCode>;
    00157 #endif
    00158
    00159 NAMESPACE_END