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