Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:55:02

0001 // fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal

0002 //           Shamelessly based upon Wei Dai's MQV source files

0003 
0004 #ifndef CRYPTOPP_FHMQV_H
0005 #define CRYPTOPP_FHMQV_H
0006 
0007 /// \file fhmqv.h

0008 /// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p)

0009 /// \since Crypto++ 5.6.4

0010 
0011 #include "gfpcrypt.h"
0012 #include "algebra.h"
0013 #include "sha.h"
0014 
0015 NAMESPACE_BEGIN(CryptoPP)
0016 
0017 /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)

0018 /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's

0019 ///   <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.

0020 ///   Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.

0021 /// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain

0022 /// \since Crypto++ 5.6.4

0023 template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
0024 class FHMQV_Domain : public AuthenticatedKeyAgreementDomain
0025 {
0026 public:
0027   typedef GROUP_PARAMETERS GroupParameters;
0028   typedef typename GroupParameters::Element Element;
0029   typedef FHMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
0030 
0031   virtual ~FHMQV_Domain() {}
0032 
0033   /// \brief Construct a FHMQV domain

0034   /// \param clientRole flag indicating initiator or recipient

0035   /// \details <tt>clientRole = true</tt> indicates initiator, and

0036   ///  <tt>clientRole = false</tt> indicates recipient or server.

0037   FHMQV_Domain(bool clientRole = true)
0038     : m_role(clientRole ? RoleClient : RoleServer) {}
0039 
0040   /// \brief Construct a FHMQV domain

0041   /// \param params group parameters and options

0042   /// \param clientRole flag indicating initiator or recipient

0043   /// \details <tt>clientRole = true</tt> indicates initiator, and

0044   ///  <tt>clientRole = false</tt> indicates recipient or server.

0045   FHMQV_Domain(const GroupParameters &params, bool clientRole = true)
0046     : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
0047 
0048   /// \brief Construct a FHMQV domain

0049   /// \param bt BufferedTransformation with group parameters and options

0050   /// \param clientRole flag indicating initiator or recipient

0051   /// \details <tt>clientRole = true</tt> indicates initiator, and

0052   ///  <tt>clientRole = false</tt> indicates recipient or server.

0053   FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
0054     : m_role(clientRole ? RoleClient : RoleServer)
0055     {m_groupParameters.BERDecode(bt);}
0056 
0057   /// \brief Construct a FHMQV domain

0058   /// \tparam T1 template parameter used as a constructor parameter

0059   /// \param v1 first parameter

0060   /// \param clientRole flag indicating initiator or recipient

0061   /// \details v1 is passed directly to the GROUP_PARAMETERS object.

0062   /// \details <tt>clientRole = true</tt> indicates initiator, and

0063   ///  <tt>clientRole = false</tt> indicates recipient or server.

0064   template <class T1>
0065   FHMQV_Domain(T1 v1, bool clientRole = true)
0066     : m_role(clientRole ? RoleClient : RoleServer)
0067     {m_groupParameters.Initialize(v1);}
0068 
0069   /// \brief Construct a FHMQV domain

0070   /// \tparam T1 template parameter used as a constructor parameter

0071   /// \tparam T2 template parameter used as a constructor parameter

0072   /// \param v1 first parameter

0073   /// \param v2 second parameter

0074   /// \param clientRole flag indicating initiator or recipient

0075   /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.

0076   /// \details <tt>clientRole = true</tt> indicates initiator, and

0077   ///  <tt>clientRole = false</tt> indicates recipient or server.

0078   template <class T1, class T2>
0079   FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
0080     : m_role(clientRole ? RoleClient : RoleServer)
0081     {m_groupParameters.Initialize(v1, v2);}
0082 
0083   /// \brief Construct a FHMQV domain

0084   /// \tparam T1 template parameter used as a constructor parameter

0085   /// \tparam T2 template parameter used as a constructor parameter

0086   /// \tparam T3 template parameter used as a constructor parameter

0087   /// \param v1 first parameter

0088   /// \param v2 second parameter

0089   /// \param v3 third parameter

0090   /// \param clientRole flag indicating initiator or recipient

0091   /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.

0092   /// \details <tt>clientRole = true</tt> indicates initiator, and

0093   ///  <tt>clientRole = false</tt> indicates recipient or server.

0094   template <class T1, class T2, class T3>
0095   FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
0096     : m_role(clientRole ? RoleClient : RoleServer)
0097     {m_groupParameters.Initialize(v1, v2, v3);}
0098 
0099   /// \brief Construct a FHMQV domain

0100   /// \tparam T1 template parameter used as a constructor parameter

0101   /// \tparam T2 template parameter used as a constructor parameter

0102   /// \tparam T3 template parameter used as a constructor parameter

0103   /// \tparam T4 template parameter used as a constructor parameter

0104   /// \param v1 first parameter

0105   /// \param v2 second parameter

0106   /// \param v3 third parameter

0107   /// \param v4 third parameter

0108   /// \param clientRole flag indicating initiator or recipient

0109   /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.

0110   /// \details <tt>clientRole = true</tt> indicates initiator, and

0111   ///  <tt>clientRole = false</tt> indicates recipient or server.

0112   template <class T1, class T2, class T3, class T4>
0113   FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
0114     : m_role(clientRole ? RoleClient : RoleServer)
0115     {m_groupParameters.Initialize(v1, v2, v3, v4);}
0116 
0117 public:
0118 
0119   /// \brief Retrieves the group parameters for this domain

0120   /// \return the group parameters for this domain as a const reference

0121   const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
0122 
0123   /// \brief Retrieves the group parameters for this domain

0124   /// \return the group parameters for this domain as a non-const reference

0125   GroupParameters & AccessGroupParameters() {return m_groupParameters;}
0126 
0127   /// \brief Retrieves the crypto parameters for this domain

0128   /// \return the crypto parameters for this domain as a non-const reference

0129   CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
0130 
0131   /// \brief Provides the size of the agreed value

0132   /// \return size of agreed value produced in this domain

0133   /// \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>,

0134   ///  which means the element is encoded in a non-reversible format. A

0135   ///  non-reversible format means its a raw byte array, and it lacks presentation

0136   ///  format like an ASN.1 BIT_STRING or OCTET_STRING.

0137   unsigned int AgreedValueLength() const
0138     {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
0139 
0140   /// \brief Provides the size of the static private key

0141   /// \return size of static private keys in this domain

0142   /// \details The length is calculated using the byte count of the subgroup order.

0143   unsigned int StaticPrivateKeyLength() const
0144     {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
0145 
0146   /// \brief Provides the size of the static public key

0147   /// \return size of static public keys in this domain

0148   /// \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>,

0149   ///  which means the element is encoded in a reversible format. A reversible

0150   ///  format means it has a presentation format, and its an ANS.1 encoded element

0151   ///  or point.

0152   unsigned int StaticPublicKeyLength() const
0153     {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
0154 
0155   /// \brief Generate static private key in this domain

0156   /// \param rng a RandomNumberGenerator derived class

0157   /// \param privateKey a byte buffer for the generated private key in this domain

0158   /// \details The private key is a random scalar used as an exponent in the range

0159   ///  <tt>[1,MaxExponent()]</tt>.

0160   /// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>

0161   void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
0162   {
0163     Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
0164     x.Encode(privateKey, StaticPrivateKeyLength());
0165   }
0166 
0167   /// \brief Generate a static public key from a private key in this domain

0168   /// \param rng a RandomNumberGenerator derived class

0169   /// \param privateKey a byte buffer with the previously generated private key

0170   /// \param publicKey a byte buffer for the generated public key in this domain

0171   /// \details The public key is an element or point on the curve, and its stored

0172   ///  in a revrsible format. A reversible format means it has a presentation

0173   ///  format, and its an ANS.1 encoded element or point.

0174   /// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>

0175   void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
0176   {
0177     CRYPTOPP_UNUSED(rng);
0178     const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
0179     Integer x(privateKey, StaticPrivateKeyLength());
0180     Element y = params.ExponentiateBase(x);
0181     params.EncodeElement(true, y, publicKey);
0182   }
0183 
0184   /// \brief Provides the size of the ephemeral private key

0185   /// \return size of ephemeral private keys in this domain

0186   /// \details An ephemeral private key is a private key and public key.

0187   ///  The serialized size is different than a static private key.

0188   unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
0189 
0190   /// \brief Provides the size of the ephemeral public key

0191   /// \return size of ephemeral public keys in this domain

0192   /// \details An ephemeral public key is a public key.

0193   ///  The serialized size is the same as a static public key.

0194   unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
0195 
0196   /// \brief Generate ephemeral private key in this domain

0197   /// \param rng a RandomNumberGenerator derived class

0198   /// \param privateKey a byte buffer for the generated private key in this domain

0199   /// \pre <tt>COUNTOF(privateKey) == EphemeralPrivateKeyLength()</tt>

0200   void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
0201   {
0202     const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
0203     Integer x(rng, Integer::One(), params.GetMaxExponent());
0204     x.Encode(privateKey, StaticPrivateKeyLength());
0205     Element y = params.ExponentiateBase(x);
0206     params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
0207   }
0208 
0209   /// \brief Generate ephemeral public key from a private key in this domain

0210   /// \param rng a RandomNumberGenerator derived class

0211   /// \param privateKey a byte buffer with the previously generated private key

0212   /// \param publicKey a byte buffer for the generated public key in this domain

0213   /// \pre <tt>COUNTOF(publicKey) == EphemeralPublicKeyLength()</tt>

0214   void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
0215   {
0216     CRYPTOPP_UNUSED(rng);
0217     std::memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
0218   }
0219 
0220   /// \brief Derive agreed value or shared secret

0221   /// \param agreedValue the shared secret

0222   /// \param staticPrivateKey your long term private key

0223   /// \param ephemeralPrivateKey your ephemeral private key

0224   /// \param staticOtherPublicKey couterparty's long term public key

0225   /// \param ephemeralOtherPublicKey couterparty's ephemeral public key

0226   /// \param validateStaticOtherPublicKey flag indicating validation

0227   /// \return true upon success, false in case of failure

0228   /// \details Agree() performs the authenticated key agreement. Agree()

0229   ///  derives a shared secret from your private keys and couterparty's

0230   ///  public keys. Each instance or run of the protocol should use a new

0231   ///  ephemeral key pair.

0232   /// \details The other's ephemeral public key will always be validated at

0233   ///  Level 1 to ensure it is a point on the curve.

0234   ///  <tt>validateStaticOtherPublicKey</tt> determines how thoroughly other's

0235   ///  static public key is validated. If you have previously validated the

0236   ///  couterparty's static public key, then use

0237   ///  <tt>validateStaticOtherPublicKey=false</tt> to save time.

0238   /// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>

0239   /// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>

0240   /// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>

0241   /// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>

0242   /// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>

0243   bool Agree(byte *agreedValue,
0244     const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
0245     const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
0246     bool validateStaticOtherPublicKey=true) const
0247   {
0248     const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
0249     size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
0250 
0251     // Depending on the role, this will hold either A's or B's static

0252     // (long term) public key. AA or BB will then point into tt.

0253     SecByteBlock tt(StaticPublicKeyLength());
0254 
0255     try
0256     {
0257       this->GetMaterial().DoQuickSanityCheck();
0258       const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
0259 
0260       if(m_role == RoleServer)
0261       {
0262         Integer b(staticPrivateKey, StaticPrivateKeyLength());
0263         Element B = params.ExponentiateBase(b);
0264         params.EncodeElement(true, B, tt);
0265 
0266         XX = ephemeralOtherPublicKey;
0267         xxs = EphemeralPublicKeyLength();
0268         YY = ephemeralPrivateKey + StaticPrivateKeyLength();
0269         yys = EphemeralPublicKeyLength();
0270         AA = staticOtherPublicKey;
0271         aas = StaticPublicKeyLength();
0272         BB = tt.BytePtr();
0273         bbs = tt.SizeInBytes();
0274       }
0275       else
0276       {
0277         Integer a(staticPrivateKey, StaticPrivateKeyLength());
0278         Element A = params.ExponentiateBase(a);
0279         params.EncodeElement(true, A, tt);
0280 
0281         XX = ephemeralPrivateKey + StaticPrivateKeyLength();
0282         xxs = EphemeralPublicKeyLength();
0283         YY = ephemeralOtherPublicKey;
0284         yys = EphemeralPublicKeyLength();
0285         AA = tt.BytePtr();
0286         aas = tt.SizeInBytes();
0287         BB = staticOtherPublicKey;
0288         bbs = StaticPublicKeyLength();
0289       }
0290 
0291       Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
0292       Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
0293 
0294       const Integer& q = params.GetSubgroupOrder();
0295       const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
0296       SecByteBlock dd(len), ee(len);
0297 
0298       Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
0299       Integer d(dd.BytePtr(), dd.SizeInBytes());
0300 
0301       Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes());
0302       Integer e(ee.BytePtr(), ee.SizeInBytes());
0303 
0304       Element sigma;
0305       if(m_role == RoleServer)
0306       {
0307         Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
0308         Integer b(staticPrivateKey, StaticPrivateKeyLength());
0309         Integer s_B = (y + e * b) % q;
0310 
0311         Element A = params.DecodeElement(AA, false);
0312         Element X = params.DecodeElement(XX, false);
0313 
0314         Element t1 = params.ExponentiateElement(A, d);
0315         Element t2 = m_groupParameters.MultiplyElements(X, t1);
0316 
0317         sigma = params.ExponentiateElement(t2, s_B);
0318       }
0319       else
0320       {
0321         Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
0322         Integer a(staticPrivateKey, StaticPrivateKeyLength());
0323         Integer s_A = (x + d * a) % q;
0324 
0325         Element B = params.DecodeElement(BB, false);
0326         Element Y = params.DecodeElement(YY, false);
0327 
0328         Element t1 = params.ExponentiateElement(B, e);
0329         Element t2 = m_groupParameters.MultiplyElements(Y, t1);
0330 
0331         sigma = params.ExponentiateElement(t2, s_A);
0332       }
0333 
0334       Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength());
0335     }
0336     catch (DL_BadElement &)
0337     {
0338       CRYPTOPP_ASSERT(0);
0339       return false;
0340     }
0341     return true;
0342   }
0343 
0344 protected:
0345 
0346   inline void Hash(const Element* sigma,
0347     const byte* e1, size_t e1len, const byte* e2, size_t e2len,
0348     const byte* s1, size_t s1len, const byte* s2, size_t s2len,
0349     byte* digest, size_t dlen) const
0350   {
0351     HASH hash;
0352     size_t idx = 0, req = dlen;
0353     size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
0354 
0355     if(sigma)
0356     {
0357       //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);

0358       //SecByteBlock sbb(x.MinEncodedSize());

0359       //x.Encode(sbb.BytePtr(), sbb.SizeInBytes());

0360       SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
0361       GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
0362       hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
0363     }
0364 
0365     hash.Update(e1, e1len);
0366     hash.Update(e2, e2len);
0367     hash.Update(s1, s1len);
0368     hash.Update(s2, s2len);
0369 
0370     hash.TruncatedFinal(digest, blk);
0371     req -= blk;
0372 
0373     // All this to catch tail bytes for large curves and small hashes

0374     while(req != 0)
0375     {
0376       hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
0377 
0378       idx += (size_t)HASH::DIGESTSIZE;
0379       blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
0380       hash.TruncatedFinal(&digest[idx], blk);
0381 
0382       req -= blk;
0383     }
0384   }
0385 
0386 private:
0387 
0388   // The paper uses Initiator and Recipient - make it classical.

0389   enum KeyAgreementRole { RoleServer = 1, RoleClient };
0390 
0391   DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
0392   const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
0393 
0394   GroupParameters m_groupParameters;
0395   KeyAgreementRole m_role;
0396 };
0397 
0398 /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)

0399 /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's

0400 ///   <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.

0401 ///   Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.

0402 /// \sa FHMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain

0403 /// \since Crypto++ 5.6.4

0404 typedef FHMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> FHMQV;
0405 
0406 NAMESPACE_END
0407 
0408 #endif