Add RFC 6979 support.

Adds RFC 6979 support for both DSA and ECDSA.
pull/131/head
Doug 2016-02-03 16:23:42 -08:00
parent 4d7cb70ea8
commit 5cc29e0e05
7 changed files with 1591 additions and 16 deletions

View File

@ -225,7 +225,7 @@ struct DL_Keys_EC
#endif #endif
}; };
template <class EC, class H> template <class EC, class H, bool useDetK = false>
struct ECDSA; struct ECDSA;
//! ECDSA keys //! ECDSA keys
@ -241,8 +241,8 @@ struct DL_Keys_ECDSA
}; };
//! ECDSA algorithm //! ECDSA algorithm
template <class EC> template <class EC, class H, bool useDetK = false>
class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA<typename EC::Point> class DL_Algorithm_ECDSA : public DL_Algorithm_GDSA<typename EC::Point, H, useDetK>
{ {
public: public:
static const char * CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";} static const char * CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";}
@ -265,8 +265,8 @@ public:
}; };
//! <a href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a> //! <a href="http://www.weidai.com/scan-mirror/sig.html#ECDSA">ECDSA</a>
template <class EC, class H> template <class EC, class H, bool useDetK>
struct ECDSA : public DL_SS<DL_Keys_ECDSA<EC>, DL_Algorithm_ECDSA<EC>, DL_SignatureMessageEncodingMethod_DSA, H> 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 #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
virtual ~ECDSA() {} virtual ~ECDSA() {}
@ -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_PrivateKeyImpl<DL_GroupParameters_EC<EC2N> >;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECP>; CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<ECP>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<EC2N>; CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_EC<EC2N>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point>; CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<ECP::Point, SHA256, false>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA<EC2N::Point>; 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<ECP>, ECDSA<ECP, SHA256> >;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC2N>, ECDSA<EC2N, SHA256> >; CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_EC<EC2N>, ECDSA<EC2N, SHA256> >;

View File

@ -181,7 +181,7 @@ protected:
}; };
//! GDSA algorithm //! GDSA algorithm
template <class T> template <class T, class H, bool useDetK>
class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm<T> class DL_Algorithm_GDSA : public DL_ElgamalLikeSignatureAlgorithm<T>
{ {
public: public:
@ -209,12 +209,150 @@ public:
return r == params.ConvertElementToInteger(publicKey.CascadeExponentiateBaseAndPublicElement(u1, u2)) % q; 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 #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
virtual ~DL_Algorithm_GDSA() {} virtual ~DL_Algorithm_GDSA() {}
#endif #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 //! NR algorithm
template <class T> template <class T>
@ -406,10 +544,10 @@ public:
}; };
//! <a href="http://www.weidai.com/scan-mirror/sig.html#DSA-1363">DSA-1363</a> //! <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< struct GDSA : public DL_SS<
DL_SignatureKeys_GFP, DL_SignatureKeys_GFP,
DL_Algorithm_GDSA<Integer>, DL_Algorithm_GDSA<Integer, H, useDetK>,
DL_SignatureMessageEncodingMethod_DSA, DL_SignatureMessageEncodingMethod_DSA,
H> H>
{ {
@ -451,7 +589,7 @@ public:
#endif #endif
}; };
template <class H> template <class H, bool useDetK = false>
class DSA2; class DSA2;
//! DSA keys //! DSA keys
@ -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 //! <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) // 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< class DSA2 : public DL_SS<
DL_Keys_DSA, DL_Keys_DSA,
DL_Algorithm_GDSA<Integer>, DL_Algorithm_GDSA<Integer, H, useDetK>,
DL_SignatureMessageEncodingMethod_DSA, DL_SignatureMessageEncodingMethod_DSA,
H, H,
DSA2<H> > DSA2<H, useDetK> >
{ {
public: public:
static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();} static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();}

View File

@ -1304,6 +1304,18 @@ public:
virtual void Sign(const DL_GroupParameters<T> &params, const Integer &privateKey, const Integer &k, const Integer &e, Integer &r, Integer &s) const =0; 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 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 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); CRYPTOPP_UNUSED(params); CRYPTOPP_UNUSED(publicKey); CRYPTOPP_UNUSED(r); CRYPTOPP_UNUSED(s);
@ -1497,7 +1509,20 @@ public:
// after virtual machine rollback // after virtual machine rollback
if (rng.CanIncorporateEntropy()) if (rng.CanIncorporateEntropy())
rng.IncorporateEntropy(representative, representative.size()); 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; Integer r, s;
r = params.ConvertElementToInteger(params.ExponentiateBase(k)); r = params.ConvertElementToInteger(params.ExponentiateBase(k));
alg.Sign(params, key.GetPrivateExponent(), k, e, r, s); alg.Sign(params, key.GetPrivateExponent(), k, e, r, s);

View File

@ -955,6 +955,7 @@ bool Validate(int alg, bool thorough, const char *seedInput)
case 70: result = ValidateHKDF(); break; case 70: result = ValidateHKDF(); break;
case 71: result = ValidateBLAKE2s(); break; case 71: result = ValidateBLAKE2s(); break;
case 72: result = ValidateBLAKE2b(); break; case 72: result = ValidateBLAKE2b(); break;
case 73: result = ValidateRFC6979(); break;
default: return false; default: return false;
} }

View File

@ -161,6 +161,7 @@ bool ValidateAll(bool thorough)
pass=ValidateRabin() && pass; pass=ValidateRabin() && pass;
pass=ValidateRW() && pass; pass=ValidateRW() && pass;
// pass=ValidateBlumGoldwasser() && pass; // pass=ValidateBlumGoldwasser() && pass;
pass=ValidateRFC6979() && pass;
pass=ValidateECP() && pass; pass=ValidateECP() && pass;
pass=ValidateEC2N() && pass; pass=ValidateEC2N() && pass;
pass=ValidateECDSA() && pass; pass=ValidateECDSA() && pass;

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,7 @@ bool ValidateXTR_DH();
bool ValidateRabin(); bool ValidateRabin();
bool ValidateRW(); bool ValidateRW();
//bool ValidateBlumGoldwasser(); //bool ValidateBlumGoldwasser();
bool ValidateRFC6979();
bool ValidateECP(); bool ValidateECP();
bool ValidateEC2N(); bool ValidateEC2N();
bool ValidateECDSA(); bool ValidateECDSA();