1 // fhmqv.h - written and placed in the public domain by Jeffrey Walton, Ray Clayton and Uri Blumenthal
2 //           Shamelessly based upon Wei Dai's MQV source files
3 
4 #ifndef CRYPTOPP_FHMQV_H
5 #define CRYPTOPP_FHMQV_H
6 
7 /// \file fhmqv.h
8 /// \brief Classes for Fully Hashed Menezes-Qu-Vanstone key agreement in GF(p)
9 /// \since Crypto++ 5.6.4
10 
11 #include "gfpcrypt.h"
12 #include "algebra.h"
13 #include "sha.h"
14 
NAMESPACE_BEGIN(CryptoPP)15 NAMESPACE_BEGIN(CryptoPP)
16 
17 /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
18 /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
19 ///   <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
20 ///   Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
21 /// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
22 /// \since Crypto++ 5.6.4
23 template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
24 class FHMQV_Domain : public AuthenticatedKeyAgreementDomain
25 {
26 public:
27   typedef GROUP_PARAMETERS GroupParameters;
28   typedef typename GroupParameters::Element Element;
29   typedef FHMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
30 
31   virtual ~FHMQV_Domain() {}
32 
33   /// \brief Construct a FHMQV domain
34   /// \param clientRole flag indicating initiator or recipient
35   /// \details <tt>clientRole = true</tt> indicates initiator, and
36   ///  <tt>clientRole = false</tt> indicates recipient or server.
37   FHMQV_Domain(bool clientRole = true)
38     : m_role(clientRole ? RoleClient : RoleServer) {}
39 
40   /// \brief Construct a FHMQV domain
41   /// \param params group parameters and options
42   /// \param clientRole flag indicating initiator or recipient
43   /// \details <tt>clientRole = true</tt> indicates initiator, and
44   ///  <tt>clientRole = false</tt> indicates recipient or server.
45   FHMQV_Domain(const GroupParameters &params, bool clientRole = true)
46     : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
47 
48   /// \brief Construct a FHMQV domain
49   /// \param bt BufferedTransformation with group parameters and options
50   /// \param clientRole flag indicating initiator or recipient
51   /// \details <tt>clientRole = true</tt> indicates initiator, and
52   ///  <tt>clientRole = false</tt> indicates recipient or server.
53   FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
54     : m_role(clientRole ? RoleClient : RoleServer)
55     {m_groupParameters.BERDecode(bt);}
56 
57   /// \brief Construct a FHMQV domain
58   /// \tparam T1 template parameter used as a constructor parameter
59   /// \param v1 first parameter
60   /// \param clientRole flag indicating initiator or recipient
61   /// \details v1 is passed directly to the GROUP_PARAMETERS object.
62   /// \details <tt>clientRole = true</tt> indicates initiator, and
63   ///  <tt>clientRole = false</tt> indicates recipient or server.
64   template <class T1>
65   FHMQV_Domain(T1 v1, bool clientRole = true)
66     : m_role(clientRole ? RoleClient : RoleServer)
67     {m_groupParameters.Initialize(v1);}
68 
69   /// \brief Construct a FHMQV domain
70   /// \tparam T1 template parameter used as a constructor parameter
71   /// \tparam T2 template parameter used as a constructor parameter
72   /// \param v1 first parameter
73   /// \param v2 second parameter
74   /// \param clientRole flag indicating initiator or recipient
75   /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
76   /// \details <tt>clientRole = true</tt> indicates initiator, and
77   ///  <tt>clientRole = false</tt> indicates recipient or server.
78   template <class T1, class T2>
79   FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
80     : m_role(clientRole ? RoleClient : RoleServer)
81     {m_groupParameters.Initialize(v1, v2);}
82 
83   /// \brief Construct a FHMQV domain
84   /// \tparam T1 template parameter used as a constructor parameter
85   /// \tparam T2 template parameter used as a constructor parameter
86   /// \tparam T3 template parameter used as a constructor parameter
87   /// \param v1 first parameter
88   /// \param v2 second parameter
89   /// \param v3 third parameter
90   /// \param clientRole flag indicating initiator or recipient
91   /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
92   /// \details <tt>clientRole = true</tt> indicates initiator, and
93   ///  <tt>clientRole = false</tt> indicates recipient or server.
94   template <class T1, class T2, class T3>
95   FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
96     : m_role(clientRole ? RoleClient : RoleServer)
97     {m_groupParameters.Initialize(v1, v2, v3);}
98 
99   /// \brief Construct a FHMQV domain
100   /// \tparam T1 template parameter used as a constructor parameter
101   /// \tparam T2 template parameter used as a constructor parameter
102   /// \tparam T3 template parameter used as a constructor parameter
103   /// \tparam T4 template parameter used as a constructor parameter
104   /// \param v1 first parameter
105   /// \param v2 second parameter
106   /// \param v3 third parameter
107   /// \param v4 third parameter
108   /// \param clientRole flag indicating initiator or recipient
109   /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
110   /// \details <tt>clientRole = true</tt> indicates initiator, and
111   ///  <tt>clientRole = false</tt> indicates recipient or server.
112   template <class T1, class T2, class T3, class T4>
113   FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
114     : m_role(clientRole ? RoleClient : RoleServer)
115     {m_groupParameters.Initialize(v1, v2, v3, v4);}
116 
117 public:
118 
119   /// \brief Retrieves the group parameters for this domain
120   /// \return the group parameters for this domain as a const reference
121   const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
122 
123   /// \brief Retrieves the group parameters for this domain
124   /// \return the group parameters for this domain as a non-const reference
125   GroupParameters & AccessGroupParameters() {return m_groupParameters;}
126 
127   /// \brief Retrieves the crypto parameters for this domain
128   /// \return the crypto parameters for this domain as a non-const reference
129   CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
130 
131   /// \brief Provides the size of the agreed value
132   /// \return size of agreed value produced in this domain
133   /// \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>,
134   ///  which means the element is encoded in a non-reversible format. A
135   ///  non-reversible format means its a raw byte array, and it lacks presentation
136   ///  format like an ASN.1 BIT_STRING or OCTET_STRING.
137   unsigned int AgreedValueLength() const
138     {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
139 
140   /// \brief Provides the size of the static private key
141   /// \return size of static private keys in this domain
142   /// \details The length is calculated using the byte count of the subgroup order.
143   unsigned int StaticPrivateKeyLength() const
144     {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
145 
146   /// \brief Provides the size of the static public key
147   /// \return size of static public keys in this domain
148   /// \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>,
149   ///  which means the element is encoded in a reversible format. A reversible
150   ///  format means it has a presentation format, and its an ANS.1 encoded element
151   ///  or point.
152   unsigned int StaticPublicKeyLength() const
153     {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
154 
155   /// \brief Generate static private key in this domain
156   /// \param rng a RandomNumberGenerator derived class
157   /// \param privateKey a byte buffer for the generated private key in this domain
158   /// \details The private key is a random scalar used as an exponent in the range
159   ///  <tt>[1,MaxExponent()]</tt>.
160   /// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
161   void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
162   {
163     Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
164     x.Encode(privateKey, StaticPrivateKeyLength());
165   }
166 
167   /// \brief Generate a static public key from a private key in this domain
168   /// \param rng a RandomNumberGenerator derived class
169   /// \param privateKey a byte buffer with the previously generated private key
170   /// \param publicKey a byte buffer for the generated public key in this domain
171   /// \details The public key is an element or point on the curve, and its stored
172   ///  in a revrsible format. A reversible format means it has a presentation
173   ///  format, and its an ANS.1 encoded element or point.
174   /// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
175   void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
176   {
177     CRYPTOPP_UNUSED(rng);
178     const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
179     Integer x(privateKey, StaticPrivateKeyLength());
180     Element y = params.ExponentiateBase(x);
181     params.EncodeElement(true, y, publicKey);
182   }
183 
184   /// \brief Provides the size of the ephemeral private key
185   /// \return size of ephemeral private keys in this domain
186   /// \details An ephemeral private key is a private key and public key.
187   ///  The serialized size is different than a static private key.
188   unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
189 
190   /// \brief Provides the size of the ephemeral public key
191   /// \return size of ephemeral public keys in this domain
192   /// \details An ephemeral public key is a public key.
193   ///  The serialized size is the same as a static public key.
194   unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
195 
196   /// \brief Generate ephemeral private key in this domain
197   /// \param rng a RandomNumberGenerator derived class
198   /// \param privateKey a byte buffer for the generated private key in this domain
199   /// \pre <tt>COUNTOF(privateKey) == EphemeralPrivateKeyLength()</tt>
200   void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
201   {
202     const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
203     Integer x(rng, Integer::One(), params.GetMaxExponent());
204     x.Encode(privateKey, StaticPrivateKeyLength());
205     Element y = params.ExponentiateBase(x);
206     params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
207   }
208 
209   /// \brief Generate ephemeral public key from a private key in this domain
210   /// \param rng a RandomNumberGenerator derived class
211   /// \param privateKey a byte buffer with the previously generated private key
212   /// \param publicKey a byte buffer for the generated public key in this domain
213   /// \pre <tt>COUNTOF(publicKey) == EphemeralPublicKeyLength()</tt>
214   void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
215   {
216     CRYPTOPP_UNUSED(rng);
217     memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
218   }
219 
220   /// \brief Derive agreed value or shared secret
221   /// \param agreedValue the shared secret
222   /// \param staticPrivateKey your long term private key
223   /// \param ephemeralPrivateKey your ephemeral private key
224   /// \param staticOtherPublicKey couterparty's long term public key
225   /// \param ephemeralOtherPublicKey couterparty's ephemeral public key
226   /// \param validateStaticOtherPublicKey flag indicating validation
227   /// \return true upon success, false in case of failure
228   /// \details Agree() performs the authenticated key agreement. Agree()
229   ///  derives a shared secret from your private keys and couterparty's
230   ///  public keys. Each instance or run of the protocol should use a new
231   ///  ephemeral key pair.
232   /// \details The other's ephemeral public key will always be validated at
233   ///  Level 1 to ensure it is a point on the curve.
234   ///  <tt>validateStaticOtherPublicKey</tt> determines how thoroughly other's
235   ///  static public key is validated. If you have previously validated the
236   ///  couterparty's static public key, then use
237   ///  <tt>validateStaticOtherPublicKey=false</tt> to save time.
238   /// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
239   /// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
240   /// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
241   /// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
242   /// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
243   bool Agree(byte *agreedValue,
244     const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
245     const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
246     bool validateStaticOtherPublicKey=true) const
247   {
248     const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
249     size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
250 
251     // Depending on the role, this will hold either A's or B's static
252     // (long term) public key. AA or BB will then point into tt.
253     SecByteBlock tt(StaticPublicKeyLength());
254 
255     try
256     {
257       this->GetMaterial().DoQuickSanityCheck();
258       const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
259 
260       if(m_role == RoleServer)
261       {
262         Integer b(staticPrivateKey, StaticPrivateKeyLength());
263         Element B = params.ExponentiateBase(b);
264         params.EncodeElement(true, B, tt);
265 
266         XX = ephemeralOtherPublicKey;
267         xxs = EphemeralPublicKeyLength();
268         YY = ephemeralPrivateKey + StaticPrivateKeyLength();
269         yys = EphemeralPublicKeyLength();
270         AA = staticOtherPublicKey;
271         aas = StaticPublicKeyLength();
272         BB = tt.BytePtr();
273         bbs = tt.SizeInBytes();
274       }
275       else
276       {
277         Integer a(staticPrivateKey, StaticPrivateKeyLength());
278         Element A = params.ExponentiateBase(a);
279         params.EncodeElement(true, A, tt);
280 
281         XX = ephemeralPrivateKey + StaticPrivateKeyLength();
282         xxs = EphemeralPublicKeyLength();
283         YY = ephemeralOtherPublicKey;
284         yys = EphemeralPublicKeyLength();
285         AA = tt.BytePtr();
286         aas = tt.SizeInBytes();
287         BB = staticOtherPublicKey;
288         bbs = StaticPublicKeyLength();
289       }
290 
291       Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
292       Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
293 
294       const Integer& q = params.GetSubgroupOrder();
295       const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
296       SecByteBlock dd(len), ee(len);
297 
298       Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
299       Integer d(dd.BytePtr(), dd.SizeInBytes());
300 
301       Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes());
302       Integer e(ee.BytePtr(), ee.SizeInBytes());
303 
304       Element sigma;
305       if(m_role == RoleServer)
306       {
307         Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
308         Integer b(staticPrivateKey, StaticPrivateKeyLength());
309         Integer s_B = (y + e * b) % q;
310 
311         Element A = params.DecodeElement(AA, false);
312         Element X = params.DecodeElement(XX, false);
313 
314         Element t1 = params.ExponentiateElement(A, d);
315         Element t2 = m_groupParameters.MultiplyElements(X, t1);
316 
317         sigma = params.ExponentiateElement(t2, s_B);
318       }
319       else
320       {
321         Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
322         Integer a(staticPrivateKey, StaticPrivateKeyLength());
323         Integer s_A = (x + d * a) % q;
324 
325         Element B = params.DecodeElement(BB, false);
326         Element Y = params.DecodeElement(YY, false);
327 
328         Element t1 = params.ExponentiateElement(B, e);
329         Element t2 = m_groupParameters.MultiplyElements(Y, t1);
330 
331         sigma = params.ExponentiateElement(t2, s_A);
332       }
333 
334       Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength());
335     }
336     catch (DL_BadElement &)
337     {
338       CRYPTOPP_ASSERT(0);
339       return false;
340     }
341     return true;
342   }
343 
344 protected:
345 
346   inline void Hash(const Element* sigma,
347     const byte* e1, size_t e1len, const byte* e2, size_t e2len,
348     const byte* s1, size_t s1len, const byte* s2, size_t s2len,
349     byte* digest, size_t dlen) const
350   {
351     HASH hash;
352     size_t idx = 0, req = dlen;
353     size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
354 
355     if(sigma)
356     {
357       //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
358       //SecByteBlock sbb(x.MinEncodedSize());
359       //x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
360       SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
361       GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
362       hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
363     }
364 
365     hash.Update(e1, e1len);
366     hash.Update(e2, e2len);
367     hash.Update(s1, s1len);
368     hash.Update(s2, s2len);
369 
370     hash.TruncatedFinal(digest, blk);
371     req -= blk;
372 
373     // All this to catch tail bytes for large curves and small hashes
374     while(req != 0)
375     {
376       hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
377 
378       idx += (size_t)HASH::DIGESTSIZE;
379       blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
380       hash.TruncatedFinal(&digest[idx], blk);
381 
382       req -= blk;
383     }
384   }
385 
386 private:
387 
388   // The paper uses Initiator and Recipient - make it classical.
389   enum KeyAgreementRole { RoleServer = 1, RoleClient };
390 
391   DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
392   const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
393 
394   GroupParameters m_groupParameters;
395   KeyAgreementRole m_role;
396 };
397 
398 /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
399 /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
400 ///   <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
401 ///   Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
402 /// \sa FHMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
403 /// \since Crypto++ 5.6.4
404 typedef FHMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> FHMQV;
405 
406 NAMESPACE_END
407 
408 #endif
409