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