Crypto++
|
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 if (len && data != input) 00070 memcpy(data, input, len); 00071 } 00072 00073 template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size) 00074 { 00075 unsigned int blockSize = this->BlockSize(); 00076 unsigned int num = ModPowerOf2(m_countLo, blockSize); 00077 size = blockSize - num; 00078 return (byte *)DataBuf() + num; 00079 } 00080 00081 template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length) 00082 { 00083 unsigned int blockSize = this->BlockSize(); 00084 bool noReverse = NativeByteOrderIs(this->GetByteOrder()); 00085 T* dataBuf = this->DataBuf(); 00086 do 00087 { 00088 if (noReverse) 00089 this->HashEndianCorrectedBlock(input); 00090 else 00091 { 00092 ByteReverse(dataBuf, input, this->BlockSize()); 00093 this->HashEndianCorrectedBlock(dataBuf); 00094 } 00095 00096 input += blockSize/sizeof(T); 00097 length -= blockSize; 00098 } 00099 while (length >= blockSize); 00100 return length; 00101 } 00102 00103 template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst) 00104 { 00105 unsigned int blockSize = this->BlockSize(); 00106 unsigned int num = ModPowerOf2(m_countLo, blockSize); 00107 T* dataBuf = this->DataBuf(); 00108 byte* data = (byte *)dataBuf; 00109 data[num++] = padFirst; 00110 if (num <= lastBlockSize) 00111 memset(data+num, 0, lastBlockSize-num); 00112 else 00113 { 00114 memset(data+num, 0, blockSize-num); 00115 HashBlock(dataBuf); 00116 memset(data, 0, lastBlockSize); 00117 } 00118 } 00119 00120 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart() 00121 { 00122 m_countLo = m_countHi = 0; 00123 Init(); 00124 } 00125 00126 template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size) 00127 { 00128 this->ThrowIfInvalidTruncatedSize(size); 00129 00130 T* dataBuf = this->DataBuf(); 00131 T* stateBuf = this->StateBuf(); 00132 unsigned int blockSize = this->BlockSize(); 00133 ByteOrder order = this->GetByteOrder(); 00134 00135 PadLastBlock(blockSize - 2*sizeof(HashWordType)); 00136 dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo()); 00137 dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi()); 00138 00139 HashBlock(dataBuf); 00140 00141 if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0) 00142 ConditionalByteReverse<HashWordType>(order, (HashWordType *)digest, stateBuf, size); 00143 else 00144 { 00145 ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize()); 00146 memcpy(digest, stateBuf, size); 00147 } 00148 00149 this->Restart(); // reinit for next use 00150 } 00151 00152 #ifdef __GNUC__ 00153 template class IteratedHashBase<word64, HashTransformation>; 00154 template class IteratedHashBase<word64, MessageAuthenticationCode>; 00155 00156 template class IteratedHashBase<word32, HashTransformation>; 00157 template class IteratedHashBase<word32, MessageAuthenticationCode>; 00158 #endif 00159 00160 NAMESPACE_END