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

Generated on Thu Mar 30 22:11:50 2006 for Crypto++ by  doxygen 1.4.6