diff options
Diffstat (limited to 'plugins/CryptoPP/crypto/src/xormac.h')
-rw-r--r-- | plugins/CryptoPP/crypto/src/xormac.h | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/plugins/CryptoPP/crypto/src/xormac.h b/plugins/CryptoPP/crypto/src/xormac.h new file mode 100644 index 0000000000..977b2cd6f7 --- /dev/null +++ b/plugins/CryptoPP/crypto/src/xormac.h @@ -0,0 +1,179 @@ +// xormac.h - written and placed in the public domain by Wei Dai
+
+#ifndef CRYPTOPP_XORMAC_H
+#define CRYPTOPP_XORMAC_H
+
+#include "seckey.h"
+#include "iterhash.h"
+#include "argnames.h"
+#include "algparam.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+template <class T> struct DigestSizeSubtract4Workaround // VC60 workaround
+{
+ CRYPTOPP_CONSTANT(RESULT = T::DIGESTSIZE-4)
+};
+
+template <class T>
+class CRYPTOPP_NO_VTABLE XMACC_Base : public FixedKeyLength<DigestSizeSubtract4Workaround<T>::RESULT, SimpleKeyingInterface::INTERNALLY_GENERATED_IV>,
+ public IteratedHash<typename T::HashWordType, typename T::ByteOrderClass, T::BLOCKSIZE, MessageAuthenticationCode>
+{
+public:
+ static std::string StaticAlgorithmName() {return std::string("XMAC(") + T::StaticAlgorithmName() + ")";}
+ CRYPTOPP_CONSTANT(DIGESTSIZE = 4+T::DIGESTSIZE)
+ typedef typename T::HashWordType HashWordType;
+
+ XMACC_Base() {SetStateSize(T::DIGESTSIZE);}
+
+ void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms);
+ void Resynchronize(const byte *IV)
+ {
+ GetWord(false, BIG_ENDIAN_ORDER, m_counter, IV);
+ this->Restart();
+ }
+ unsigned int IVSize() const
+ {return 4;}
+ void GetNextIV(byte *IV)
+ {
+ if (m_counter == 0xffffffff)
+ throw NotImplemented("XMACC: must have a valid counter to get next IV");
+ PutWord(false, BIG_ENDIAN_ORDER, IV, m_counter+1);
+ }
+
+ word32 CurrentCounter() const {return m_counter;}
+
+ void TruncatedFinal(byte *mac, size_t size);
+ bool TruncatedVerify(const byte *mac, size_t length);
+ unsigned int DigestSize() const {return DIGESTSIZE;} // need to override this
+
+private:
+ void Init();
+ static void WriteWord32(byte *output, word32 value);
+ static void XorDigest(HashWordType *digest, const HashWordType *buffer);
+ void HashEndianCorrectedBlock(const HashWordType *data);
+
+ FixedSizeSecBlock<byte, DigestSizeSubtract4Workaround<T>::RESULT> m_key;
+ CRYPTOPP_CONSTANT(BUFFER_SIZE = (T::DIGESTSIZE / sizeof(HashWordType))) // VC60 workaround
+#ifdef __BORLANDC__
+ FixedSizeSecBlock<HashWordType, T::DIGESTSIZE / sizeof(HashWordType)> m_buffer;
+#else
+ FixedSizeSecBlock<HashWordType, BUFFER_SIZE> m_buffer;
+#endif
+ word32 m_counter, m_index;
+};
+
+//! <a href="http://www.weidai.com/scan-mirror/mac.html#XMAC">XMAC</a>
+/*! If you need to generate MACs with XMACC (instead of just verifying them),
+ you must save the counter before destroying an XMACC object
+ and reinitialize it the next time you create an XMACC with the same key.
+ Start counter at 0 when using a key for the first time. */
+template <class T>
+class XMACC : public ClonableImpl<XMACC<T>, MessageAuthenticationCodeImpl<XMACC_Base<T> > >
+{
+public:
+ XMACC() {}
+ XMACC(const byte *key, word32 counter = 0xffffffff)
+ {this->SetKey(key, this->KEYLENGTH, MakeParameters(Name::XMACC_Counter(), counter));}
+};
+
+template <class T> void XMACC_Base<T>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms)
+{
+ this->AssertValidKeyLength(length);
+ m_counter = 0xffffffff;
+ const byte *iv = NULL;
+ if (params.GetValue(Name::IV(), iv))
+ GetWord(false, BIG_ENDIAN_ORDER, m_counter, iv);
+ else
+ params.GetValue(Name::XMACC_Counter(), m_counter);
+ memcpy_s(m_key, m_key.SizeInBytes(), key, this->KEYLENGTH);
+ Init();
+}
+
+template <class T> void XMACC_Base<T>::Init()
+{
+ m_index = 0x80000000;
+ memset(this->m_digest, 0, T::DIGESTSIZE);
+}
+
+template <class T> inline void XMACC_Base<T>::WriteWord32(byte *output, word32 value)
+{
+ output[0] = byte(value >> 24);
+ output[1] = byte(value >> 16);
+ output[2] = byte(value >> 8);
+ output[3] = byte(value);
+}
+
+template <class T> inline void XMACC_Base<T>::XorDigest(HashWordType *digest, const HashWordType *buffer)
+{
+ for (unsigned i=0; i<(T::DIGESTSIZE/sizeof(HashWordType)); i++)
+ digest[i] ^= buffer[i];
+}
+
+template <class T> void XMACC_Base<T>::HashEndianCorrectedBlock(const HashWordType *input)
+{
+ memcpy_s(m_buffer, m_buffer.SizeInBytes(), m_key, this->KEYLENGTH);
+ WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, ++m_index);
+ T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
+ T::Transform(m_buffer, input);
+ XorDigest(this->m_digest, m_buffer);
+}
+
+template <class T> void XMACC_Base<T>::TruncatedFinal(byte *mac, size_t size)
+{
+ this->ThrowIfInvalidTruncatedSize(size);
+ if (size < 4)
+ throw InvalidArgument("XMACC: truncating the MAC to less than 4 bytes will cause it to be unverifiable");
+ if (m_counter == 0xffffffff)
+ throw InvalidArgument("XMACC: the counter must be initialized to a valid value for MAC generation");
+
+ PadLastBlock(this->BLOCKSIZE - 2*sizeof(HashWordType));
+ CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE - 2*sizeof(HashWordType));
+ this->m_data[this->m_data.size()-2] = ByteReverse(this->GetBitCountHi()); // ByteReverse for backwards compatibility
+ this->m_data[this->m_data.size()-1] = ByteReverse(this->GetBitCountLo());
+ HashEndianCorrectedBlock(this->m_data);
+
+ memcpy_s(m_buffer, m_buffer.SizeInBytes(), m_key, this->KEYLENGTH);
+ WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, 0);
+ memset(this->m_data, 0, this->BLOCKSIZE-4);
+ WriteWord32((byte *)this->m_data.begin()+this->BLOCKSIZE-4, ++m_counter);
+ T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
+ T::CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE);
+ T::Transform(m_buffer, this->m_data);
+ XorDigest(this->m_digest, m_buffer);
+
+ WriteWord32(mac, m_counter);
+ T::CorrectEndianess(this->m_digest, this->m_digest, T::DIGESTSIZE);
+ memcpy_s(mac+4, size-4, this->m_digest, size-4);
+
+ this->Restart(); // reinit for next use
+}
+
+template <class T> bool XMACC_Base<T>::TruncatedVerify(const byte *mac, size_t size)
+{
+ assert(4 <= size && size <= DIGESTSIZE);
+
+ PadLastBlock(this->BLOCKSIZE - 2*sizeof(HashWordType));
+ CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE - 2*sizeof(HashWordType));
+ this->m_data[this->m_data.size()-2] = ByteReverse(this->GetBitCountHi()); // ByteReverse for backwards compatibility
+ this->m_data[this->m_data.size()-1] = ByteReverse(this->GetBitCountLo());
+ HashEndianCorrectedBlock(this->m_data);
+
+ memcpy_s(m_buffer, m_buffer.SizeInBytes(), m_key, this->KEYLENGTH);
+ WriteWord32((byte *)m_buffer.begin()+this->KEYLENGTH, 0);
+ memset(this->m_data, 0, this->BLOCKSIZE-4);
+ memcpy_s((byte *)this->m_data.begin()+this->BLOCKSIZE-4, 4, mac, 4);
+ T::CorrectEndianess(m_buffer, m_buffer, T::DIGESTSIZE);
+ T::CorrectEndianess(this->m_data, this->m_data, this->BLOCKSIZE);
+ T::Transform(m_buffer, this->m_data);
+ XorDigest(this->m_digest, m_buffer);
+
+ T::CorrectEndianess(this->m_digest, this->m_digest, T::DIGESTSIZE);
+ bool macValid = (memcmp(mac+4, this->m_digest, size-4) == 0);
+ this->Restart(); // reinit for next use
+ return macValid;
+}
+
+NAMESPACE_END
+
+#endif
|