123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408 |
- // fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal
- // Shamelessly based upon Wei Dai's MQV source files
- #ifndef CRYPTOPP_FHMQV_H
- #define CRYPTOPP_FHMQV_H
- /// \file fhmqv.h
- /// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p)
- /// \since Crypto++ 5.6.4
- #include "gfpcrypt.h"
- #include "algebra.h"
- #include "sha.h"
- NAMESPACE_BEGIN(CryptoPP)
- /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
- /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
- /// <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
- /// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
- /// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
- /// \since Crypto++ 5.6.4
- template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
- class FHMQV_Domain : public AuthenticatedKeyAgreementDomain
- {
- public:
- typedef GROUP_PARAMETERS GroupParameters;
- typedef typename GroupParameters::Element Element;
- typedef FHMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
- virtual ~FHMQV_Domain() {}
- /// \brief Construct a FHMQV domain
- /// \param clientRole flag indicating initiator or recipient
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- FHMQV_Domain(bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer) {}
- /// \brief Construct a FHMQV domain
- /// \param params group parameters and options
- /// \param clientRole flag indicating initiator or recipient
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- FHMQV_Domain(const GroupParameters ¶ms, bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
- /// \brief Construct a FHMQV domain
- /// \param bt BufferedTransformation with group parameters and options
- /// \param clientRole flag indicating initiator or recipient
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer)
- {m_groupParameters.BERDecode(bt);}
- /// \brief Construct a FHMQV domain
- /// \tparam T1 template parameter used as a constructor parameter
- /// \param v1 first parameter
- /// \param clientRole flag indicating initiator or recipient
- /// \details v1 is passed directly to the GROUP_PARAMETERS object.
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- template <class T1>
- FHMQV_Domain(T1 v1, bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer)
- {m_groupParameters.Initialize(v1);}
- /// \brief Construct a FHMQV domain
- /// \tparam T1 template parameter used as a constructor parameter
- /// \tparam T2 template parameter used as a constructor parameter
- /// \param v1 first parameter
- /// \param v2 second parameter
- /// \param clientRole flag indicating initiator or recipient
- /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- template <class T1, class T2>
- FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer)
- {m_groupParameters.Initialize(v1, v2);}
- /// \brief Construct a FHMQV domain
- /// \tparam T1 template parameter used as a constructor parameter
- /// \tparam T2 template parameter used as a constructor parameter
- /// \tparam T3 template parameter used as a constructor parameter
- /// \param v1 first parameter
- /// \param v2 second parameter
- /// \param v3 third parameter
- /// \param clientRole flag indicating initiator or recipient
- /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- template <class T1, class T2, class T3>
- FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer)
- {m_groupParameters.Initialize(v1, v2, v3);}
- /// \brief Construct a FHMQV domain
- /// \tparam T1 template parameter used as a constructor parameter
- /// \tparam T2 template parameter used as a constructor parameter
- /// \tparam T3 template parameter used as a constructor parameter
- /// \tparam T4 template parameter used as a constructor parameter
- /// \param v1 first parameter
- /// \param v2 second parameter
- /// \param v3 third parameter
- /// \param v4 third parameter
- /// \param clientRole flag indicating initiator or recipient
- /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
- /// \details <tt>clientRole = true</tt> indicates initiator, and
- /// <tt>clientRole = false</tt> indicates recipient or server.
- template <class T1, class T2, class T3, class T4>
- FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
- : m_role(clientRole ? RoleClient : RoleServer)
- {m_groupParameters.Initialize(v1, v2, v3, v4);}
- public:
- /// \brief Retrieves the group parameters for this domain
- /// \return the group parameters for this domain as a const reference
- const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
- /// \brief Retrieves the group parameters for this domain
- /// \return the group parameters for this domain as a non-const reference
- GroupParameters & AccessGroupParameters() {return m_groupParameters;}
- /// \brief Retrieves the crypto parameters for this domain
- /// \return the crypto parameters for this domain as a non-const reference
- CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
- /// \brief Provides the size of the agreed value
- /// \return size of agreed value produced in this domain
- /// \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>,
- /// which means the element is encoded in a non-reversible format. A
- /// non-reversible format means its a raw byte array, and it lacks presentation
- /// format like an ASN.1 BIT_STRING or OCTET_STRING.
- unsigned int AgreedValueLength() const
- {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
- /// \brief Provides the size of the static private key
- /// \return size of static private keys in this domain
- /// \details The length is calculated using the byte count of the subgroup order.
- unsigned int StaticPrivateKeyLength() const
- {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
- /// \brief Provides the size of the static public key
- /// \return size of static public keys in this domain
- /// \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>,
- /// which means the element is encoded in a reversible format. A reversible
- /// format means it has a presentation format, and its an ANS.1 encoded element
- /// or point.
- unsigned int StaticPublicKeyLength() const
- {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
- /// \brief Generate static private key in this domain
- /// \param rng a RandomNumberGenerator derived class
- /// \param privateKey a byte buffer for the generated private key in this domain
- /// \details The private key is a random scalar used as an exponent in the range
- /// <tt>[1,MaxExponent()]</tt>.
- /// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
- void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
- {
- Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
- x.Encode(privateKey, StaticPrivateKeyLength());
- }
- /// \brief Generate a static public key from a private key in this domain
- /// \param rng a RandomNumberGenerator derived class
- /// \param privateKey a byte buffer with the previously generated private key
- /// \param publicKey a byte buffer for the generated public key in this domain
- /// \details The public key is an element or point on the curve, and its stored
- /// in a revrsible format. A reversible format means it has a presentation
- /// format, and its an ANS.1 encoded element or point.
- /// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
- void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
- {
- CRYPTOPP_UNUSED(rng);
- const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters();
- Integer x(privateKey, StaticPrivateKeyLength());
- Element y = params.ExponentiateBase(x);
- params.EncodeElement(true, y, publicKey);
- }
- /// \brief Provides the size of the ephemeral private key
- /// \return size of ephemeral private keys in this domain
- /// \details An ephemeral private key is a private key and public key.
- /// The serialized size is different than a static private key.
- unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
- /// \brief Provides the size of the ephemeral public key
- /// \return size of ephemeral public keys in this domain
- /// \details An ephemeral public key is a public key.
- /// The serialized size is the same as a static public key.
- unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
- /// \brief Generate ephemeral private key in this domain
- /// \param rng a RandomNumberGenerator derived class
- /// \param privateKey a byte buffer for the generated private key in this domain
- /// \pre <tt>COUNTOF(privateKey) == EphemeralPrivateKeyLength()</tt>
- void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
- {
- const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters();
- Integer x(rng, Integer::One(), params.GetMaxExponent());
- x.Encode(privateKey, StaticPrivateKeyLength());
- Element y = params.ExponentiateBase(x);
- params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
- }
- /// \brief Generate ephemeral public key from a private key in this domain
- /// \param rng a RandomNumberGenerator derived class
- /// \param privateKey a byte buffer with the previously generated private key
- /// \param publicKey a byte buffer for the generated public key in this domain
- /// \pre <tt>COUNTOF(publicKey) == EphemeralPublicKeyLength()</tt>
- void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
- {
- CRYPTOPP_UNUSED(rng);
- memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
- }
- /// \brief Derive agreed value or shared secret
- /// \param agreedValue the shared secret
- /// \param staticPrivateKey your long term private key
- /// \param ephemeralPrivateKey your ephemeral private key
- /// \param staticOtherPublicKey couterparty's long term public key
- /// \param ephemeralOtherPublicKey couterparty's ephemeral public key
- /// \param validateStaticOtherPublicKey flag indicating validation
- /// \return true upon success, false in case of failure
- /// \details Agree() performs the authenticated key agreement. Agree()
- /// derives a shared secret from your private keys and couterparty's
- /// public keys. Each instance or run of the protocol should use a new
- /// ephemeral key pair.
- /// \details The other's ephemeral public key will always be validated at
- /// Level 1 to ensure it is a point on the curve.
- /// <tt>validateStaticOtherPublicKey</tt> determines how thoroughly other's
- /// static public key is validated. If you have previously validated the
- /// couterparty's static public key, then use
- /// <tt>validateStaticOtherPublicKey=false</tt> to save time.
- /// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
- /// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
- /// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
- /// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
- /// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
- bool Agree(byte *agreedValue,
- const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
- const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
- bool validateStaticOtherPublicKey=true) const
- {
- const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
- size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
- // Depending on the role, this will hold either A's or B's static
- // (long term) public key. AA or BB will then point into tt.
- SecByteBlock tt(StaticPublicKeyLength());
- try
- {
- this->GetMaterial().DoQuickSanityCheck();
- const DL_GroupParameters<Element> ¶ms = GetAbstractGroupParameters();
- if(m_role == RoleServer)
- {
- Integer b(staticPrivateKey, StaticPrivateKeyLength());
- Element B = params.ExponentiateBase(b);
- params.EncodeElement(true, B, tt);
- XX = ephemeralOtherPublicKey;
- xxs = EphemeralPublicKeyLength();
- YY = ephemeralPrivateKey + StaticPrivateKeyLength();
- yys = EphemeralPublicKeyLength();
- AA = staticOtherPublicKey;
- aas = StaticPublicKeyLength();
- BB = tt.BytePtr();
- bbs = tt.SizeInBytes();
- }
- else
- {
- Integer a(staticPrivateKey, StaticPrivateKeyLength());
- Element A = params.ExponentiateBase(a);
- params.EncodeElement(true, A, tt);
- XX = ephemeralPrivateKey + StaticPrivateKeyLength();
- xxs = EphemeralPublicKeyLength();
- YY = ephemeralOtherPublicKey;
- yys = EphemeralPublicKeyLength();
- AA = tt.BytePtr();
- aas = tt.SizeInBytes();
- BB = staticOtherPublicKey;
- bbs = StaticPublicKeyLength();
- }
- Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
- Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
- const Integer& q = params.GetSubgroupOrder();
- const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
- SecByteBlock dd(len), ee(len);
- Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
- Integer d(dd.BytePtr(), dd.SizeInBytes());
- Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes());
- Integer e(ee.BytePtr(), ee.SizeInBytes());
- Element sigma;
- if(m_role == RoleServer)
- {
- Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
- Integer b(staticPrivateKey, StaticPrivateKeyLength());
- Integer s_B = (y + e * b) % q;
- Element A = params.DecodeElement(AA, false);
- Element X = params.DecodeElement(XX, false);
- Element t1 = params.ExponentiateElement(A, d);
- Element t2 = m_groupParameters.MultiplyElements(X, t1);
- sigma = params.ExponentiateElement(t2, s_B);
- }
- else
- {
- Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
- Integer a(staticPrivateKey, StaticPrivateKeyLength());
- Integer s_A = (x + d * a) % q;
- Element B = params.DecodeElement(BB, false);
- Element Y = params.DecodeElement(YY, false);
- Element t1 = params.ExponentiateElement(B, e);
- Element t2 = m_groupParameters.MultiplyElements(Y, t1);
- sigma = params.ExponentiateElement(t2, s_A);
- }
- Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength());
- }
- catch (DL_BadElement &)
- {
- CRYPTOPP_ASSERT(0);
- return false;
- }
- return true;
- }
- protected:
- inline void Hash(const Element* sigma,
- const byte* e1, size_t e1len, const byte* e2, size_t e2len,
- const byte* s1, size_t s1len, const byte* s2, size_t s2len,
- byte* digest, size_t dlen) const
- {
- HASH hash;
- size_t idx = 0, req = dlen;
- size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
- if(sigma)
- {
- //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
- //SecByteBlock sbb(x.MinEncodedSize());
- //x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
- SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
- GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
- hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
- }
- hash.Update(e1, e1len);
- hash.Update(e2, e2len);
- hash.Update(s1, s1len);
- hash.Update(s2, s2len);
- hash.TruncatedFinal(digest, blk);
- req -= blk;
- // All this to catch tail bytes for large curves and small hashes
- while(req != 0)
- {
- hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
- idx += (size_t)HASH::DIGESTSIZE;
- blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
- hash.TruncatedFinal(&digest[idx], blk);
- req -= blk;
- }
- }
- private:
- // The paper uses Initiator and Recipient - make it classical.
- enum KeyAgreementRole { RoleServer = 1, RoleClient };
- DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
- const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
- GroupParameters m_groupParameters;
- KeyAgreementRole m_role;
- };
- /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
- /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
- /// <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
- /// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
- /// \sa FHMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
- /// \since Crypto++ 5.6.4
- typedef FHMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> FHMQV;
- NAMESPACE_END
- #endif
|