- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

# iterhash.cpp

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