source: git/src-cryptopp/fhmqv.h

Last change on this file was e230cb0, checked in by David Stainton <dstainton415@…>, at 2016-10-12T13:27:29Z

Add cryptopp from tag CRYPTOPP_5_6_5

  • Property mode set to 100644
File size: 11.8 KB
Line 
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
15NAMESPACE_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
23template <class GROUP_PARAMETERS, class COFACTOR_OPTION = CPP_TYPENAME GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
24class FHMQV_Domain : public AuthenticatedKeyAgreementDomain
25{
26public:
27  typedef GROUP_PARAMETERS GroupParameters;
28  typedef typename GroupParameters::Element Element;
29  typedef FHMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
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
64public:
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        CRYPTOPP_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
242protected:
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 = STDMIN(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 = STDMIN(req, (size_t)HASH::DIGESTSIZE);
276      hash.TruncatedFinal(&digest[idx], blk);
277
278      req -= blk;
279    }
280  }
281
282private:
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
300typedef FHMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> FHMQV;
301
302NAMESPACE_END
303
304#endif
Note: See TracBrowser for help on using the repository browser.