Crypto++  5.6.4
Free C++ class library of cryptographic schemes
hmqv.h
Go to the documentation of this file.
1 // hmqv.h - written and placed in the public domain by Uri Blumenthal
2 // Shamelessly based upon Jeffrey Walton's FHMQV and Wei Dai's MQV source files
3 
4 #ifndef CRYPTOPP_HMQV_H
5 #define CRYPTOPP_HMQV_H
6 
7 //! \file hmqv.h
8 //! \brief Classes for 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 
15 NAMESPACE_BEGIN(CryptoPP)
16 
17 //! \brief Hashed Menezes-Qu-Vanstone in GF(p)
18 //! \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
19 //! Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
20 //! \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
21 //! \since Crypto++ 5.6.4
22 template <class GROUP_PARAMETERS, class COFACTOR_OPTION = CPP_TYPENAME GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
24 {
25 public:
26  typedef GROUP_PARAMETERS GroupParameters;
27  typedef typename GroupParameters::Element Element;
29 
30 #ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
31  virtual ~HMQV_Domain() {}
32 #endif
33 
34  HMQV_Domain(bool clientRole = true): m_role(clientRole ? RoleClient : RoleServer) {}
35 
36  HMQV_Domain(const GroupParameters &params, bool clientRole = true)
37  : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
38 
39  HMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
40  : m_role(clientRole ? RoleClient : RoleServer)
41  {m_groupParameters.BERDecode(bt);}
42 
43  template <class T1>
44  HMQV_Domain(T1 v1, bool clientRole = true)
45  : m_role(clientRole ? RoleClient : RoleServer)
46  {m_groupParameters.Initialize(v1);}
47 
48  template <class T1, class T2>
49  HMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
50  : m_role(clientRole ? RoleClient : RoleServer)
51  {m_groupParameters.Initialize(v1, v2);}
52 
53  template <class T1, class T2, class T3>
54  HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
55  : m_role(clientRole ? RoleClient : RoleServer)
56  {m_groupParameters.Initialize(v1, v2, v3);}
57 
58  template <class T1, class T2, class T3, class T4>
59  HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
60  : m_role(clientRole ? RoleClient : RoleServer)
61  {m_groupParameters.Initialize(v1, v2, v3, v4);}
62 
63 public:
64 
65  const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
66  GroupParameters & AccessGroupParameters(){return m_groupParameters;}
67 
68  CryptoParameters & AccessCryptoParameters(){return AccessAbstractGroupParameters();}
69 
70  //! return length of agreed value produced
71  unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
72  //! return length of static private keys in this domain
73  unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
74  //! return length of static public keys in this domain
75  unsigned int StaticPublicKeyLength() const{return GetAbstractGroupParameters().GetEncodedElementSize(true);}
76 
77  //! generate static private key
78  /*! \pre size of privateKey == PrivateStaticKeyLength() */
79  void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
80  {
81  Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
82  x.Encode(privateKey, StaticPrivateKeyLength());
83  }
84 
85  //! generate static public key
86  /*! \pre size of publicKey == PublicStaticKeyLength() */
87  void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
88  {
89  CRYPTOPP_UNUSED(rng);
90  const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
91  Integer x(privateKey, StaticPrivateKeyLength());
92  Element y = params.ExponentiateBase(x);
93  params.EncodeElement(true, y, publicKey);
94  }
95 
96  unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
97  unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
98 
99  //! return length of ephemeral private keys in this domain
100  void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
101  {
102  const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
103  Integer x(rng, Integer::One(), params.GetMaxExponent());
104  x.Encode(privateKey, StaticPrivateKeyLength());
105  Element y = params.ExponentiateBase(x);
106  params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
107  }
108 
109  //! return length of ephemeral public keys in this domain
110  void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
111  {
112  CRYPTOPP_UNUSED(rng);
113  memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
114  }
115 
116  //! derive agreed value from your private keys and couterparty's public keys, return false in case of failure
117  /*! \note The ephemeral public key will always be validated.
118  If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time.
119  \pre size of agreedValue == AgreedValueLength()
120  \pre length of staticPrivateKey == StaticPrivateKeyLength()
121  \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength()
122  \pre length of staticOtherPublicKey == StaticPublicKeyLength()
123  \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength()
124  */
125  bool Agree(byte *agreedValue,
126  const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
127  const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
128  bool validateStaticOtherPublicKey=true) const
129  {
130  byte *XX = NULL, *YY = NULL, *AA = NULL, *BB = NULL;
131  size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
132 
133  // Depending on the role, this will hold either A's or B's static
134  // (long term) public key. AA or BB will then point into tt.
135  SecByteBlock tt(StaticPublicKeyLength());
136 
137  try
138  {
139  const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
140 
141  if(m_role == RoleServer)
142  {
143  Integer b(staticPrivateKey, StaticPrivateKeyLength());
144  Element B = params.ExponentiateBase(b);
145  params.EncodeElement(true, B, tt);
146 
147  XX = const_cast<byte*>(ephemeralOtherPublicKey);
148  xxs = EphemeralPublicKeyLength();
149  YY = const_cast<byte*>(ephemeralPrivateKey) + StaticPrivateKeyLength();
150  yys = EphemeralPublicKeyLength();
151  AA = const_cast<byte*>(staticOtherPublicKey);
152  aas = StaticPublicKeyLength();
153  BB = tt.BytePtr();
154  bbs = tt.SizeInBytes();
155  }
156  else if(m_role == RoleClient)
157  {
158  Integer a(staticPrivateKey, StaticPrivateKeyLength());
159  Element A = params.ExponentiateBase(a);
160  params.EncodeElement(true, A, tt);
161 
162  XX = const_cast<byte*>(ephemeralPrivateKey) + StaticPrivateKeyLength();
163  xxs = EphemeralPublicKeyLength();
164  YY = const_cast<byte*>(ephemeralOtherPublicKey);
165  yys = EphemeralPublicKeyLength();
166  AA = tt.BytePtr();
167  aas = tt.SizeInBytes();
168  BB = const_cast<byte*>(staticOtherPublicKey);
169  bbs = StaticPublicKeyLength();
170  }
171  else
172  {
173  assert(0);
174  return false;
175  }
176 
177  // DecodeElement calls ValidateElement at level 1. Level 1 only calls
178  // VerifyPoint to ensure the element is in G*. If the other's PublicKey is
179  // requested to be validated, we manually call ValidateElement at level 3.
180  Element VV1 = params.DecodeElement(staticOtherPublicKey, false);
181  if(!params.ValidateElement(validateStaticOtherPublicKey ? 3 : 1, VV1, NULL))
182  return false;
183 
184  // DecodeElement calls ValidateElement at level 1. Level 1 only calls
185  // VerifyPoint to ensure the element is in G*. Crank it up.
186  Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, false);
187  if(!params.ValidateElement(3, VV2, NULL))
188  return false;
189 
190  // const Integer& p = params.GetGroupOrder(); // not used, remove later
191  const Integer& q = params.GetSubgroupOrder();
192  const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
193 
194  Integer d, e;
195  SecByteBlock dd(len), ee(len);
196 
197  // Compute $d = \hat{H}(X, \hat{B})$
198  Hash(NULL, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
199  d.Decode(dd.BytePtr(), dd.SizeInBytes());
200 
201  // Compute $e = \hat{H}(Y, \hat{A})$
202  Hash(NULL, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes());
203  e.Decode(ee.BytePtr(), ee.SizeInBytes());
204 
205  Element sigma;
206  if(m_role == RoleServer)
207  {
208  Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
209  Integer b(staticPrivateKey, StaticPrivateKeyLength());
210  Integer s_B = (y + e * b) % q;
211 
212  Element A = params.DecodeElement(AA, false);
213  Element X = params.DecodeElement(XX, false);
214 
215  Element t1 = params.ExponentiateElement(A, d);
216  Element t2 = m_groupParameters.MultiplyElements(X, t1);
217 
218  // $\sigma_B}=(X \cdot A^{d})^{s_B}
219  sigma = params.ExponentiateElement(t2, s_B);
220  }
221  else
222  {
223  Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
224  Integer a(staticPrivateKey, StaticPrivateKeyLength());
225  Integer s_A = (x + d * a) % q;
226 
227  Element B = params.DecodeElement(BB, false);
228  Element Y = params.DecodeElement(YY, false);
229 
230  Element t1 = params.ExponentiateElement(B, e);
231  Element t2 = m_groupParameters.MultiplyElements(Y, t1);
232 
233  // $\sigma_A}=(Y \cdot B^{e})^{s_A}
234  sigma = params.ExponentiateElement(t2, s_A);
235  }
236  Hash(&sigma, NULL, 0, NULL, 0, agreedValue, AgreedValueLength());
237  }
238  catch (DL_BadElement &)
239  {
240  return false;
241  }
242  return true;
243  }
244 
245 protected:
246  // Hash invocation by client and server differ only in what keys
247  // each provides.
248 
249  inline void Hash(const Element* sigma,
250  const byte* e1, size_t e1len, // Ephemeral key and key length
251  const byte* s1, size_t s1len, // Static key and key length
252  byte* digest, size_t dlen) const
253  {
254  HASH hash;
255  size_t idx = 0, req = dlen;
256  size_t blk = std::min(dlen, (size_t)HASH::DIGESTSIZE);
257 
258  if(sigma)
259  {
260  if (e1len != 0 || s1len != 0) {
261  assert(0);
262  }
263  Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
264  SecByteBlock sbb(x.MinEncodedSize());
265  x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
266  hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
267  } else {
268  if (e1len == 0 || s1len == 0) {
269  assert(0);
270  }
271  hash.Update(e1, e1len);
272  hash.Update(s1, s1len);
273  }
274 
275  hash.TruncatedFinal(digest, blk);
276  req -= blk;
277 
278  // All this to catch tail bytes for large curves and small hashes
279  while(req != 0)
280  {
281  hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
282 
283  idx += (size_t)HASH::DIGESTSIZE;
284  blk = std::min(req, (size_t)HASH::DIGESTSIZE);
285  hash.TruncatedFinal(&digest[idx], blk);
286 
287  req -= blk;
288  }
289  }
290 
291 private:
292 
293  // The paper uses Initiator and Recipient - make it classical.
294  enum KeyAgreementRole{ RoleServer = 1, RoleClient };
295 
296  DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
297  const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
298 
299  GroupParameters m_groupParameters;
300  KeyAgreementRole m_role;
301 };
302 
303 //! \brief Hashed Menezes-Qu-Vanstone in GF(p)
304 //! \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
305 //! Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
306 //! \sa HMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
307 //! \since Crypto++ 5.6.4
309 
310 NAMESPACE_END
311 
312 #endif
unsigned int EphemeralPrivateKeyLength() const
Provides the size of ephemeral private key.
Definition: hmqv.h:96
void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
return length of ephemeral public keys in this domain
Definition: hmqv.h:110
unsigned int AgreedValueLength() const
return length of agreed value produced
Definition: hmqv.h:71
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:538
Interface for Discrete Log (DL) group parameters.
Definition: pubkey.h:752
Hashed Menezes-Qu-Vanstone in GF(p)
Definition: hmqv.h:23
Interface for random number generators.
Definition: cryptlib.h:1186
void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
return length of ephemeral private keys in this domain
Definition: hmqv.h:100
SecBlock<byte> typedef.
Definition: secblock.h:731
Classes for performing mathematics over different fields.
Interface for buffered transformations.
Definition: cryptlib.h:1352
virtual Element ExponentiateBase(const Integer &exponent) const
Retrieves the subgroup generator.
Definition: pubkey.h:821
static const Integer & One()
Integer representing 1.
Definition: integer.cpp:3016
void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
generate static private key
Definition: hmqv.h:79
unsigned int StaticPublicKeyLength() const
return length of static public keys in this domain
Definition: hmqv.h:75
bool Agree(byte *agreedValue, const byte *staticPrivateKey, const byte *ephemeralPrivateKey, const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, bool validateStaticOtherPublicKey=true) const
derive agreed value from your private keys and couterparty&#39;s public keys, return false in case of fai...
Definition: hmqv.h:125
size_t MinEncodedSize(Signedness sign=UNSIGNED) const
The minimum number of bytes to encode this integer.
Definition: integer.cpp:3338
CryptoParameters & AccessCryptoParameters()
Retrieves a reference to Crypto Parameters.
Definition: hmqv.h:68
implements the SHA-512 standard
Definition: sha.h:56
HMQV_Domain< DL_GroupParameters_GFP_DefaultSafePrime > HMQV
Hashed Menezes-Qu-Vanstone in GF(p)
Definition: hmqv.h:308
Multiple precision integer with arithmetic operations.
Definition: integer.h:45
Implementation of schemes based on DL over GF(p)
virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0
Decodes the element.
Exception thrown when an invalid group element is encountered.
Definition: pubkey.h:742
virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation< Element > *precomp) const =0
Check the element for errors.
Classes for SHA-1 and SHA-2 family of message digests.
unsigned int BitCount() const
Determines the number of bits required to represent the Integer.
Definition: integer.cpp:3289
void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const
Encode in big-endian format.
Definition: integer.cpp:3350
virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0
Encodes the element.
void Decode(const byte *input, size_t inputLen, Signedness sign=UNSIGNED)
Decode from big-endian byte array.
Definition: integer.cpp:3298
Interface for crypto prameters.
Definition: cryptlib.h:2196
virtual Integer GetMaxExponent() const =0
Retrieves the maximum exponent for the group.
unsigned int EphemeralPublicKeyLength() const
Provides the size of ephemeral public key.
Definition: hmqv.h:97
Crypto++ library namespace.
Interface for domains of authenticated key agreement protocols.
Definition: cryptlib.h:2747
virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const
Exponentiates an element.
Definition: pubkey.h:831
void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
generate static public key
Definition: hmqv.h:87
unsigned int StaticPrivateKeyLength() const
return length of static private keys in this domain
Definition: hmqv.h:73
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:531
virtual const Integer & GetSubgroupOrder() const =0
Retrieves the subgroup order.