source: trunk/src-cryptopp/hmqv.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: 12.0 KB
Line 
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
15NAMESPACE_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
22template <class GROUP_PARAMETERS, class COFACTOR_OPTION = CPP_TYPENAME GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
23class HMQV_Domain: public AuthenticatedKeyAgreementDomain
24{
25public:
26  typedef GROUP_PARAMETERS GroupParameters;
27  typedef typename GroupParameters::Element Element;
28  typedef HMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
29
30#ifndef CRYPTOPP_MAINTAIN_BACKWARDS_COMPATIBILITY_562
31        virtual ~HMQV_Domain() {}
32#endif
33
34  HMQV_Domain(bool clientRole = true): m_role(clientRole ? RoleClient : RoleServer) {}
35
36  HMQV_Domain(const GroupParameters &params, bool clientRole = true)
37    : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
38
39  HMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
40    : m_role(clientRole ? RoleClient : RoleServer)
41  {m_groupParameters.BERDecode(bt);}
42
43  template <class T1>
44  HMQV_Domain(T1 v1, bool clientRole = true)
45    : m_role(clientRole ? RoleClient : RoleServer)
46  {m_groupParameters.Initialize(v1);}
47
48  template <class T1, class T2>
49  HMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
50    : m_role(clientRole ? RoleClient : RoleServer)
51  {m_groupParameters.Initialize(v1, v2);}
52
53  template <class T1, class T2, class T3>
54  HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
55    : m_role(clientRole ? RoleClient : RoleServer)
56  {m_groupParameters.Initialize(v1, v2, v3);}
57
58  template <class T1, class T2, class T3, class T4>
59  HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
60    : m_role(clientRole ? RoleClient : RoleServer)
61  {m_groupParameters.Initialize(v1, v2, v3, v4);}
62
63public:
64
65  const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
66  GroupParameters & AccessGroupParameters(){return m_groupParameters;}
67
68  CryptoParameters & AccessCryptoParameters(){return AccessAbstractGroupParameters();}
69
70  //! return length of agreed value produced
71  unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
72  //! return length of static private keys in this domain
73  unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
74  //! return length of static public keys in this domain
75  unsigned int StaticPublicKeyLength() const{return GetAbstractGroupParameters().GetEncodedElementSize(true);}
76
77  //! generate static private key
78  /*! \pre size of privateKey == PrivateStaticKeyLength() */
79  void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
80  {
81    Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
82    x.Encode(privateKey, StaticPrivateKeyLength());
83  }
84
85  //! generate static public key
86  /*! \pre size of publicKey == PublicStaticKeyLength() */
87  void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
88  {
89    CRYPTOPP_UNUSED(rng);
90    const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
91    Integer x(privateKey, StaticPrivateKeyLength());
92    Element y = params.ExponentiateBase(x);
93    params.EncodeElement(true, y, publicKey);
94  }
95
96  unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
97  unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
98
99  //! return length of ephemeral private keys in this domain
100  void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
101  {
102    const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
103    Integer x(rng, Integer::One(), params.GetMaxExponent());
104    x.Encode(privateKey, StaticPrivateKeyLength());
105    Element y = params.ExponentiateBase(x);
106    params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
107  }
108
109  //! return length of ephemeral public keys in this domain
110  void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
111  {
112    CRYPTOPP_UNUSED(rng);
113    memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
114  }
115
116  //! derive agreed value from your private keys and couterparty's public keys, return false in case of failure
117  /*! \note The ephemeral public key will always be validated.
118  If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time.
119  \pre size of agreedValue == AgreedValueLength()
120  \pre length of staticPrivateKey == StaticPrivateKeyLength()
121  \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength()
122  \pre length of staticOtherPublicKey == StaticPublicKeyLength()
123  \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength()
124  */
125  bool Agree(byte *agreedValue,
126    const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
127    const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
128    bool validateStaticOtherPublicKey=true) const
129  {
130    byte *XX = NULL, *YY = NULL, *AA = NULL, *BB = NULL;
131    size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
132
133    // Depending on the role, this will hold either A's or B's static
134    // (long term) public key. AA or BB will then point into tt.
135    SecByteBlock tt(StaticPublicKeyLength());
136
137    try
138    {
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, NULL))
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, NULL))
188        return false;
189
190      // const Integer& p = params.GetGroupOrder(); // not used, remove later
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      // Compute $d = \hat{H}(X, \hat{B})$
198      Hash(NULL, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
199      d.Decode(dd.BytePtr(), dd.SizeInBytes());
200
201      // Compute $e = \hat{H}(Y, \hat{A})$
202      Hash(NULL, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes());
203      e.Decode(ee.BytePtr(), ee.SizeInBytes());
204
205      Element sigma;
206      if(m_role == RoleServer)
207      {
208        Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
209        Integer b(staticPrivateKey, StaticPrivateKeyLength());
210        Integer s_B = (y + e * b) % q;
211
212        Element A = params.DecodeElement(AA, false);
213        Element X = params.DecodeElement(XX, false);
214
215        Element t1 = params.ExponentiateElement(A, d);
216        Element t2 = m_groupParameters.MultiplyElements(X, t1);
217
218        // $\sigma_B}=(X \cdot A^{d})^{s_B}
219        sigma = params.ExponentiateElement(t2, s_B);
220      }
221      else
222      {
223        Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
224        Integer a(staticPrivateKey, StaticPrivateKeyLength());
225        Integer s_A = (x + d * a) % q;
226
227        Element B = params.DecodeElement(BB, false);
228        Element Y = params.DecodeElement(YY, false);
229
230        Element t1 = params.ExponentiateElement(B, e);
231        Element t2 = m_groupParameters.MultiplyElements(Y, t1);
232
233        // $\sigma_A}=(Y \cdot B^{e})^{s_A}
234        sigma = params.ExponentiateElement(t2, s_A);
235      }
236      Hash(&sigma, NULL, 0, NULL, 0, agreedValue, AgreedValueLength());
237    }
238    catch (DL_BadElement &)
239    {
240      return false;
241    }
242    return true;
243  }
244
245protected:
246  // Hash invocation by client and server differ only in what keys
247  // each provides.
248
249  inline void Hash(const Element* sigma,
250    const byte* e1, size_t e1len, // Ephemeral key and key length
251    const byte* s1, size_t s1len, // Static key and key length
252    byte* digest, size_t dlen) const
253  {
254    HASH hash;
255    size_t idx = 0, req = dlen;
256    size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
257
258    if(sigma)
259    {
260      if (e1len != 0 || s1len != 0) {
261        CRYPTOPP_ASSERT(0);
262      }
263      Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
264      SecByteBlock sbb(x.MinEncodedSize());
265      x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
266      hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
267    } else {
268      if (e1len == 0 || s1len == 0) {
269        CRYPTOPP_ASSERT(0);
270      }
271      hash.Update(e1, e1len);
272      hash.Update(s1, s1len);
273    }
274
275    hash.TruncatedFinal(digest, blk);
276    req -= blk;
277
278    // All this to catch tail bytes for large curves and small hashes
279    while(req != 0)
280    {
281      hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
282
283      idx += (size_t)HASH::DIGESTSIZE;
284      blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
285      hash.TruncatedFinal(&digest[idx], blk);
286
287      req -= blk;
288    }
289  }
290
291private:
292
293  // The paper uses Initiator and Recipient - make it classical.
294  enum KeyAgreementRole{ RoleServer = 1, RoleClient };
295
296  DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
297  const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
298
299  GroupParameters m_groupParameters;
300  KeyAgreementRole m_role;
301};
302
303//! \brief Hashed Menezes-Qu-Vanstone in GF(p)
304//! \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
305//!   Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
306//! \sa HMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
307//! \since Crypto++ 5.6.4
308typedef HMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> HMQV;
309
310NAMESPACE_END
311
312#endif
Note: See TracBrowser for help on using the repository browser.