- Main Page
- Namespaces
- Classes
- Files

- File List
- 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         // 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