From 7e427805174b9fc672caf838f9e456a09be32043 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Sun, 11 Dec 2016 01:02:00 -0500 Subject: [PATCH] Add Deterministic DSA and ECDSA Signatures (Issue 121) Based on Douglas Roark PR 131 --- TestVectors/all.txt | 2 +- TestVectors/dsa_rfc6979.txt | 80 +++++++-------- bench2.cpp | 9 ++ cryptest.vcxproj | 1 + cryptest.vcxproj.filters | 3 + cryptlib.h | 1 + datatest.cpp | 4 +- eccrypto.h | 31 +++++- gfpcrypt.h | 193 +++++++++++++++++++++++++++++++++++- pubkey.h | 41 +++++++- regtest.cpp | 5 + 11 files changed, 320 insertions(+), 50 deletions(-) diff --git a/TestVectors/all.txt b/TestVectors/all.txt index cd4d5c70..58d1fd44 100644 --- a/TestVectors/all.txt +++ b/TestVectors/all.txt @@ -9,7 +9,7 @@ Test: TestVectors/whrlpool.txt Test: TestVectors/dlies.txt Test: TestVectors/dsa.txt Test: TestVectors/dsa_1363.txt -#Test: TestVectors/dsa_rfc6979.txt +Test: TestVectors/dsa_rfc6979.txt #Test: TestVectors/ecdsa_rfc6979.txt Test: TestVectors/esign.txt Test: TestVectors/hmac.txt diff --git a/TestVectors/dsa_rfc6979.txt b/TestVectors/dsa_rfc6979.txt index 505ba42e..ed9ac8ac 100644 --- a/TestVectors/dsa_rfc6979.txt +++ b/TestVectors/dsa_rfc6979.txt @@ -1,5 +1,5 @@ AlgorithmType: Signature -Name: DSA/SHA-1 +Name: DSA-RFC6979/SHA-1 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-1 KeyFormat: Component @@ -25,7 +25,7 @@ Signature: 42AB2052FD43E123F0607F115052A67DCD9C5C77183916B0230D45B9931491D4C6B0B Test: Verify AlgorithmType: Signature -Name: DSA/SHA-1 +Name: DSA-RFC6979/SHA-1 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-1 KeyFormat: Component @@ -46,13 +46,13 @@ PrivateExponent: 411602CB19A6CCC34494D79D98EF1E7ED5AF25F7 Test: KeyPairValidAndConsistent Message: 73616D706C65 Signature: 2E1A0C2562B2912CAAF89186FB0F42001585DA5529EFB6B0AFF2D7A68EB70CA313022253B9A88DF5 -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 42AB2052FD43E123F0607F115052A67DCD9C5C77183916B0230D45B9931491D4C6B0BD2FB4AAF088 -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-224 +Name: DSA-RFC6979/SHA-224 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-224 KeyFormat: Component @@ -77,7 +77,7 @@ Signature: 6868E9964E36C1689F6037F91F28D5F2C30610F249CEC3ACDC83018C5BD2674ECAAD3 Test: Verify AlgorithmType: Signature -Name: DSA/SHA-224 +Name: DSA-RFC6979/SHA-224 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-224 KeyFormat: Component @@ -97,13 +97,13 @@ PublicElement: 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ PrivateExponent: 411602CB19A6CCC34494D79D98EF1E7ED5AF25F7 Message: 73616D706C65 Signature: 4BC3B686AEA70145856814A6F1BB53346F02101E410697B92295D994D21EDD2F4ADA85566F6F94C1 -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 6868E9964E36C1689F6037F91F28D5F2C30610F249CEC3ACDC83018C5BD2674ECAAD35B8CD22940F -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-256 +Name: DSA-RFC6979/SHA-256 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-256 KeyFormat: Component @@ -128,7 +128,7 @@ Signature: 22518C127299B0F6FDC9872B282B9E70D07908126837EC18F150D55DE95B5E29BE7AF Test: Verify AlgorithmType: Signature -Name: DSA/SHA-256 +Name: DSA-RFC6979/SHA-256 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-256 KeyFormat: Component @@ -148,13 +148,13 @@ PublicElement: 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ PrivateExponent: 411602CB19A6CCC34494D79D98EF1E7ED5AF25F7 Message: 73616D706C65 Signature: 81F2F5850BE5BC123C43F71A3033E9384611C5454CDD914B65EB6C66A8AAAD27299BEE6B035F5E89 -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 22518C127299B0F6FDC9872B282B9E70D07908126837EC18F150D55DE95B5E29BE7AF5D01E4FE160 -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-384 +Name: DSA-RFC6979/SHA-384 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-384 KeyFormat: Component @@ -179,7 +179,7 @@ Signature: 854CF929B58D73C3CBFDC421E8D5430CD6DB5E6691D0E0F53E22F898D158380676A87 Test: Verify AlgorithmType: Signature -Name: DSA/SHA-384 +Name: DSA-RFC6979/SHA-384 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-384 KeyFormat: Component @@ -199,13 +199,13 @@ PublicElement: 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ PrivateExponent: 411602CB19A6CCC34494D79D98EF1E7ED5AF25F7 Message: 73616D706C65 Signature: 07F2108557EE0E3921BC1774F1CA9B410B4CE65A54DF70456C86FAC10FAB47C1949AB83F2C6F7595 -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 854CF929B58D73C3CBFDC421E8D5430CD6DB5E6691D0E0F53E22F898D158380676A871A157CDA622 -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-512 +Name: DSA-RFC6979/SHA-512 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-512 KeyFormat: Component @@ -230,7 +230,7 @@ Signature: 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A07C670C7AD72B6C050C109E1790008 Test: Verify AlgorithmType: Signature -Name: DSA/SHA-512 +Name: DSA-RFC6979/SHA-512 Source: RFC 6979 Comment: Section A.2.1. DSA, 1024 Bits, SHA-512 KeyFormat: Component @@ -250,13 +250,13 @@ PublicElement: 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653\ PrivateExponent: 411602CB19A6CCC34494D79D98EF1E7ED5AF25F7 Message: 73616D706C65 Signature: 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A07C670C7AD72B6C050C109E1790008097125433E8 -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-1 +Name: DSA-RFC6979/SHA-1 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-1 KeyFormat: Component @@ -296,7 +296,7 @@ Signature: C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0\ Test: Verify AlgorithmType: Signature -Name: DSA/SHA-1 +Name: DSA-RFC6979/SHA-1 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-1 KeyFormat: Component @@ -330,14 +330,14 @@ Test: KeyPairValidAndConsistent Message: 73616D706C65 Signature: 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A\ D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0\ 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-224 +Name: DSA-RFC6979/SHA-224 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-224 KeyFormat: Component @@ -377,7 +377,7 @@ Signature: 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3\ Test: Verify AlgorithmType: Signature -Name: DSA/SHA-224 +Name: DSA-RFC6979/SHA-224 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-224 KeyFormat: Component @@ -411,14 +411,14 @@ Test: KeyPairValidAndConsistent Message: 73616D706C65 Signature: DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C\ A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3\ E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806 -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-256 +Name: DSA-RFC6979/SHA-256 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-256 KeyFormat: Component @@ -458,7 +458,7 @@ Signature: 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0\ Test: Verify AlgorithmType: Signature -Name: DSA/SHA-256 +Name: DSA-RFC6979/SHA-256 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-256 KeyFormat: Component @@ -492,14 +492,14 @@ Test: KeyPairValidAndConsistent Message: 73616D706C65 Signature: EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809\ 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53 -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0\ 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-384 +Name: DSA-RFC6979/SHA-384 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-384 KeyFormat: Component @@ -539,7 +539,7 @@ Signature: 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE\ Test: Verify AlgorithmType: Signature -Name: DSA/SHA-384 +Name: DSA-RFC6979/SHA-384 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-384 KeyFormat: Component @@ -573,14 +573,14 @@ Test: KeyPairValidAndConsistent Message: 73616D706C65 Signature: B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B\ 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE\ 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961 -#Test: DeterministicSign +Test: DeterministicSign AlgorithmType: Signature -Name: DSA/SHA-512 +Name: DSA-RFC6979/SHA-512 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-512 KeyFormat: Component @@ -620,7 +620,7 @@ Signature: 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307\ Test: Verify AlgorithmType: Signature -Name: DSA/SHA-512 +Name: DSA-RFC6979/SHA-512 Source: RFC 6979 Comment: Section A.2.2. DSA, 2048 Bits, SHA-512 KeyFormat: Component @@ -654,9 +654,9 @@ Test: KeyPairValidAndConsistent Message: 73616D706C65 Signature: 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E\ D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351 -#Test: DeterministicSign +Test: DeterministicSign Message: 74657374 Signature: 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307\ C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1 -#Test: DeterministicSign +Test: DeterministicSign diff --git a/bench2.cpp b/bench2.cpp index 329887cf..ab9c21ac 100644 --- a/bench2.cpp +++ b/bench2.cpp @@ -293,6 +293,7 @@ void BenchmarkAll2(double t, double hertz) BenchMarkSignature >(CRYPTOPP_DATA_DIR "TestData/luc1024.dat", "LUC 1024", t); BenchMarkSignature >(CRYPTOPP_DATA_DIR "TestData/nr1024.dat", "NR 1024", t); BenchMarkSignature(CRYPTOPP_DATA_DIR "TestData/dsa1024.dat", "DSA 1024", t); + // BenchMarkSignature(CRYPTOPP_DATA_DIR "TestData/dsa1024.dat", "DSA-RFC6979 1024", t); BenchMarkSignature >(CRYPTOPP_DATA_DIR "TestData/lucs512.dat", "LUC-HMP 512", t); BenchMarkSignature >(CRYPTOPP_DATA_DIR "TestData/esig1023.dat", "ESIGN 1023", t); BenchMarkSignature >(CRYPTOPP_DATA_DIR "TestData/esig1536.dat", "ESIGN 1536", t); @@ -333,6 +334,8 @@ void BenchmarkAll2(double t, double hertz) ECIES::Encryptor cpub(cpriv); ECDSA::Signer spriv(cpriv); ECDSA::Verifier spub(spriv); + ECDSA_RFC6979::Signer spriv2(cpriv); + ECDSA_RFC6979::Verifier spub2(spriv); ECDH::Domain ecdhc(ASN1::secp256k1()); ECMQV::Domain ecmqvc(ASN1::secp256k1()); @@ -340,6 +343,8 @@ void BenchmarkAll2(double t, double hertz) BenchMarkDecryption("ECIES over GF(p) 256", cpriv, cpub, t); BenchMarkSigning("ECDSA over GF(p) 256", spriv, t); BenchMarkVerification("ECDSA over GF(p) 256", spriv, spub, t); + BenchMarkSigning("ECDSA-RFC6979 over GF(p) 256", spriv2, t); + BenchMarkVerification("ECDSA-RFC6979 over GF(p) 256", spriv2, spub2, t); BenchMarkKeyGen("ECDHC over GF(p) 256", ecdhc, t); BenchMarkAgreement("ECDHC over GF(p) 256", ecdhc, t); BenchMarkKeyGen("ECMQVC over GF(p) 256", ecmqvc, t); @@ -352,6 +357,8 @@ void BenchmarkAll2(double t, double hertz) ECIES::Encryptor cpub(cpriv); ECDSA::Signer spriv(cpriv); ECDSA::Verifier spub(spriv); + ECDSA_RFC6979::Signer spriv2(cpriv); + ECDSA_RFC6979::Verifier spub2(spriv); ECDH::Domain ecdhc(ASN1::sect233r1()); ECMQV::Domain ecmqvc(ASN1::sect233r1()); @@ -359,6 +366,8 @@ void BenchmarkAll2(double t, double hertz) BenchMarkDecryption("ECIES over GF(2^n) 233", cpriv, cpub, t); BenchMarkSigning("ECDSA over GF(2^n) 233", spriv, t); BenchMarkVerification("ECDSA over GF(2^n) 233", spriv, spub, t); + BenchMarkSigning("ECDSA-RFC6979 over GF(2^n) 233", spriv2, t); + BenchMarkVerification("ECDSA-RFC6979 over GF(2^n) 233", spriv2, spub2, t); BenchMarkKeyGen("ECDHC over GF(2^n) 233", ecdhc, t); BenchMarkAgreement("ECDHC over GF(2^n) 233", ecdhc, t); BenchMarkKeyGen("ECMQVC over GF(2^n) 233", ecmqvc, t); diff --git a/cryptest.vcxproj b/cryptest.vcxproj index 403739a4..b056cb8c 100644 --- a/cryptest.vcxproj +++ b/cryptest.vcxproj @@ -228,6 +228,7 @@ + diff --git a/cryptest.vcxproj.filters b/cryptest.vcxproj.filters index 0f1918ce..393d5178 100644 --- a/cryptest.vcxproj.filters +++ b/cryptest.vcxproj.filters @@ -54,6 +54,9 @@ TestVectors + + TestVectors + TestVectors diff --git a/cryptlib.h b/cryptlib.h index a087711c..b3330544 100644 --- a/cryptlib.h +++ b/cryptlib.h @@ -2427,6 +2427,7 @@ public: //! \class PK_SignatureScheme //! \brief Interface for public-key signers and verifiers //! \details This class provides an interface common to signers and verifiers for querying scheme properties +//! \sa DL_SignatureSchemeBase, TF_SignatureSchemeBase, DL_SignerBase, TF_SignerBase class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE PK_SignatureScheme { public: diff --git a/datatest.cpp b/datatest.cpp index 7a2e64c9..d4f5c0ab 100644 --- a/datatest.cpp +++ b/datatest.cpp @@ -291,10 +291,12 @@ void TestSignatureScheme(TestData &v) // additional determinsitic signatures are added, then the test harness will // likely need to be extended. string signature; - SignerFilter f(GlobalRNG(), *signer, new HexEncoder(new StringSink(signature))); + SignerFilter f(GlobalRNG(), *signer, new StringSink(signature)); StringSource ss(GetDecodedDatum(v, "Message"), true, new Redirector(f)); + if (GetDecodedDatum(v, "Signature") != signature) SignalTestFailure(); + return; } else if (test == "RandomSign") diff --git a/eccrypto.h b/eccrypto.h index c5049f13..ebfda2a8 100644 --- a/eccrypto.h +++ b/eccrypto.h @@ -1,4 +1,5 @@ // eccrypto.h - written and placed in the public domain by Wei Dai +// deterministic signatures added by by Douglas Roark //! \file eccrypto.h //! \brief Classes and functions for Elliptic Curves over prime and binary fields @@ -343,6 +344,16 @@ public: CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA";} }; +//! \class DL_Algorithm_ECDSA_RFC6979 +//! \brief Elliptic Curve DSA (ECDSA) signature algorithm +//! \tparam EC elliptic curve field +template +class DL_Algorithm_ECDSA_RFC6979 : public DL_Algorithm_DSA_RFC6979 +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECDSA-RFC6979";} +}; + //! \class DL_Algorithm_ECNR //! \brief Elliptic Curve NR (ECNR) signature algorithm //! \tparam EC elliptic curve field @@ -363,6 +374,23 @@ struct ECDSA : public DL_SS, DL_Algorithm_ECDSA, DL_Signat { }; +//! \class ECDSA_RFC6979 +//! \brief Elliptic Curve DSA (ECDSA) deterministic signature scheme +//! \tparam EC elliptic curve field +//! \tparam H HashTransformation derived class +//! \sa Deterministic Usage of the +//! Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +template +struct ECDSA_RFC6979 : public DL_SS< + DL_Keys_ECDSA, + DL_Algorithm_ECDSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + ECDSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("ECDSA-RFC6979/") + H::StaticAlgorithmName();} +}; + //! \class ECNR //! \brief Elliptic Curve NR (ECNR) signature scheme //! \tparam EC elliptic curve field @@ -415,7 +443,8 @@ struct ECIES DL_EncryptionAlgorithm_Xor, DHAES_MODE, LABEL_OCTETS>, ECIES > { - static std::string CRYPTOPP_API StaticAlgorithmName() {return "ECIES";} // TODO: fix this after name is standardized + // TODO: fix this after name is standardized + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "ECIES";} }; NAMESPACE_END diff --git a/gfpcrypt.h b/gfpcrypt.h index 2cef5e9b..681bc1d2 100644 --- a/gfpcrypt.h +++ b/gfpcrypt.h @@ -1,6 +1,7 @@ // gfpcrypt.h - written and placed in the public domain by Wei Dai +// deterministic signatures added by by Douglas Roark -//! \file eccrypto.h +//! \file gfpcrypt.h //! \brief Classes and functions for schemes based on Discrete Logs (DL) over GF(p) #ifndef CRYPTOPP_GFPCRYPT_H @@ -224,7 +225,179 @@ public: } }; +//! \class DL_Algorithm_DSA_RFC6979 +//! \brief GDSA algorithm +//! \tparam T FieldElement type or class +//! \tparam H HashTransformation derived class +//! \sa Deterministic Usage of the +//! Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) +template +class DL_Algorithm_DSA_RFC6979 : public DL_Algorithm_GDSA, public DeterministicSignatureAlgorithm +{ +public: + CRYPTOPP_STATIC_CONSTEXPR const char* CRYPTOPP_API StaticAlgorithmName() {return "DSA-RFC6979";} + + virtual ~DL_Algorithm_DSA_RFC6979() {} + + bool IsProbabilistic() const + {return false;} + bool IsDeterministic() const + {return true;} + + // Deterministic K + Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const + { + static const byte zero = 0, one = 1; + const size_t qlen = q.BitCount(); + const size_t rlen = BitsToBytes(qlen); + + // Step (a) - formatted E(m) + SecByteBlock BH(e.MinEncodedSize()); + e.Encode(BH, BH.size()); + BH = bits2octets(BH, q); + + // Step (a) - private key to byte array + SecByteBlock BX(STDMAX(rlen, x.MinEncodedSize())); + x.Encode(BX, BX.size()); + + // Step (b) + SecByteBlock V(H::DIGESTSIZE); + std::fill(V.begin(), V.begin()+H::DIGESTSIZE, one); + + // Step (c) + SecByteBlock K(H::DIGESTSIZE); + std::fill(K.begin(), K.begin()+H::DIGESTSIZE, zero); + + // Step (d) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.Update(&zero, 1); + m_hmac.Update(BX, BX.size()); + m_hmac.Update(BH, BH.size()); + m_hmac.TruncatedFinal(K, K.size()); + + // Step (e) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + // Step (f) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.Update(&one, 1); + m_hmac.Update(BX, BX.size()); + m_hmac.Update(BH, BH.size()); + m_hmac.TruncatedFinal(K, K.size()); + + // Step (g) + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + Integer k; + SecByteBlock temp(rlen); + for (;;) + { + // We want qlen bits, but we support only hash functions with an output length + // multiple of 8; hence, we will gather rlen bits, i.e., rolen octets. + size_t toff = 0; + while (toff < rlen) + { + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + + size_t cc = STDMIN(V.size(), temp.size() - toff); + memcpy_s(temp+toff, temp.size() - toff, V, cc); + toff += cc; + } + + k = bits2int(temp, qlen); + if (k > 0 && k < q) + break; + + // k is not in the proper range; update K and V, and loop. + m_hmac.Update(V, V.size()); + m_hmac.Update(&zero, 1); + m_hmac.TruncatedFinal(K, K.size()); + + m_hmac.SetKey(K, K.size()); + m_hmac.Update(V, V.size()); + m_hmac.TruncatedFinal(V, V.size()); + } + + return k; + } + +protected: + +#if 0 + // Determine bits without converting to an Integer + inline unsigned int BitCount(const byte* buffer, size_t size) const + { + unsigned int idx = 0; + while (idx < size && buffer[idx] == 0) { idx++; } + return (size-idx)*8 - (8-BitPrecision(buffer[idx])); + } +#endif + + Integer bits2int(const SecByteBlock& bits, size_t qlen) const + { + Integer ret(bits, bits.size()); + size_t blen = bits.size()*8; + + if (blen > qlen) + ret >>= blen - qlen; + + return ret; + } + + // 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, size_t rlen) const + { + SecByteBlock block(val.MinEncodedSize()); + val.Encode(block, val.MinEncodedSize()); + + if (block.size() == rlen) + return block; + + // The least significant bytes are the ones we need to preserve. + SecByteBlock t(rlen); + if (block.size() > rlen) + { + size_t offset = block.size() - rlen; + memcpy(t, block + offset, rlen); + } + else // block.size() < rlen + { + size_t offset = rlen - block.size(); + memset(t, '\x00', offset); + memcpy(t + offset, block, rlen - offset); + } + + return t; + } + + // Turn a stream of bits into a set of bytes with the same length as an elliptic + // curve's order. + SecByteBlock bits2octets(const SecByteBlock& in, const Integer& q) const + { + Integer b2 = bits2int(in, in.size()*8); + Integer b1 = b2 - q; + return int2octets(b1.IsNegative() ? b2 : b1, q.ByteCount()); + } + +private: + mutable H m_hash; + mutable HMAC m_hmac; +}; + CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_GDSA; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; +CRYPTOPP_DLL_TEMPLATE_CLASS DL_Algorithm_DSA_RFC6979; //! \class DL_Algorithm_NR //! \brief NR algorithm @@ -541,10 +714,22 @@ class DSA2 : public DL_SS< { public: static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();} +}; - //#ifdef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY - //enum {MIN_PRIME_LENGTH = 1024, MAX_PRIME_LENGTH = 3072, PRIME_LENGTH_MULTIPLE = 1024}; - //#endif +//! \class DSA_RFC6979 +//! \brief DSA deterministic signature scheme +//! \tparam H HashTransformation derived class +//! \sa DSA-1363 +//! \since Crypto++ 1.0 for DSA, Crypto++ 5.6.2 for DSA2 +template +struct DSA_RFC6979 : public DL_SS< + DL_SignatureKeys_GFP, + DL_Algorithm_DSA_RFC6979, + DL_SignatureMessageEncodingMethod_DSA, + H, + DSA_RFC6979 > +{ + static std::string CRYPTOPP_API StaticAlgorithmName() {return std::string("DSA-RFC6979/") + H::StaticAlgorithmName();} }; //! DSA with SHA-1, typedef'd for backwards compatibility diff --git a/pubkey.h b/pubkey.h index 7db0e816..7587a8ab 100644 --- a/pubkey.h +++ b/pubkey.h @@ -329,6 +329,12 @@ public: virtual size_t MaxRecoverableLength(size_t representativeBitLength, size_t hashIdentifierLength, size_t digestLength) const {CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(representativeBitLength); CRYPTOPP_UNUSED(hashIdentifierLength); CRYPTOPP_UNUSED(digestLength); return 0;} + //! \brief Determines whether an encoding method requires a random number generator + //! \return true if the encoding method requires a RandomNumberGenerator() + //! \details if IsProbabilistic() returns false, then NullRNG() can be passed to functions that take + //! RandomNumberGenerator(). + //! \sa Bellare and RogawayPSS: + //! Provably Secure Encoding Method for Digital Signatures bool IsProbabilistic() const {return true;} bool AllowNonrecoverablePart() const @@ -1265,6 +1271,19 @@ public: {return params.GetSubgroupOrder().ByteCount();} virtual size_t SLen(const DL_GroupParameters ¶ms) const {return params.GetSubgroupOrder().ByteCount();} + // RFC 6979, present in DL signers + virtual bool IsDeterministic() const + {return false;} +}; + +//! \brief Interface for deterministic signers +//! \details RFC 6979 signers which generate k based on the encoded message and private key +class CRYPTOPP_NO_VTABLE DeterministicSignatureAlgorithm +{ +public: + virtual ~DeterministicSignatureAlgorithm() {} + + virtual Integer GenerateRandom(const Integer &x, const Integer &q, const Integer &e) const =0; }; //! \brief Interface for DL key agreement algorithms @@ -1376,6 +1395,9 @@ protected: size_t MessageRepresentativeLength() const {return BitsToBytes(MessageRepresentativeBitLength());} size_t MessageRepresentativeBitLength() const {return this->GetAbstractGroupParameters().GetSubgroupOrder().BitCount();} + // true if the scheme conforms to RFC 6979 + virtual bool IsDeterministic() const {return false;} + virtual const DL_ElgamalLikeSignatureAlgorithm & GetSignatureAlgorithm() const =0; virtual const PK_SignatureMessageEncodingMethod & GetMessageEncodingInterface() const =0; virtual HashIdentifier GetHashIdentifier() const =0; @@ -1433,11 +1455,24 @@ public: ma.m_empty = true; Integer e(representative, representative.size()); - // hash message digest into random number k to prevent reusing the same k on a different messages - // after virtual machine rollback + // hash message digest into random number k to prevent reusing the same k on + // different messages after virtual machine rollback if (rng.CanIncorporateEntropy()) rng.IncorporateEntropy(representative, representative.size()); - Integer k(rng, 1, params.GetSubgroupOrder()-1); + + Integer k; + if (alg.IsDeterministic()) + { + const Integer& q = params.GetSubgroupOrder(); + const Integer& x = key.GetPrivateExponent(); + const DeterministicSignatureAlgorithm& det = dynamic_cast(alg); + k = det.GenerateRandom(x, q, e); + } + 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); diff --git a/regtest.cpp b/regtest.cpp index 0216b149..d10db6c1 100644 --- a/regtest.cpp +++ b/regtest.cpp @@ -126,6 +126,11 @@ void RegisterFactories() RegisterSignatureSchemeDefaultFactories >(); RegisterSignatureSchemeDefaultFactories >(); RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); + RegisterSignatureSchemeDefaultFactories >(); RegisterSignatureSchemeDefaultFactories >("NR(1363)/EMSA1(SHA-1)"); RegisterSignatureSchemeDefaultFactories >("DSA-1363/EMSA1(SHA-1)"); RegisterSignatureSchemeDefaultFactories >("RSA/PKCS1-1.5(MD2)");