Crypto++ 8.2
Free C&
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
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 = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
25{
26public:
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
62public:
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);
149 YY = const_cast<byte*>(ephemeralPrivateKey) + StaticPrivateKeyLength();
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();
164 YY = const_cast<byte*>(ephemeralOtherPublicKey);
166 AA = tt.BytePtr();
167 aas = tt.SizeInBytes();
168 BB = const_cast<byte*>(staticOtherPublicKey);
169 bbs = StaticPublicKeyLength();
170 }
171 else
172 {
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
241protected:
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
281private:
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
301NAMESPACE_END
302
303#endif
Classes for performing mathematics over different fields.
Interface for domains of authenticated key agreement protocols.
Definition: cryptlib.h:2957
Interface for buffered transformations.
Definition: cryptlib.h:1599
void DoQuickSanityCheck() const
Perform a quick sanity check.
Definition: cryptlib.h:2387
Interface for crypto prameters.
Definition: cryptlib.h:2436
Exception thrown when an invalid group element is encountered.
Definition: pubkey.h:744
Interface for Discrete Log (DL) group parameters.
Definition: pubkey.h:754
virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const
Exponentiates an element.
Definition: pubkey.h:849
virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation< Element > *precomp) const =0
Check the element for errors.
virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0
Encodes the element.
virtual Integer GetMaxExponent() const =0
Retrieves the maximum exponent for the group.
virtual const Integer & GetSubgroupOrder() const =0
Retrieves the subgroup order.
virtual Element ExponentiateBase(const Integer &exponent) const
Exponentiates the base.
Definition: pubkey.h:839
virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0
Decodes the element.
Fully Hashed Menezes-Qu-Vanstone in GF(p)
Definition: fhmqv.h:25
unsigned int AgreedValueLength() const
return length of agreed value produced
Definition: fhmqv.h:70
unsigned int EphemeralPublicKeyLength() const
Provides the size of ephemeral public key.
Definition: fhmqv.h:96
CryptoParameters & AccessCryptoParameters()
Retrieves a reference to Crypto Parameters.
Definition: fhmqv.h:67
void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
generate static public key
Definition: fhmqv.h:86
unsigned int EphemeralPrivateKeyLength() const
Provides the size of ephemeral private key.
Definition: fhmqv.h:95
void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
return length of ephemeral public keys in this domain
Definition: fhmqv.h:109
void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
generate static private key
Definition: fhmqv.h:78
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's public keys, return false in case of fai...
Definition: fhmqv.h:124
void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
return length of ephemeral private keys in this domain
Definition: fhmqv.h:99
unsigned int StaticPrivateKeyLength() const
return length of static private keys in this domain
Definition: fhmqv.h:72
unsigned int StaticPublicKeyLength() const
return length of static public keys in this domain
Definition: fhmqv.h:74
Multiple precision integer with arithmetic operations.
Definition: integer.h:50
unsigned int BitCount() const
Determines the number of bits required to represent the Integer.
Definition: integer.cpp:3345
static const Integer & One()
Integer representing 1.
Definition: integer.cpp:4877
const CryptoMaterial & GetMaterial() const
Retrieves a reference to Crypto Parameters.
Definition: cryptlib.h:2532
Interface for random number generators.
Definition: cryptlib.h:1384
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:811
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:804
SecBlock<byte> typedef.
Definition: secblock.h:1058
FHMQV_Domain< DL_GroupParameters_GFP_DefaultSafePrime > FHMQV
Fully Hashed Menezes-Qu-Vanstone in GF(p)
Definition: fhmqv.h:299
Classes and functions for schemes based on Discrete Logs (DL) over GF(p)
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:567
Crypto++ library namespace.
Classes for SHA-1 and SHA-2 family of message digests.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69