Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RFC 6979 support. #131

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions eccrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ struct DL_Keys_EC
#endif
};

template <class EC, class H>
template <class EC, class H, bool useDetK = false>
struct ECDSA;

//! ECDSA keys
Expand All @@ -241,8 +241,8 @@ struct DL_Keys_ECDSA
};

//! ECDSA algorithm
template <class EC>
class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA<typename EC::Point>
template <class EC, class H, bool useDetK = false>
class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA<typename EC::Point, H, useDetK>
{
public:
static const char * CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";}
Expand All @@ -265,8 +265,8 @@ class DL_Algorithm_ECNR : public DL_Algorithm_NR<typename EC::Point>
};

//! <a href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a>
template <class EC, class H>
struct ECDSA : public DL_SS<DL_Keys_ECDSA<EC>, DL_Algorithm_ECDSA<EC>, DL_SignatureMessageEncodingMethod_DSA, H>
template <class EC, class H, bool useDetK>
struct ECDSA : public DL_SS<DL_Keys_ECDSA<EC>, DL_Algorithm_ECDSA<EC, H, useDetK>, DL_SignatureMessageEncodingMethod_DSA, H>
{
#ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
virtual ~ECDSA() {}
Expand Down Expand Up @@ -327,8 +327,10 @@ CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<ECP> >;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKeyImpl<DL_GroupParameters_EC<EC2N> >;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECP>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<EC2N>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point, SHA256, false>;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this code? Had to put something here to get the code to compile.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this code?

The short of it: its used to manually instantiate a template for the shared object or DLL. For non-shared object and non-DLL, it does nothing.

Also see the discussion of CRYPTOPP_DLL_TEMPLATE_CLASS at config.h on the Crypto++ wiki.

Also see Explicit Instantiation on MSDN and 7.5 Where's the Template? in the GCC manual.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point, SHA256, true>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point, SHA256, false>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point, SHA256, true>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<ECP>, ECDSA<ECP, SHA256> >;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC2N>, ECDSA<EC2N, SHA256> >;

Expand Down
154 changes: 146 additions & 8 deletions gfpcrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class CRYPTOPP_DLL DL_GroupParameters_GFP_DefaultSafePrime : public DL_GroupPara
};

//! GDSA algorithm
template <class T>
template <class T, class H, bool useDetK>
class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm<T>
{
public:
Expand Down Expand Up @@ -209,12 +209,150 @@ class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm<T>
return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q;
}

bool UseDeterministicK() const
{
return useDetK;
}

// Creates a k-value based on RFC 6979. Uses the message to hash and its size,
// the curve order and its bit length, and a private key. Returns true to
// indicate that the returned k-value is valid.
const bool getDetKVal(const byte* hmsg, const size_t& hmsgSize,
const Integer& cord, const size_t& cordBits,
const Integer& pk, Integer& kVal) const
{
// After doing the initial setup, get the msg hash and work towards the final
// k value, per the spec.
SecByteBlock zeroByte(1);
SecByteBlock oneByte(1);
memset(zeroByte, '\x00', 1);
memset(oneByte, '\x01', 1);

size_t cordBytes = (cordBits + 7) / 8;
SecByteBlock hkey(H::DIGESTSIZE);
memset(hkey, '\x00', H::DIGESTSIZE);
K.SetKey(hkey, hkey.size());
SecByteBlock msgHash(K.DIGESTSIZE);
SecByteBlock V(K.DIGESTSIZE);
SecByteBlock prvKeyBlock = int2octets(pk, (const unsigned int)cordBytes);
memset(V, '\x01', K.DIGESTSIZE);
hashFunct.CalculateDigest(msgHash, hmsg, hmsgSize);

SecByteBlock octetMsg = bits2octets(msgHash, cord, cordBits);
SecByteBlock hmacInput1 = V + zeroByte + prvKeyBlock + octetMsg;
K.CalculateDigest(hkey, hmacInput1, hmacInput1.size());

K.SetKey(hkey, hkey.size());
K.CalculateDigest(V, V, V.size());

SecByteBlock hmacInput2 = V + oneByte + prvKeyBlock + octetMsg;
K.CalculateDigest(hkey, hmacInput2, hmacInput2.size());

K.SetKey(hkey, hkey.size());
K.CalculateDigest(V, V, V.size());

Integer retVal;
for(bool done = false; done != true; )
{
SecByteBlock b2iData;
for(size_t s = 0; s < cordBytes; s += hkey.size())
{
K.CalculateDigest(V, V, V.size());
b2iData += V;
}

// Odds of failure are practically nil but we must play it safe.
Integer b2i = bits2int(b2iData, (const unsigned int)cordBits);
if(b2i >= Integer::One() && b2i < cord)
{
retVal = b2i;
done = true;
}
else
{
SecByteBlock newHMACInput = V + zeroByte;
K.CalculateDigest(hkey, newHMACInput, newHMACInput.size());

K.SetKey(hkey, hkey.size());
K.CalculateDigest(V, V, V.size());
}
}
// Before running the k-val, hash & HMAC functs need to be cleared.
// CalculateDigest() does this every time, though, so we're good.
kVal = retVal;
return true;
}

#ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
virtual ~DL_Algorithm_GDSA() {}
#endif

protected:
// RFC 6979 support function. Takes a set of bits, takes the most significant
// bytes (subject to a given bit limit), and turns them into an integer.
Integer bits2int(const SecByteBlock& bits, const unsigned int& qlen) const
{
Integer retVal(bits, bits.size());
if((retVal.ByteCount() * 8) > qlen)
{
retVal >>= ((retVal.ByteCount() * 8) - qlen);
}

return retVal;
}

// RFC 6979 support function. Takes an integer and converts it into bytes that
// are the same length as an elliptic curve's order.
SecByteBlock int2octets(const Integer& val, const unsigned int& rlenBytes) const
{
SecByteBlock octetBlock(val.ByteCount());
val.Encode(octetBlock, val.ByteCount());
SecByteBlock retVal = octetBlock;

// The least significant bytes are the ones we need to preserve.
if(octetBlock.size() > rlenBytes)
{
SecByteBlock octetBlock1(rlenBytes);
size_t offset = octetBlock.size() - rlenBytes;
memcpy(octetBlock1, octetBlock + offset, rlenBytes);
retVal = octetBlock1;
}
else if(octetBlock.size() < rlenBytes)
{
SecByteBlock octetBlock2(rlenBytes);
memset(octetBlock2, '\x00', rlenBytes);
size_t offset = rlenBytes - octetBlock.size();
memcpy(octetBlock2 + offset, octetBlock, rlenBytes - offset);
retVal = octetBlock2;
}

return retVal;
}

// Turn a stream of bits into a set of bytes with the same length as an elliptic
// curve's order.
SecByteBlock bits2octets(const SecByteBlock& inData, const Integer& curveOrder,
const size_t& curveOrderNumBits) const
{
Integer bintTemp = bits2int(inData, (const unsigned int)curveOrderNumBits);
Integer bint = bintTemp - curveOrder;
return int2octets(bint.IsNegative() ? bintTemp : bint,
curveOrder.ByteCount());
}

// Get() returns const ref
const H& GetHash() const { return const_cast<const H&>(hashFunct); }
const HMAC<H>& GetHMAC() const { return const_cast<const HMAC<H>&>(K); }
// Access() returns non-const ref
H& AccessHash() { return hashFunct; }
HMAC<H>& AccessHMAC() { return K; }
private:
mutable H hashFunct;
mutable HMAC<H> K;
};

CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<Integer>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<Integer, SHA256, false>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<Integer, SHA256, true>;

//! NR algorithm
template <class T>
Expand Down Expand Up @@ -406,10 +544,10 @@ class DL_PrivateKey_GFP_OldFormat : public BASE
};

