00001
00002
00003 #ifndef CRYPTOPP_XORMAC_H
00004 #define CRYPTOPP_XORMAC_H
00005
00006 #include "seckey.h"
00007 #include "iterhash.h"
00008 #include "argnames.h"
00009 #include "algparam.h"
00010
00011 NAMESPACE_BEGIN(CryptoPP)
00012
00013 template <class T> struct DigestSizeSubtract4Workaround
00014 {
00015 CRYPTOPP_CONSTANT(RESULT = T::DIGESTSIZE-4)
00016 };
00017
00018 template <class T>
00019 class CRYPTOPP_NO_VTABLE XMACC_Base : public FixedKeyLength<DigestSizeSubtract4Workaround<T>::RESULT, SimpleKeyingInterface::INTERNALLY_GENERATED_IV>,
00020 public IteratedHash<typename T::HashWordType, typename T::ByteOrderClass, T::BLOCKSIZE, MessageAuthenticationCode>
00021 {
00022 public:
00023 static std::string StaticAlgorithmName() {return std::string("XMAC(") + T::StaticAlgorithmName() + ")";}
00024 CRYPTOPP_CONSTANT(DIGESTSIZE = 4+T::DIGESTSIZE)
00025 typedef typename T::HashWordType HashWordType;
00026
00027 XMACC_Base() {SetStateSize(T::DIGESTSIZE);}
00028
00029 void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms);
00030 void Resynchronize(const byte *IV)
00031 {
00032 GetWord(false, BIG_ENDIAN_ORDER, m_counter, IV);
00033 this->Restart();
00034 }
00035 unsigned int IVSize() const
00036 {return 4;}
00037 void GetNextIV(byte *IV)
00038 {
00039 if (m_counter == 0xffffffff)
00040 throw NotImplemented("XMACC: must have a valid counter to get next IV");
00041 PutWord(false, BIG_ENDIAN_ORDER, IV, m_counter+1);
00042 }
00043
00044 word32 CurrentCounter() const {return m_counter;}
00045
00046 void TruncatedFinal(byte *mac, size_t size);
00047 bool TruncatedVerify(const byte *mac, size_t length);
00048 unsigned int DigestSize() const {return DIGESTSIZE;}
00049
00050 private:
00051 void Init();
00052 static void WriteWord32(byte *output, word32 value);
00053 static void XorDigest(HashWordType *digest, const HashWordType *buffer);
00054 void HashEndianCorrectedBlock(const HashWordType *data);
00055
00056 FixedSizeSecBlock<byte, DigestSizeSubtract4Workaround<T>::RESULT> m_key;
00057 CRYPTOPP_CONSTANT(BUFFER_SIZE = (T::DIGESTSIZE / sizeof(HashWordType)))
00058 #ifdef __BORLANDC__
00059 FixedSizeSecBlock<HashWordType, T::DIGESTSIZE / sizeof(HashWordType)> m_buffer;
00060 #else
00061 FixedSizeSecBlock<HashWordType, BUFFER_SIZE> m_buffer;
00062 #endif
00063 word32 m_counter, m_index;
00064 };
00065
00066
00067
00068
00069
00070
00071 template <class T>
00072 class XMACC : public ClonableImpl<XMACC<T>, MessageAuthenticationCodeImpl<XMACC_Base<T> > >
00073 {
00074 public:
00075 XMACC() {}
00076 XMACC(const byte *key, word32 counter = 0xffffffff)
00077 {this->SetKey(key, this->KEYLENGTH, MakeParameters(Name::XMACC_Counter(), counter));}
00078 };
00079
00080 template <class T> void XMACC_Base<T>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms)
00081 {
00082 this->AssertValidKeyLength(length);
00083 m_counter = 0xffffffff;
00084 const byte *iv = NULL;
00085 if (params.GetValue(Name::IV(), iv))
00086 GetWord(false, BIG_ENDIAN_ORDER, m_counter, iv);
00087 else
00088 params.GetValue(Name::XMACC_Counter(), m_counter);
00089 memcpy_s(m_key, m_key.SizeInBytes(), key, this->KEYLENGTH);
00090 Init();
00091 }
00092
00093 template <class T> void XMACC_Base<T>::Init()
00094 {
00095 m_index = 0x80000000;
00096 memset(this->m_digest, 0, T::DIGESTSIZE);
00097 }
00098
00099 template <class T> inline void XMACC_Base<T>::WriteWord32(byte *output, word32 value)
00100 {
00101 output[0] = byte(value >> 24);
00102 output[1] = byte(value >> 16);
00103 output[2] = byte(value >> 8);
00104 output[3] = byte(value);
00105 }
00106
00107 template <class T> inline void XMACC_Base<T>::XorDigest(HashWordType *digest, const HashWordType *buffer)
00108 {
00109 for (unsigned i=0; i<(T::DIGESTSIZE/sizeof(HashWordType)); i++)
00110 digest[i] ^= buffer[i];
00111 }
00112
00113 template <class T> void XMACC_Base<T>::HashEndianCorrectedBlock(const HashWordType *input)
00114 {
00115 memcpy_s(m_buffer, m_buffer.SizeInBytes(), m_key, this->KEYLENGTH);
00116 WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, ++m_index);
00117 T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
00118 T::Transform(m_buffer, input);
00119 XorDigest(this->m_digest, m_buffer);
00120 }
00121
00122 template <class T> void XMACC_Base<T>::TruncatedFinal(byte *mac, size_t size)
00123 {
00124 this->ThrowIfInvalidTruncatedSize(size);
00125 if (size < 4)
00126 throw InvalidArgument("XMACC: truncating the MAC to less than 4 bytes will cause it to be unverifiable");
00127 if (m_counter == 0xffffffff)
00128 throw InvalidArgument("XMACC: the counter must be initialized to a valid value for MAC generation");
00129
00130 PadLastBlock(this->BLOCKSIZE - 2*sizeof(HashWordType));
00131 CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE - 2*sizeof(HashWordType));
00132 this->m_data[this->m_data.size()-2] = ByteReverse(this->GetBitCountHi());
00133 this->m_data[this->m_data.size()-1] = ByteReverse(this->GetBitCountLo());
00134 HashEndianCorrectedBlock(this->m_data);
00135
00136 memcpy_s(m_buffer, m_buffer.SizeInBytes(), m_key, this->KEYLENGTH);
00137 WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, 0);
00138 memset(this->m_data, 0, this->BLOCKSIZE-4);
00139 WriteWord32((byte *)this->m_data.begin()+this->BLOCKSIZE-4, ++m_counter);
00140 T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
00141 T::CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE);
00142 T::Transform(m_buffer, this->m_data);
00143 XorDigest(this->m_digest, m_buffer);
00144
00145 WriteWord32(mac, m_counter);
00146 T::CorrectEndianess(this->m_digest, this->m_digest, T::DIGESTSIZE);
00147 memcpy_s(mac+4, size-4, this->m_digest, size-4);
00148
00149 this->Restart();
00150 }
00151
00152 template <class T> bool XMACC_Base<T>::TruncatedVerify(const byte *mac, size_t size)
00153 {
00154 assert(4 <= size && size <= DIGESTSIZE);
00155
00156 PadLastBlock(this->BLOCKSIZE - 2*sizeof(HashWordType));
00157 CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE - 2*sizeof(HashWordType));
00158 this->m_data[this->m_data.size()-2] = ByteReverse(this->GetBitCountHi());
00159 this->m_data[this->m_data.size()-1] = ByteReverse(this->GetBitCountLo());
00160 HashEndianCorrectedBlock(this->m_data);
00161
00162 memcpy_s(m_buffer, m_buffer.SizeInBytes(), m_key, this->KEYLENGTH);
00163 WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, 0);
00164 memset(this->m_data, 0, this->BLOCKSIZE-4);
00165 memcpy_s((byte *)this->m_data.begin()+this->BLOCKSIZE-4, 4, mac, 4);
00166 T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
00167 T::CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE);
00168 T::Transform(m_buffer, this->m_data);
00169 XorDigest(this->m_digest, m_buffer);
00170
00171 T::CorrectEndianess(this->m_digest, this->m_digest, T::DIGESTSIZE);
00172 bool macValid = (memcmp(mac+4, this->m_digest, size-4) == 0);
00173 this->Restart();
00174 return macValid;
00175 }
00176
00177 NAMESPACE_END
00178
00179 #endif