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 "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 {enum {RESULT = T::DIGESTSIZE-4};};     // VC60 workaround
    00014
    00015 template <class T>
    00016 class CRYPTOPP_NO_VTABLE XMACC_Base : public FixedKeyLength<DigestSizeSubtract4Workaround<T>::RESULT, SimpleKeyingInterface::INTERNALLY_GENERATED_IV>,
    00017                                         public IteratedHash<typename T::HashWordType, typename T::ByteOrderClass, T::BLOCKSIZE, MessageAuthenticationCode>
    00018 {
    00019 public:
    00020         static std::string StaticAlgorithmName() {return std::string("XMAC(") + T::StaticAlgorithmName() + ")";}
    00021         enum {DIGESTSIZE = 4+T::DIGESTSIZE};
    00022         typedef typename T::HashWordType HashWordType;
    00023
    00024         XMACC_Base() {SetStateSize(T::DIGESTSIZE);}
    00025
    00026         void CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs &params);
    00027         void Resynchronize(const byte *IV)
    00028         {
    00029                 GetWord(false, BIG_ENDIAN_ORDER, m_counter, IV);
    00030                 this->Restart();
    00031         }
    00032         unsigned int IVSize() const
    00033                 {return 4;}
    00034         void GetNextIV(byte *IV)
    00035         {
    00036                 if (m_counter == 0xffffffff)
    00037                         throw NotImplemented("XMACC: must have a valid counter to get next IV");
    00038                 PutWord(false, BIG_ENDIAN_ORDER, IV, m_counter+1);
    00039         }
    00040
    00041         word32 CurrentCounter() const {return m_counter;}
    00042
    00043         void TruncatedFinal(byte *mac, unsigned int size);
    00044         bool TruncatedVerify(const byte *mac, unsigned int length);
    00045         unsigned int DigestSize() const {return DIGESTSIZE;}    // need to override this
    00046
    00047 private:
    00048         void Init();
    00049         static void WriteWord32(byte *output, word32 value);
    00050         static void XorDigest(HashWordType *digest, const HashWordType *buffer);
    00051         void HashEndianCorrectedBlock(const HashWordType *data);
    00052
    00053         FixedSizeSecBlock<byte, DigestSizeSubtract4Workaround<T>::RESULT> m_key;
    00054         enum {BUFFER_SIZE = ((T::DIGESTSIZE) / sizeof(HashWordType))};  // VC60 workaround
    00055         FixedSizeSecBlock<HashWordType, BUFFER_SIZE> m_buffer;
    00056         word32 m_counter, m_index;
    00057 };
    00058
    00059 //! <a href="http://www.weidai.com/scan-mirror/mac.html#XMAC">XMAC</a>
    00060 /*! If you need to generate MACs with XMACC (instead of just verifying them),
    00061         you must save the counter before destroying an XMACC object
    00062         and reinitialize it the next time you create an XMACC with the same key.
    00063         Start counter at 0 when using a key for the first time. */
    00064 template <class T>
    00065 class XMACC : public ClonableImpl<XMACC<T>, MessageAuthenticationCodeImpl<XMACC_Base<T> > >
    00066 {
    00067 public:
    00068         XMACC() {}
    00069         XMACC(const byte *key, word32 counter = 0xffffffff)
    00070                 {this->SetKey(key, this->KEYLENGTH, MakeParameters(Name::XMACC_Counter(), counter));}
    00071 };
    00072
    00073 template <class T> void XMACC_Base<T>::CheckedSetKey(void *, Empty empty, const byte *key, unsigned int length, const NameValuePairs &params)
    00074 {
    00075         this->ThrowIfInvalidKeyLength(length);
    00076         m_counter = 0xffffffff;
    00077         const byte *iv = NULL;
    00078         if (params.GetValue(Name::IV(), iv))
    00079                 GetWord(false, BIG_ENDIAN_ORDER, m_counter, iv);
    00080         else
    00081                 params.GetValue(Name::XMACC_Counter(), m_counter);
    00082         memcpy(m_key, key, this->KEYLENGTH);
    00083         Init();
    00084 }
    00085
    00086 template <class T> void XMACC_Base<T>::Init()
    00087 {
    00088         m_index = 0x80000000;
    00089         memset(this->m_digest, 0, T::DIGESTSIZE);
    00090 }
    00091
    00092 template <class T> inline void XMACC_Base<T>::WriteWord32(byte *output, word32 value)
    00093 {
    00094         output[0] = byte(value >> 24);
    00095         output[1] = byte(value >> 16);
    00096         output[2] = byte(value >> 8);
    00097         output[3] = byte(value);
    00098 }
    00099
    00100 template <class T> inline void XMACC_Base<T>::XorDigest(HashWordType *digest, const HashWordType *buffer)
    00101 {
    00102         for (unsigned i=0; i<(T::DIGESTSIZE/sizeof(HashWordType)); i++)
    00103                 digest[i] ^= buffer[i];
    00104 }
    00105
    00106 template <class T> void XMACC_Base<T>::HashEndianCorrectedBlock(const HashWordType *input)
    00107 {
    00108         memcpy(m_buffer, m_key, this->KEYLENGTH);
    00109         WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, ++m_index);
    00110         T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
    00111         T::Transform(m_buffer, input);
    00112         XorDigest(this->m_digest, m_buffer);
    00113 }
    00114
    00115 template <class T> void XMACC_Base<T>::TruncatedFinal(byte *mac, unsigned int size)
    00116 {
    00117         this->ThrowIfInvalidTruncatedSize(size);
    00118         if (size < 4)
    00119                 throw InvalidArgument("XMACC: truncating the MAC to less than 4 bytes will cause it to be unverifiable");
    00120         if (m_counter == 0xffffffff)
    00121                 throw InvalidArgument("XMACC: the counter must be initialized to a valid value for MAC generation");
    00122
    00123         PadLastBlock(this->BLOCKSIZE - 2*sizeof(HashWordType));
    00124         CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE - 2*sizeof(HashWordType));
    00125         this->m_data[this->m_data.size()-2] = ByteReverse(this->GetBitCountHi());       // ByteReverse for backwards compatibility
    00126         this->m_data[this->m_data.size()-1] = ByteReverse(this->GetBitCountLo());
    00127         HashEndianCorrectedBlock(this->m_data);
    00128
    00129         memcpy(m_buffer, m_key, this->KEYLENGTH);
    00130         WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, 0);
    00131         memset(this->m_data, 0, this->BLOCKSIZE-4);
    00132         WriteWord32((byte *)this->m_data.begin()+this->BLOCKSIZE-4, ++m_counter);
    00133         T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
    00134         T::CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE);
    00135         T::Transform(m_buffer, this->m_data);
    00136         XorDigest(this->m_digest, m_buffer);
    00137
    00138         WriteWord32(mac, m_counter);
    00139         T::CorrectEndianess(this->m_digest, this->m_digest, T::DIGESTSIZE);
    00140         memcpy(mac+4, this->m_digest, size-4);
    00141
    00142         this->Restart();                // reinit for next use
    00143 }
    00144
    00145 template <class T> bool XMACC_Base<T>::TruncatedVerify(const byte *mac, unsigned int size)
    00146 {
    00147         assert(4 <= size && size <= DIGESTSIZE);
    00148
    00149         PadLastBlock(this->BLOCKSIZE - 2*sizeof(HashWordType));
    00150         CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE - 2*sizeof(HashWordType));
    00151         this->m_data[this->m_data.size()-2] = ByteReverse(this->GetBitCountHi());       // ByteReverse for backwards compatibility
    00152         this->m_data[this->m_data.size()-1] = ByteReverse(this->GetBitCountLo());
    00153         HashEndianCorrectedBlock(this->m_data);
    00154
    00155         memcpy(m_buffer, m_key, this->KEYLENGTH);
    00156         WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, 0);
    00157         memset(this->m_data, 0, this->BLOCKSIZE-4);
    00158         memcpy((byte *)this->m_data.begin()+this->BLOCKSIZE-4, mac, 4);
    00159         T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
    00160         T::CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE);
    00161         T::Transform(m_buffer, this->m_data);
    00162         XorDigest(this->m_digest, m_buffer);
    00163
    00164         T::CorrectEndianess(this->m_digest, this->m_digest, T::DIGESTSIZE);
    00165         bool macValid = (memcmp(mac+4, this->m_digest, size-4) == 0);
    00166         this->Restart();                // reinit for next use
    00167         return macValid;
    00168 }
    00169
    00170 NAMESPACE_END
    00171
    00172 #endif