Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

xormac.h

00001 // xormac.h - written and placed in the public domain by Wei Dai
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};};     // VC60 workaround
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 &params);
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;}    // need to override this
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))};  // VC60 workaround
00053         FixedSizeSecBlock<HashWordType, BUFFER_SIZE> m_buffer;
00054         word32 m_counter, m_index;
00055 };
00056 
00057 //! <a href="http://www.weidai.com/scan-mirror/mac.html#XMAC">XMAC</a>
00058 /*! If you need to generate MACs with XMACC (instead of just verifying them),
00059         you must save the counter before destroying an XMACC object
00060         and reinitialize it the next time you create an XMACC with the same key.
00061         Start counter at 0 when using a key for the first time. */
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 &params)
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()); // byteReverse for backwards compatibility
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();              // reinit for next use
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()); // byteReverse for backwards compatibility
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();              // reinit for next use
00165         return macValid;
00166 }
00167 
00168 NAMESPACE_END
00169 
00170 #endif

Generated on Sun Mar 14 20:44:29 2004 for Crypto++ by doxygen 1.3.6-20040222