Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound 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 MessageAuthenticationCodeFinalTemplate<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