iterhash.cpp

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

Generated on Sat Dec 23 02:07:08 2006 for Crypto++ by  doxygen 1.5.1-p1