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