//! <a href="http://www.weidai.com/scan-mirror/sig.html#DSA-1363">DSA-1363</a>
template <class H>
template <class H, bool useDetK = false>
struct GDSA : public DL_SS<
DL_SignatureKeys_GFP,
DL_Algorithm_GDSA<Integer>,
DL_Algorithm_GDSA<Integer, H, useDetK>,
DL_SignatureMessageEncodingMethod_DSA,
H>
{
Expand Down Expand Up @@ -451,7 +589,7 @@ class CRYPTOPP_DLL DL_GroupParameters_DSA : public DL_GroupParameters_GFP
#endif
};

template <class H>
template <class H, bool useDetK = false>
class DSA2;

//! DSA keys
Expand All @@ -467,13 +605,13 @@ struct DL_Keys_DSA

//! <a href="http://en.wikipedia.org/wiki/Digital_Signature_Algorithm">DSA</a>, as specified in FIPS 186-3
// class named DSA2 instead of DSA for backwards compatibility (DSA was a non-template class)
template <class H>
template <class H, bool useDetK>
class DSA2 : public DL_SS<
DL_Keys_DSA,
DL_Algorithm_GDSA<Integer>,
DL_Algorithm_GDSA<Integer, H, useDetK>,
DL_SignatureMessageEncodingMethod_DSA,
H,
DSA2<H> >
DSA2<H, useDetK> >
{
public:
static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();}
Expand Down
27 changes: 26 additions & 1 deletion pubkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,18 @@ class CRYPTOPP_NO_VTABLE DL_ElgamalLikeSignatureAlgorithm

virtual void Sign(const DL_GroupParameters<T> &params, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0;
virtual bool Verify(const DL_GroupParameters<T> &params, const DL_PublicKey<T> &publicKey, const Integer &e, const Integer &r, const Integer &s) const =0;
virtual bool UseDeterministicK() const
{
// By default, assume k-value won't be deterministic.
return false;
}
virtual const bool getDetKVal(const byte* hmsg, const size_t& hmsgSize,
const Integer& cord, const size_t& cordBits,
const Integer& pk, Integer& kVal) const
{
// By default, assume there is no deterministic k-value.
return false;
}
virtual Integer RecoverPresignature(const DL_GroupParameters<T> &params, const DL_PublicKey<T> &publicKey, const Integer &r, const Integer &s) const
{
CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(publicKey); CRYPTOPP_UNUSED(r); CRYPTOPP_UNUSED(s);
Expand Down Expand Up @@ -1497,7 +1509,20 @@ class CRYPTOPP_NO_VTABLE DL_SignerBase : public DL_SignatureSchemeBase<PK_Signer
// after virtual machine rollback
if (rng.CanIncorporateEntropy())
rng.IncorporateEntropy(representative, representative.size());
Integer k(rng, 1, params.GetSubgroupOrder()-1);

// By default, RFC 6979 won't be applied.
Integer k;
if(alg.UseDeterministicK()) {
alg.getDetKVal(representative,
representative.size(),
params.GetSubgroupOrder(),
params.GetSubgroupOrder().BitCount(),
key.GetPrivateExponent(),
k);
}
else {
k.Randomize(rng, 1, params.GetSubgroupOrder()-1);
}
Integer r, s;
r = params.ConvertElementToInteger(params.ExponentiateBase(k));
alg.Sign(params, key.GetPrivateExponent(), k, e, r, s);
Expand Down
1 change: 1 addition & 0 deletions test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,7 @@ bool Validate(int alg, bool thorough, const char *seedInput)
case 70: result = ValidateHKDF(); break;
case 71: result = ValidateBLAKE2s(); break;
case 72: result = ValidateBLAKE2b(); break;
case 73: result = ValidateRFC6979(); break;
default: return false;
}

Expand Down
1 change: 1 addition & 0 deletions validat1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ bool ValidateAll(bool thorough)
pass=ValidateRabin() && pass;
pass=ValidateRW() && pass;
// pass=ValidateBlumGoldwasser() && pass;
pass=ValidateRFC6979() && pass;
pass=ValidateECP() && pass;
pass=ValidateEC2N() && pass;
pass=ValidateECDSA() && pass;
Expand Down
Loading