Crypto++  8.2
Free C++ class library of cryptographic schemes
fhmqv.h
Go to the documentation of this file.
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 
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>
25 {
26 public:
27  typedef GROUP_PARAMETERS GroupParameters;
28  typedef typename GroupParameters::Element Element;
30 
31  virtual ~FHMQV_Domain() {}
32 
33  FHMQV_Domain(bool clientRole = true): m_role(clientRole ? RoleClient : RoleServer) {}
34 
35  FHMQV_Domain(const GroupParameters &params, bool clientRole = true)
36  : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
37 
38  FHMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
39  : m_role(clientRole ? RoleClient : RoleServer)
40  {m_groupParameters.BERDecode(bt);}
41 
42  template <class T1>
43  FHMQV_Domain(T1 v1, bool clientRole = true)
44  : m_role(clientRole ? RoleClient : RoleServer)
45  {m_groupParameters.Initialize(v1);}
46 
47  template <class T1, class T2>
48  FHMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
49  : m_role(clientRole ? RoleClient : RoleServer)
50  {m_groupParameters.Initialize(v1, v2);}
51 
52  template <class T1, class T2, class T3>
53  FHMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
54  : m_role(clientRole ? RoleClient : RoleServer)
55  {m_groupParameters.Initialize(v1, v2, v3);}
56 
57  template <class T1, class T2, class T3, class T4>
58  FHMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
59  : m_role(clientRole ? RoleClient : RoleServer)
60  {m_groupParameters.Initialize(v1, v2, v3, v4);}
61 
62 public:
63 
64  const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
65  GroupParameters & AccessGroupParameters(){return m_groupParameters;}
66 
67  CryptoParameters & AccessCryptoParameters(){return AccessAbstractGroupParameters();}
68 
69  /// return length of agreed value produced
70  unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
71  /// return length of static private keys in this domain
72  unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
73  /// return length of static public keys in this domain
74  unsigned int StaticPublicKeyLength() const{return GetAbstractGroupParameters().GetEncodedElementSize(true);}
75 
76  /// generate static private key
77  /*! \pre size of privateKey == PrivateStaticKeyLength() */
78  void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
79  {
80  Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
81  x.Encode(privateKey, StaticPrivateKeyLength());
82  }
83 
84  /// generate static public key
85  /*! \pre size of publicKey == PublicStaticKeyLength() */
86  void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
87  {
88  CRYPTOPP_UNUSED(rng);
89  const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
90  Integer x(privateKey, StaticPrivateKeyLength());
91  Element y = params.ExponentiateBase(x);
92  params.EncodeElement(true, y, publicKey);
93  }
94 
96  unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
97 
98  /// return length of ephemeral private keys in this domain
99  void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
100  {
101  const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
102  Integer x(rng, Integer::One(), params.GetMaxExponent());
103  x.Encode(privateKey, StaticPrivateKeyLength());
104  Element y = params.ExponentiateBase(x);
105  params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
106  }
107 
108  /// return length of ephemeral public keys in this domain
109  void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
110  {
111  CRYPTOPP_UNUSED(rng);
112  memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
113  }
114 
115  /// derive agreed value from your private keys and couterparty's public keys, return false in case of failure
116  /*! \note The ephemeral public key will always be validated.
117  If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time.
118  \pre size of agreedValue == AgreedValueLength()
119  \pre length of staticPrivateKey == StaticPrivateKeyLength()
120  \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength()
121  \pre length of staticOtherPublicKey == StaticPublicKeyLength()
122  \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength()
123  */
124  bool Agree(byte *agreedValue,
125  const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
126  const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
127  bool validateStaticOtherPublicKey=true) const
128  {
129  byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
130  size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
131 
132  // Depending on the role, this will hold either A's or B's static
133  // (long term) public key. AA or BB will then point into tt.
135 
136  try
137  {
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  CRYPTOPP_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, NULLPTR))
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, NULLPTR))
188  return false;
189 
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  Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
197  d.Decode(dd.BytePtr(), dd.SizeInBytes());
198 
199  Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes());
200  e.Decode(ee.BytePtr(), ee.SizeInBytes());
201 
202  Element sigma;
203  if(m_role == RoleServer)
204  {
205  Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
206  Integer b(staticPrivateKey, StaticPrivateKeyLength());
207  Integer s_B = (y + e * b) % q;
208 
209  Element A = params.DecodeElement(AA, false);
210  Element X = params.DecodeElement(XX, false);
211 
212  Element t1 = params.ExponentiateElement(A, d);
213  Element t2 = m_groupParameters.MultiplyElements(X, t1);
214 
215  sigma = params.ExponentiateElement(t2, s_B);
216  }
217  else
218  {
219  Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
220  Integer a(staticPrivateKey, StaticPrivateKeyLength());
221  Integer s_A = (x + d * a) % q;
222 
223  Element B = params.DecodeElement(BB, false);
224  Element Y = params.DecodeElement(YY, false);
225 
226  Element t1 = params.ExponentiateElement(B, e);
227  Element t2 = m_groupParameters.MultiplyElements(Y, t1);
228 
229  sigma = params.ExponentiateElement(t2, s_A);
230  }
231 
232  Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength());
233  }
234  catch (DL_BadElement &)
235  {
236  return false;
237  }
238  return true;
239  }
240 
241 protected:
242 
243  inline void Hash(const Element* sigma,
244  const byte* e1, size_t e1len, const byte* e2, size_t e2len,
245  const byte* s1, size_t s1len, const byte* s2, size_t s2len,
246  byte* digest, size_t dlen) const
247  {
248  HASH hash;
249  size_t idx = 0, req = dlen;
250  size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
251 
252  if(sigma)
253  {
254  Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
255  SecByteBlock sbb(x.MinEncodedSize());
256  x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
257  hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
258  }
259 
260  hash.Update(e1, e1len);
261  hash.Update(e2, e2len);
262  hash.Update(s1, s1len);
263  hash.Update(s2, s2len);
264 
265  hash.TruncatedFinal(digest, blk);
266  req -= blk;
267 
268  // All this to catch tail bytes for large curves and small hashes
269  while(req != 0)
270  {
271  hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
272 
273  idx += (size_t)HASH::DIGESTSIZE;
274  blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
275  hash.TruncatedFinal(&digest[idx], blk);
276 
277  req -= blk;
278  }
279  }
280 
281 private:
282 
283  // The paper uses Initiator and Recipient - make it classical.
284  enum KeyAgreementRole{ RoleServer = 1, RoleClient };
285 
286  DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
287  const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
288 
289  GroupParameters m_groupParameters;
290  KeyAgreementRole m_role;
291 };
292 
293 /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
294 /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
295 /// <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
296 /// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
297 /// \sa FHMQV, MQV_Domain, HMQV_Domain, AuthenticatedKeyAgreementDomain
298 /// \since Crypto++ 5.6.4
300 
301 NAMESPACE_END
302 
303 #endif
void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
generate static public key
Definition: fhmqv.h:86
unsigned int StaticPublicKeyLength() const
return length of static public keys in this domain
Definition: fhmqv.h:74
unsigned int EphemeralPrivateKeyLength() const
Provides the size of ephemeral private key.
Definition: fhmqv.h:95
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
Fully Hashed Menezes-Qu-Vanstone in GF(p)
Definition: fhmqv.h:24
Interface for Discrete Log (DL) group parameters.
Definition: pubkey.h:753
void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
return length of ephemeral public keys in this domain
Definition: fhmqv.h:109
Interface for random number generators.
Definition: cryptlib.h:1383
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: fhmqv.h:124
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
void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
return length of ephemeral private keys in this domain
Definition: fhmqv.h:99
static const Integer & One()
Integer representing 1.
Definition: integer.cpp:4877
unsigned int StaticPrivateKeyLength() const
return length of static private keys in this domain
Definition: fhmqv.h:72
void DoQuickSanityCheck() const
Perform a quick sanity check.
Definition: cryptlib.h:2387
unsigned int AgreedValueLength() const
return length of agreed value produced
Definition: fhmqv.h:70
void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
generate static private key
Definition: fhmqv.h:78
Multiple precision integer with arithmetic operations.
Definition: integer.h:49
CryptoParameters & AccessCryptoParameters()
Retrieves a reference to Crypto Parameters.
Definition: fhmqv.h:67
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:567
#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
unsigned int EphemeralPublicKeyLength() const
Provides the size of ephemeral public key.
Definition: fhmqv.h:96
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.
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
FHMQV_Domain< DL_GroupParameters_GFP_DefaultSafePrime > FHMQV
Fully Hashed Menezes-Qu-Vanstone in GF(p)
Definition: fhmqv.h:299
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.