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 &params) =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 &params);

	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 &params);

	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 &params);
	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 &params);

	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

Reply via email to