Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // hmqv.h - written and placed in the public domain by Uri Blumenthal

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

0003 
0004 #ifndef CRYPTOPP_HMQV_H
0005 #define CRYPTOPP_HMQV_H
0006 
0007 /// \file hmqv.h

0008 /// \brief Classes for 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 Hashed Menezes-Qu-Vanstone in GF(p)

0018 /// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance

0019 ///   Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.

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

0021 /// \since Crypto++ 5.6.4

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

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

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

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

0036   HMQV_Domain(bool clientRole = true)
0037     : m_role(clientRole ? RoleClient : RoleServer) {}
0038 
0039   /// \brief Construct a HMQV domain

0040   /// \param params group parameters and options

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

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

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

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

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

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

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

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

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

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

0058   /// \param v1 first parameter

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

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

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

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

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

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

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

0071   /// \param v1 first parameter

0072   /// \param v2 second parameter

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

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

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

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

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

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

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

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

0086   /// \param v1 first parameter

0087   /// \param v2 second parameter

0088   /// \param v3 third parameter

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

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

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

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

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

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

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

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

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

0103   /// \param v1 first parameter

0104   /// \param v2 second parameter

0105   /// \param v3 third parameter

0106   /// \param v4 third parameter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

0150   ///  or point.

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

0155   /// \param rng a RandomNumberGenerator derived class

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

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

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

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

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

0167   /// \param rng a RandomNumberGenerator derived class

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

0196   /// \param rng a RandomNumberGenerator derived class

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

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

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

0209   /// \param rng a RandomNumberGenerator derived class

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

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

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

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

0220   /// \param agreedValue the shared secret

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

0222   /// \param ephemeralPrivateKey your ephemeral private key

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

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

0225   /// \param validateStaticOtherPublicKey flag indicating validation

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

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

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

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

0230   ///  ephemeral key pair.

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

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

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

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

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

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

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

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

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

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

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

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

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

0252     SecByteBlock tt(StaticPublicKeyLength());
0253 
0254     try
0255     {
0256       this->GetMaterial().DoQuickSanityCheck();
0257       const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
0258 
0259       if(m_role == RoleServer)
0260       {
0261         Integer b(staticPrivateKey, StaticPrivateKeyLength());
0262         Element B = params.ExponentiateBase(b);
0263         params.EncodeElement(true, B, tt);
0264 
0265         XX = ephemeralOtherPublicKey;
0266         xxs = EphemeralPublicKeyLength();
0267         YY = ephemeralPrivateKey + StaticPrivateKeyLength();
0268         yys = EphemeralPublicKeyLength();
0269         AA = staticOtherPublicKey;
0270         aas = StaticPublicKeyLength();
0271         BB = tt.BytePtr();
0272         bbs = tt.SizeInBytes();
0273       }
0274       else
0275       {
0276         Integer a(staticPrivateKey, StaticPrivateKeyLength());
0277         Element A = params.ExponentiateBase(a);
0278         params.EncodeElement(true, A, tt);
0279 
0280         XX = ephemeralPrivateKey + StaticPrivateKeyLength();
0281         xxs = EphemeralPublicKeyLength();
0282         YY = ephemeralOtherPublicKey;
0283         yys = EphemeralPublicKeyLength();
0284         AA = tt.BytePtr();
0285         aas = tt.SizeInBytes();
0286         BB = staticOtherPublicKey;
0287         bbs = StaticPublicKeyLength();
0288       }
0289 
0290       Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
0291       Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
0292 
0293       const Integer& q = params.GetSubgroupOrder();
0294       const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
0295       SecByteBlock dd(len), ee(len);
0296 
0297       // Compute $d = \hat{H}(X, \hat{B})$

0298       Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
0299       Integer d(dd.BytePtr(), dd.SizeInBytes());
0300 
0301       // Compute $e = \hat{H}(Y, \hat{A})$

0302       Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes());
0303       Integer e(ee.BytePtr(), ee.SizeInBytes());
0304 
0305       Element sigma;
0306       if(m_role == RoleServer)
0307       {
0308         Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
0309         Integer b(staticPrivateKey, StaticPrivateKeyLength());
0310         Integer s_B = (y + e * b) % q;
0311 
0312         Element A = params.DecodeElement(AA, false);
0313         Element X = params.DecodeElement(XX, false);
0314 
0315         Element t1 = params.ExponentiateElement(A, d);
0316         Element t2 = m_groupParameters.MultiplyElements(X, t1);
0317 
0318         // $\sigma_B}=(X \cdot A^{d})^{s_B}

0319         sigma = params.ExponentiateElement(t2, s_B);
0320       }
0321       else
0322       {
0323         Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
0324         Integer a(staticPrivateKey, StaticPrivateKeyLength());
0325         Integer s_A = (x + d * a) % q;
0326 
0327         Element B = params.DecodeElement(BB, false);
0328         Element Y = params.DecodeElement(YY, false);
0329 
0330         Element t3 = params.ExponentiateElement(B, e);
0331         Element t4 = m_groupParameters.MultiplyElements(Y, t3);
0332 
0333         // $\sigma_A}=(Y \cdot B^{e})^{s_A}

0334         sigma = params.ExponentiateElement(t4, s_A);
0335       }
0336       Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength());
0337     }
0338     catch (DL_BadElement &)
0339     {
0340       CRYPTOPP_ASSERT(0);
0341       return false;
0342     }
0343     return true;
0344   }
0345 
0346 protected:
0347   // Hash invocation by client and server differ only in what keys

0348   // each provides.

0349 
0350   inline void Hash(const Element* sigma,
0351     const byte* e1, size_t e1len, // Ephemeral key and key length

0352     const byte* s1, size_t s1len, // Static key and key length

0353     byte* digest, size_t dlen) const
0354   {
0355     HASH hash;
0356     size_t idx = 0, req = dlen;
0357     size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
0358 
0359     if(sigma)
0360     {
0361       if (e1len != 0 || s1len != 0) {
0362         CRYPTOPP_ASSERT(0);
0363       }
0364       //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);

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

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

0367       SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
0368       GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
0369       hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
0370     } else {
0371       if (e1len == 0 || s1len == 0) {
0372         CRYPTOPP_ASSERT(0);
0373       }
0374       hash.Update(e1, e1len);
0375       hash.Update(s1, s1len);
0376     }
0377 
0378     hash.TruncatedFinal(digest, blk);
0379     req -= blk;
0380 
0381     // All this to catch tail bytes for large curves and small hashes

0382     while(req != 0)
0383     {
0384       hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
0385 
0386       idx += (size_t)HASH::DIGESTSIZE;
0387       blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
0388       hash.TruncatedFinal(&digest[idx], blk);
0389 
0390       req -= blk;
0391     }
0392   }
0393 
0394 private:
0395 
0396   // The paper uses Initiator and Recipient - make it classical.

0397   enum KeyAgreementRole { RoleServer = 1, RoleClient };
0398 
0399   DL_GroupParameters<Element> & AccessAbstractGroupParameters()
0400     {return m_groupParameters;}
0401   const DL_GroupParameters<Element> & GetAbstractGroupParameters() const
0402     {return m_groupParameters;}
0403 
0404   GroupParameters m_groupParameters;
0405   KeyAgreementRole m_role;
0406 };
0407 
0408 /// \brief Hashed Menezes-Qu-Vanstone in GF(p)

0409 /// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance

0410 ///   Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.

0411 /// \sa HMQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain

0412 /// \since Crypto++ 5.6.4

0413 typedef HMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> HMQV;
0414 
0415 NAMESPACE_END
0416 
0417 #endif