Crypto++  7.0
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  {
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& q = params.GetSubgroupOrder();
190  const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
191 
192  Integer d, e;
193  SecByteBlock dd(len), ee(len);
194 
195  Hash(NULLPTR, XX, xxs, YY, yys, AA, aas, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
196  d.Decode(dd.BytePtr(), dd.SizeInBytes());
197 
198  Hash(NULLPTR, YY, yys, XX, xxs, AA, aas, BB, bbs, ee.BytePtr(), ee.SizeInBytes());
199  e.Decode(ee.BytePtr(), ee.SizeInBytes());
200 
201  Element sigma;
202  if(m_role == RoleServer)
203  {
204  Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
205  Integer b(staticPrivateKey, StaticPrivateKeyLength());
206  Integer s_B = (y + e * b) % q;
207 
208  Element A = params.DecodeElement(AA, false);
209  Element X = params.DecodeElement(XX, false);
210 
211  Element t1 = params.ExponentiateElement(A, d);
212  Element t2 = m_groupParameters.MultiplyElements(X, t1);
213 
214  sigma = params.ExponentiateElement(t2, s_B);
215  }
216  else
217  {
218  Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
219  Integer a(staticPrivateKey, StaticPrivateKeyLength());
220  Integer s_A = (x + d * a) % q;
221 
222  Element B = params.DecodeElement(BB, false);
223  Element Y = params.DecodeElement(YY, false);
224 
225  Element t1 = params.ExponentiateElement(B, e);
226  Element t2 = m_groupParameters.MultiplyElements(Y, t1);
227 
228  sigma = params.ExponentiateElement(t2, s_A);
229  }
230 
231  Hash(&sigma, XX, xxs, YY, yys, AA, aas, BB, bbs, agreedValue, AgreedValueLength());
232  }
233  catch (DL_BadElement &)
234  {
235  return false;
236  }
237  return true;
238  }
239 
240 protected:
241 
242  inline void Hash(const Element* sigma,
243  const byte* e1, size_t e1len, const byte* e2, size_t e2len,
244  const byte* s1, size_t s1len, const byte* s2, size_t s2len,
245  byte* digest, size_t dlen) const
246  {
247  HASH hash;
248  size_t idx = 0, req = dlen;
249  size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
250 
251  if(sigma)
252  {
253  Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
254  SecByteBlock sbb(x.MinEncodedSize());
255  x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
256  hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
257  }
258 
259  hash.Update(e1, e1len);
260  hash.Update(e2, e2len);
261  hash.Update(s1, s1len);
262  hash.Update(s2, s2len);
263 
264  hash.TruncatedFinal(digest, blk);
265  req -= blk;
266 
267  // All this to catch tail bytes for large curves and small hashes
268  while(req != 0)
269  {
270  hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
271 
272  idx += (size_t)HASH::DIGESTSIZE;
273  blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
274  hash.TruncatedFinal(&digest[idx], blk);
275 
276  req -= blk;
277  }
278  }
279 
280 private:
281 
282  // The paper uses Initiator and Recipient - make it classical.
283  enum KeyAgreementRole{ RoleServer = 1, RoleClient };
284 
285  DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
286  const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
287 
288  GroupParameters m_groupParameters;
289  KeyAgreementRole m_role;
290 };
291 
292 /// \brief Fully Hashed Menezes-Qu-Vanstone in GF(p)
293 /// \details This implementation follows Augustin P. Sarr and Philippe Elbaz–Vincent, and Jean–Claude Bajard's
294 /// <a href="http://eprint.iacr.org/2009/408">A Secure and Efficient Authenticated Diffie-Hellman Protocol</a>.
295 /// Note: this is FHMQV, Protocol 5, from page 11; and not FHMQV-C.
296 /// \sa FHMQV, MQV_Domain, HMQV_Domain, AuthenticatedKeyAgreementDomain
297 /// \since Crypto++ 5.6.4
299 
300 NAMESPACE_END
301 
302 #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:805
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:1349
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:1052
Classes for performing mathematics over different fields.
Interface for buffered transformations.
Definition: cryptlib.h:1564
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:4854
unsigned int StaticPrivateKeyLength() const
return length of static private keys in this domain
Definition: fhmqv.h:72
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:563
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:60
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:3340
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:2401
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:2922
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:298
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:798
virtual const Integer & GetSubgroupOrder() const =0
Retrieves the subgroup order.