hello,
I finally fixed the problems (I hope). I deleted the macro from the
previous version and replaced it by a templated version
(SHA3_<DigestByteSize>), facilitating the usage of SHA3.
I also deleted the HMAC_Simple class and incorporated it all into HMAC. I
included a new option to HMAC: "CompabilityMode", this will construct a
nested HMAC with SHA-3 instead of a "fast" H(K||M) HMAC.
The changed files are appended. I'll contact Wei Dai soon, when I finished
some other stuff and propose the usage of this new HMAC in Crypto++ 5.6.3
BR
JPM
Am Sonntag, 31. August 2014 15:21:00 UTC+2 schrieb Jean-Pierre Münch:
>
> hello,
>
> I've made some progress and coded a solution for the hmac problem.
> It solves the problem by introducing a new class: HMAC_Simple<>.
> If you want to use HMAC-SHA-3 this is a simple and good solution, but as
> some other dependencies need to be changed it's not yet the optimal
> solution which would include the SHA-3 special case into the main logic,
> I'll look further into it.
> I also introduced the new SHA3_X(X) Macro. This macro creates a new SHA3
> class like SHA3_512 with X instead of 512, this will in future solve some
> problems with raw SHA3 und HMAC.
> The modified files (sha3.h,hmac.h and hmac.cpp) are appended. For this
> solution to work, just copy and paste them into your copy and they'll work,
> but you need to recompile.
>
> BR
>
> JPM
>
> Am Sonntag, 31. August 2014 10:53:19 UTC+2 schrieb Jean-Pierre Münch:
>>
>> hello,
>>
>> the problem with SHA-3 and HMAC is that Keccak (SHA-3) isn't an iterated
>> block cipher or a similar construction as nearly all other ciphers are.
>> You have now 2 options:
>> Calculating HMAC_K(X)=H(K||X) by hand where you need it or defining a
>> template sepcialization for the SHA3 class for HMAC and changing the way
>> how HMAC is calulated there.
>>
>> Relevant stackoverflow topic:
>> https://crypto.stackexchange.com/questions/17735/is-hmac-needed-for-a-sha-3-based-mac
>>
>> Source code for specialization to follow soon.
>>
>> BR
>>
>> JPM
>>
>> Am Samstag, 16. August 2014 17:46:17 UTC+2 schrieb Frank Spears:
>>>
>>> hello,
>>>
>>> i tried to use the new SHA-3 hash function that is available in
>>> Crypto++ version 5.6.2, through the following code:
>>>
>>> CryptoPP::HMAC <CryptoPP::SHA3_512> sha;
>>>
>>> this compiles just fine. however, when i run the program, it crashes
>>> with the following exception:
>>>
>>> terminate called after throwing an instance of
>>> 'CryptoPP::InvalidArgument'
>>> what(): HMAC: can only be used with a block-based hash function
>>>
>>> is there a way around this? as far as i know, SHA-3 should be good
>>> enough to be used as HMAC.
>>>
>>> thanks in advance for replying!
>>>
>>> Frank Spears.
>>>
>>
--
--
You received this message because you are subscribed to the "Crypto++ Users"
Google Group.
To unsubscribe, send an email to [email protected].
More information about Crypto++ and this group is available at
http://www.cryptopp.com.
---
You received this message because you are subscribed to the Google Groups
"Crypto++ Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
// hmac.h - written and placed in the public domain by Wei Dai
#ifndef CRYPTOPP_HMAC_H
#define CRYPTOPP_HMAC_H
#include "seckey.h"
#include "secblock.h"
#include "sha3.h"
NAMESPACE_BEGIN(CryptoPP)
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HMAC_Base_Impl : public VariableKeyLength<16, 0, INT_MAX>, public MessageAuthenticationCode
{
public:
virtual void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms) =0;
virtual void Restart();
virtual void Update(const byte *input, size_t length);
virtual void TruncatedFinal(byte *mac, size_t size) =0;
virtual unsigned int DigestSize() const {return const_cast<HMAC_Base_Impl*>(this)->AccessHash()->DigestSize();}
static std::string StaticAlgorithmName() {return "";} // won't be called
protected:
virtual HashTransformation* AccessHash() =0;
virtual void KeyHash() =0;
};
//! _
class CRYPTOPP_DLL HMAC_Base_Classic : public MessageAuthenticationCodeImpl<HMAC_Base_Impl>
{
public:
HMAC_Base_Classic(HashTransformation * Hash) : m_innerHashKeyed(false),m_hash(Hash) {}
void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms);
void TruncatedFinal(byte *mac, size_t size);
protected:
byte * AccessIpad() {return m_buf;}
byte * AccessOpad() {return m_buf + AccessHash()->BlockSize();}
byte * AccessInnerHash() {return m_buf + 2*AccessHash()->BlockSize();}
HashTransformation* AccessHash() {return m_hash;}
private:
void KeyHash();
SecByteBlock m_buf;
bool m_innerHashKeyed;
HashTransformation * m_hash;
};
class CRYPTOPP_DLL HMAC_Base_Compability : public MessageAuthenticationCodeImpl<HMAC_Base_Impl>
{
public:
HMAC_Base_Compability(HashTransformation * Hash) : m_innerHashKeyed(false),m_hash(Hash) {}
void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms);
void TruncatedFinal(byte *mac, size_t size);
protected:
byte * AccessIpad() {return m_buf;}
byte * AccessOpad() {return m_buf + AccessHash()->BlockSize();}
byte * AccessInnerHash() {return m_buf + 2*AccessHash()->BlockSize();}
HashTransformation* AccessHash() {return m_hash;}
private:
void KeyHash();
SecByteBlock m_buf;
bool m_innerHashKeyed;
HashTransformation * m_hash;
};
//! _
class CRYPTOPP_DLL HMAC_Base_Fast : public MessageAuthenticationCodeImpl<HMAC_Base_Impl>
{
public:
HMAC_Base_Fast(HashTransformation * Hash) : m_HashKeyed(false),m_hash(Hash) {}
void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms);
void TruncatedFinal(byte *mac, size_t size);
protected:
virtual HashTransformation * AccessHash() {return m_hash;}
private:
void KeyHash();
SecByteBlock m_key;
bool m_HashKeyed;
HashTransformation * m_hash;
};
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HMAC_Base : public VariableKeyLength<16, 0, INT_MAX>, public MessageAuthenticationCode
{
public:
HMAC_Base();
void UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs ¶ms);
void Restart();
void Update(const byte *input, size_t length);
void TruncatedFinal(byte *mac, size_t size);
unsigned int DigestSize() const {return const_cast<HMAC_Base*>(this)->AccessHash().DigestSize();}
protected:
virtual HashTransformation & AccessHash() =0;
virtual bool IsCompabilityMode() =0;
private:
std::auto_ptr<HMAC_Base_Impl> m_ExecutingClass;
};
//! <a href="http://www.weidai.com/scan-mirror/mac.html#HMAC">HMAC</a>
/*! HMAC(K, text) = H(K XOR opad, H(K XOR ipad, text)) */
/* HMAC: can only be used with a block-based hash function, like SHA-2, SHA-1, Whirlpool, ... */
template <class T>
class HMAC : public MessageAuthenticationCodeImpl<HMAC_Base, HMAC<T> >
{
public:
CRYPTOPP_CONSTANT(DIGESTSIZE=T::DIGESTSIZE)
HMAC(const bool CompabilityMode = false) : m_hash(), m_CompabilityMode(CompabilityMode) {}
HMAC(const byte *key, size_t length=HMAC_Base::DEFAULT_KEYLENGTH,const bool CompabilityMode = false)
: m_hash(), m_CompabilityMode(CompabilityMode)
{this->SetKey(key, length);}
static std::string StaticAlgorithmName() {return std::string("HMAC(") + T::StaticAlgorithmName() + ")";}
std::string AlgorithmName() const {return std::string("HMAC(") + m_hash.AlgorithmName() + ")";}
private:
HashTransformation & AccessHash() {return m_hash;}
bool IsCompabilityMode() {return m_CompabilityMode;}
T m_hash;
const bool m_CompabilityMode;
};
NAMESPACE_END
#endif
// hmac.cpp - written and placed in the public domain by Wei Dai
#include "pch.h"
#ifndef CRYPTOPP_IMPORTS
#include "hmac.h"
NAMESPACE_BEGIN(CryptoPP)
HMAC_Base::HMAC_Base()
{
if(!AccessHash().BlockSize())
{
if(IsCompabilityMode())
m_ExecutingClass=std::auto_ptr<HMAC_Base_Impl>(new HMAC_Base_Compability(&AccessHash()));
else
m_ExecutingClass=std::auto_ptr<HMAC_Base_Impl>(new HMAC_Base_Fast(&AccessHash()));
}
else
m_ExecutingClass=std::auto_ptr<HMAC_Base_Impl>(new HMAC_Base_Classic(&AccessHash()));
}
void HMAC_Base::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs & NameValues)
{
return m_ExecutingClass->UncheckedSetKey(userKey,keylength,NameValues);
}
void HMAC_Base::Restart()
{
return m_ExecutingClass->Restart();
}
void HMAC_Base::Update(const byte *input, size_t length)
{
return m_ExecutingClass->Update(input,length);
}
void HMAC_Base::TruncatedFinal(byte *mac, size_t size)
{
return m_ExecutingClass->TruncatedFinal(mac,size);
}
void HMAC_Base_Impl::Restart()
{
AccessHash()->Restart();
}
void HMAC_Base_Impl::Update(const byte *input, size_t length)
{
KeyHash();
AccessHash()->Update(input, length);
}
void HMAC_Base_Classic::TruncatedFinal(byte *mac, size_t size)
{
ThrowIfInvalidTruncatedSize(size);
HashTransformation & hash = *AccessHash();
if (!m_innerHashKeyed)
KeyHash();
hash.Final(AccessInnerHash());
hash.Update(AccessOpad(), hash.BlockSize());
hash.Update(AccessInnerHash(), hash.DigestSize());
hash.TruncatedFinal(mac, size);
m_innerHashKeyed = false;
}
void HMAC_Base_Classic::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &)
{
AssertValidKeyLength(keylength);
Restart();
HashTransformation * hash = AccessHash();
unsigned int blockSize = hash->BlockSize();
if (!blockSize)
throw InvalidArgument("HMAC: can only be used with a block-based hash function");
m_buf.resize(2*AccessHash()->BlockSize() + AccessHash()->DigestSize());
if (keylength <= blockSize)
memcpy(AccessIpad(), userKey, keylength);
else
{
AccessHash()->CalculateDigest(AccessIpad(), userKey, keylength);
keylength = hash->DigestSize();
}
assert(keylength <= blockSize);
memset(AccessIpad()+keylength, 0, blockSize-keylength);
for (unsigned int i=0; i<blockSize; i++)
{
AccessOpad()[i] = AccessIpad()[i] ^ 0x5c;
AccessIpad()[i] ^= 0x36;
}
}
void HMAC_Base_Classic::KeyHash()
{
if(!m_innerHashKeyed)
{
HashTransformation * hash = AccessHash();
hash->Update(AccessIpad(), hash->BlockSize());
m_innerHashKeyed = true;
}
}
void HMAC_Base_Fast::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &)
{
AssertValidKeyLength(keylength);
Restart();
HashTransformation &hash = *AccessHash();
unsigned int DigestSize = hash.DigestSize();
if (hash.BlockSize())
throw InvalidArgument("HMAC-Fast: can only be used with a non-block-based hash function");
m_key.resize(DigestSize);
if (keylength <= DigestSize)
memcpy(m_key, userKey, keylength);
else
{
AccessHash()->CalculateDigest(m_key, userKey, keylength);
keylength = hash.DigestSize();
}
assert(keylength <= DigestSize);
}
void HMAC_Base_Fast::KeyHash()
{
if(!m_HashKeyed)
{
HashTransformation &hash = *AccessHash();
hash.Update(m_key, m_key.SizeInBytes());
m_HashKeyed = true;
}
}
void HMAC_Base_Fast::TruncatedFinal(byte *mac, size_t size)
{
ThrowIfInvalidTruncatedSize(size);
HashTransformation &hash = *AccessHash();
hash.TruncatedFinal(mac, size);
m_HashKeyed = false;
}
void HMAC_Base_Compability::TruncatedFinal(byte *mac, size_t size)
{
ThrowIfInvalidTruncatedSize(size);
HashTransformation & hash = *AccessHash();
if (!m_innerHashKeyed)
KeyHash();
hash.Final(AccessInnerHash());
hash.Update(AccessOpad(), hash.DigestSize());
hash.Update(AccessInnerHash(), hash.DigestSize());
hash.TruncatedFinal(mac, size);
m_innerHashKeyed = false;
}
void HMAC_Base_Compability::UncheckedSetKey(const byte *userKey, unsigned int keylength, const NameValuePairs &)
{
AssertValidKeyLength(keylength);
Restart();
HashTransformation * hash = AccessHash();
unsigned int digestsize = hash->DigestSize();
if (!digestsize)
throw InvalidArgument("HMAC: can only be used with a hash function");
m_buf.resize(3*AccessHash()->DigestSize());
if (keylength <= digestsize)
memcpy(AccessIpad(), userKey, keylength);
else
{
AccessHash()->CalculateDigest(AccessIpad(), userKey, keylength);
keylength = hash->DigestSize();
}
assert(keylength <= digestsize);
memset(AccessIpad()+keylength, 0, digestsize-keylength);
for (unsigned int i=0; i<digestsize; i++)
{
AccessOpad()[i] = AccessIpad()[i] ^ 0x5c;
AccessIpad()[i] ^= 0x36;
}
}
void HMAC_Base_Compability::KeyHash()
{
if(!m_innerHashKeyed)
{
HashTransformation * hash = AccessHash();
hash->Update(AccessIpad(), hash->DigestSize());
m_innerHashKeyed = true;
}
}
NAMESPACE_END
#endif
// sha3.h - written and placed in the public domain by Wei Dai
#ifndef CRYPTOPP_SHA3_H
#define CRYPTOPP_SHA3_H
#include "cryptlib.h"
#include "secblock.h"
NAMESPACE_BEGIN(CryptoPP)
/// <a href="http://en.wikipedia.org/wiki/SHA-3">SHA-3</a>
class SHA3 : public HashTransformation
{
public:
SHA3(unsigned int digestSize) : m_digestSize(digestSize) {Restart();}
unsigned int DigestSize() const {return m_digestSize;}
std::string AlgorithmName() const {return "SHA-3-" + IntToString(m_digestSize*8);}
unsigned int OptimalDataAlignment() const {return GetAlignmentOf<word64>();}
void Update(const byte *input, size_t length);
void Restart();
void TruncatedFinal(byte *hash, size_t size);
protected:
inline unsigned int r() const {return 200 - 2 * m_digestSize;}
FixedSizeSecBlock<word64, 25> m_state;
unsigned int m_digestSize, m_counter;
};
template<unsigned int DigestSize>
class SHA3_ : SHA3
{
public:
CRYPTOPP_CONSTANT(DIGESTSIZE = DigestSize)
SHA3_() : SHA3(DIGESTSIZE) {}
static std::string StaticAlgorithmName() {return "SHA-3-" + IntToString(m_digestSize*8);}
};
typedef SHA3_<28> SHA3_224;
typedef SHA3_<32> SHA3_256;
typedef SHA3_<48> SHA3_384;
typedef SHA3_<64> SHA3_512;
/*class SHA3_224 : public SHA3
{
public:
CRYPTOPP_CONSTANT(DIGESTSIZE = 28)
SHA3_224() : SHA3(DIGESTSIZE) {}
static const char * StaticAlgorithmName() {return "SHA-3-224";}
};
class SHA3_256 : public SHA3
{
public:
CRYPTOPP_CONSTANT(DIGESTSIZE = 32)
SHA3_256() : SHA3(DIGESTSIZE) {}
static const char * StaticAlgorithmName() {return "SHA-3-256";}
};
class SHA3_384 : public SHA3
{
public:
CRYPTOPP_CONSTANT(DIGESTSIZE = 48)
SHA3_384() : SHA3(DIGESTSIZE) {}
static const char * StaticAlgorithmName() {return "SHA-3-384";}
};
class SHA3_512 : public SHA3
{
public:
CRYPTOPP_CONSTANT(DIGESTSIZE = 64)
SHA3_512() : SHA3(DIGESTSIZE) {}
static const char * StaticAlgorithmName() {return "SHA-3-512";}
};*/
NAMESPACE_END
#endif