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.cpp - written and placed in the public domain by Wei Dai

#include "pch.h"

#ifndef CRYPTOPP_IMPORTS

#include "hmac.h"

NAMESPACE_BEGIN(CryptoPP)

void HMAC_Base::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::KeyInnerHash()
{
	assert(!m_innerHashKeyed);
	HashTransformation &hash = AccessHash();
	hash.Update(AccessIpad(), hash.BlockSize());
	m_innerHashKeyed = true;
}

void HMAC_Base::Restart()
{
	if (m_innerHashKeyed)
	{
		AccessHash().Restart();
		m_innerHashKeyed = false;
	}
}

void HMAC_Base::Update(const byte *input, size_t length)
{
	if (!m_innerHashKeyed)
		KeyInnerHash();
	AccessHash().Update(input, length);
}

void HMAC_Base::TruncatedFinal(byte *mac, size_t size)
{
	ThrowIfInvalidTruncatedSize(size);

	HashTransformation &hash = AccessHash();

	if (!m_innerHashKeyed)
		KeyInnerHash();
	hash.Final(AccessInnerHash());

	hash.Update(AccessOpad(), hash.BlockSize());
	hash.Update(AccessInnerHash(), hash.DigestSize());
	hash.TruncatedFinal(mac, size);

	m_innerHashKeyed = false;
}

void HMAC_Base_Simple::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-Simple: 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_Simple::KeyHash()
{
	assert(!m_innerHashKeyed);
	HashTransformation &hash = AccessHash();
	hash.Update(m_key, m_key.SizeInBytes());
	m_HashKeyed = true;
}

void HMAC_Base_Simple::Restart()
{
	if (m_HashKeyed)
	{
		AccessHash().Restart();
		m_HashKeyed = false;
	}
}

void HMAC_Base_Simple::Update(const byte *input, size_t length)
{
	if (!m_HashKeyed)
		KeyHash();
	AccessHash().Update(input, length);
}

void HMAC_Base_Simple::TruncatedFinal(byte *mac, size_t size)
{
	ThrowIfInvalidTruncatedSize(size);

	HashTransformation &hash = AccessHash();

	hash.TruncatedFinal(mac, size);

	m_HashKeyed = false;
}

SHA3_X(720);
HMAC_Simple<SHA3_720> Test();

NAMESPACE_END

#endif
// 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 : public VariableKeyLength<16, 0, INT_MAX>, public MessageAuthenticationCode
{
public:
	HMAC_Base() : m_innerHashKeyed(false) {}
	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 OptimalBlockSize() const {return const_cast<HMAC_Base*>(this)->AccessHash().OptimalBlockSize();}
	unsigned int DigestSize() const {return const_cast<HMAC_Base*>(this)->AccessHash().DigestSize();}

protected:
	virtual HashTransformation & AccessHash() =0;
	byte * AccessIpad() {return m_buf;}
	byte * AccessOpad() {return m_buf + AccessHash().BlockSize();}
	byte * AccessInnerHash() {return m_buf + 2*AccessHash().BlockSize();}

private:
	void KeyInnerHash();

	SecByteBlock m_buf;
	bool m_innerHashKeyed;
};

//! <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)
	CRYPTOPP_CONSTANT(BLOCKSIZE=T::BLOCKSIZE)

	HMAC() {}
	HMAC(const byte *key, size_t length=HMAC_Base::DEFAULT_KEYLENGTH)
		{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;}

	T m_hash;
};

//! _
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE HMAC_Base_Simple : public VariableKeyLength<16, 0, INT_MAX>, public MessageAuthenticationCode
{
public:
	HMAC_Base_Simple() : m_HashKeyed(false) {}
	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_Simple*>(this)->AccessHash().DigestSize();}

protected:
	virtual HashTransformation & AccessHash() =0;

private:
	void KeyHash();

	SecByteBlock m_key;
	bool m_HashKeyed;
};

// HMAC-Simple: can only be used with a non-block-based hash function, like Keccak/SHA-3
template <class T>
class HMAC_Simple : public MessageAuthenticationCodeImpl<HMAC_Base_Simple,HMAC_Simple<T>>
{
public:
	HMAC_Simple() {}
	HMAC_Simple(const byte *key, size_t length=HMAC_Base_Simple::DEFAULT_KEYLENGTH)
		{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;}

	T m_hash;
};

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;
};

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";}
};

#define SHA3_X(X) \
class SHA3_##X : public SHA3 \
{ \
public: \
	CRYPTOPP_CONSTANT(DIGESTSIZE = X) \
	SHA3_##X() : SHA3(DIGESTSIZE) {} \
	static const char * StaticAlgorithmName() {return "SHA-3-X";} \
} \

NAMESPACE_END

#endif

Reply via email to