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

Generated on Sat Dec 23 02:07:11 2006 for Crypto++ by  doxygen 1.5.1-p1