Crypto++ 8.0 Free C++ class library of cryptographic schemes

hmqv.h
Go to the documentation of this file.
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
15 NAMESPACE_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
22 template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
23 class HMQV_Domain: public AuthenticatedKeyAgreementDomain
24 {
25 public:
26 typedef GROUP_PARAMETERS GroupParameters;
27 typedef typename GroupParameters::Element Element;
28 typedef HMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
29
30 virtual ~HMQV_Domain() {}
31
32 HMQV_Domain(bool clientRole = true): m_role(clientRole ? RoleClient : RoleServer) {}
33
34 HMQV_Domain(const GroupParameters &params, bool clientRole = true)
35 : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
36
37 HMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
38 : m_role(clientRole ? RoleClient : RoleServer)
39 {m_groupParameters.BERDecode(bt);}
40
41 template <class T1>
42 HMQV_Domain(T1 v1, bool clientRole = true)
43 : m_role(clientRole ? RoleClient : RoleServer)
44 {m_groupParameters.Initialize(v1);}
45
46 template <class T1, class T2>
47 HMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
48 : m_role(clientRole ? RoleClient : RoleServer)
49 {m_groupParameters.Initialize(v1, v2);}
50
51 template <class T1, class T2, class T3>
52 HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
53 : m_role(clientRole ? RoleClient : RoleServer)
54 {m_groupParameters.Initialize(v1, v2, v3);}
55
56 template <class T1, class T2, class T3, class T4>
57 HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
58 : m_role(clientRole ? RoleClient : RoleServer)
59 {m_groupParameters.Initialize(v1, v2, v3, v4);}
60
61 public:
62
63 const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
64 GroupParameters & AccessGroupParameters(){return m_groupParameters;}
65
66 CryptoParameters & AccessCryptoParameters(){return AccessAbstractGroupParameters();}
67
68 /// return length of agreed value produced
69 unsigned int AgreedValueLength() const {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
70 /// return length of static private keys in this domain
71 unsigned int StaticPrivateKeyLength() const {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
72 /// return length of static public keys in this domain
73 unsigned int StaticPublicKeyLength() const{return GetAbstractGroupParameters().GetEncodedElementSize(true);}
74
75 /// generate static private key
76 /*! \pre size of privateKey == PrivateStaticKeyLength() */
77 void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
78 {
79 Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
80 x.Encode(privateKey, StaticPrivateKeyLength());
81 }
82
83 /// generate static public key
84 /*! \pre size of publicKey == PublicStaticKeyLength() */
85 void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
86 {
87 CRYPTOPP_UNUSED(rng);
88 const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
89 Integer x(privateKey, StaticPrivateKeyLength());
90 Element y = params.ExponentiateBase(x);
91 params.EncodeElement(true, y, publicKey);
92 }
93
94 unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
95 unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
96
97 /// return length of ephemeral private keys in this domain
98 void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
99 {
100 const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
101 Integer x(rng, Integer::One(), params.GetMaxExponent());
102 x.Encode(privateKey, StaticPrivateKeyLength());
103 Element y = params.ExponentiateBase(x);
104 params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
105 }
106
107 /// return length of ephemeral public keys in this domain
108 void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
109 {
110 CRYPTOPP_UNUSED(rng);
111 memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
112 }
113
114 /// derive agreed value from your private keys and couterparty's public keys, return false in case of failure
115 /*! \note The ephemeral public key will always be validated.
116 If you have previously validated the static public key, use validateStaticOtherPublicKey=false to save time.
117 \pre size of agreedValue == AgreedValueLength()
118 \pre length of staticPrivateKey == StaticPrivateKeyLength()
119 \pre length of ephemeralPrivateKey == EphemeralPrivateKeyLength()
120 \pre length of staticOtherPublicKey == StaticPublicKeyLength()
121 \pre length of ephemeralOtherPublicKey == EphemeralPublicKeyLength()
122 */
123 bool Agree(byte *agreedValue,
124 const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
125 const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
126 bool validateStaticOtherPublicKey=true) const
127 {
128 byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
129 size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
130
131 // Depending on the role, this will hold either A's or B's static
132 // (long term) public key. AA or BB will then point into tt.
133 SecByteBlock tt(StaticPublicKeyLength());
134
135 try
136 {
137 this->GetMaterial().DoQuickSanityCheck();
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& p = params.GetGroupOrder(); // not used, remove later
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 // Compute $d = \hat{H}(X, \hat{B})$
197 Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
198 d.Decode(dd.BytePtr(), dd.SizeInBytes());
199
200 // Compute $e = \hat{H}(Y, \hat{A})$
201 Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes());
202 e.Decode(ee.BytePtr(), ee.SizeInBytes());
203
204 Element sigma;
205 if(m_role == RoleServer)
206 {
207 Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
208 Integer b(staticPrivateKey, StaticPrivateKeyLength());
209 Integer s_B = (y + e * b) % q;
210
211 Element A = params.DecodeElement(AA, false);
212 Element X = params.DecodeElement(XX, false);
213
214 Element t1 = params.ExponentiateElement(A, d);
215 Element t2 = m_groupParameters.MultiplyElements(X, t1);
216
217 // $\sigma_B}=(X \cdot A^{d})^{s_B}
218 sigma = params.ExponentiateElement(t2, s_B);
219 }
220 else
221 {
222 Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
223 Integer a(staticPrivateKey, StaticPrivateKeyLength());
224 Integer s_A = (x + d * a) % q;
225
226 Element B = params.DecodeElement(BB, false);
227 Element Y = params.DecodeElement(YY, false);
228
229 Element t1 = params.ExponentiateElement(B, e);
230 Element t2 = m_groupParameters.MultiplyElements(Y, t1);
231
232 // $\sigma_A}=(Y \cdot B^{e})^{s_A}
233 sigma = params.ExponentiateElement(t2, s_A);
234 }
235 Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength());
236 }
237 catch (DL_BadElement &)
238 {
239 return false;
240 }
241 return true;
242 }
243
244 protected:
245 // Hash invocation by client and server differ only in what keys
246 // each provides.
247
248 inline void Hash(const Element* sigma,
249 const byte* e1, size_t e1len, // Ephemeral key and key length
250 const byte* s1, size_t s1len, // Static key and key length
251 byte* digest, size_t dlen) const
252 {
253 HASH hash;
254 size_t idx = 0, req = dlen;
255 size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
256
257 if(sigma)
258 {
259 if (e1len != 0 || s1len != 0) {
260 CRYPTOPP_ASSERT(0);
261 }
262 Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
263 SecByteBlock sbb(x.MinEncodedSize());
264 x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
265 hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
266 } else {
267 if (e1len == 0 || s1len == 0) {
268 CRYPTOPP_ASSERT(0);
269 }
270 hash.Update(e1, e1len);
271 hash.Update(s1, s1len);
272 }
273
274 hash.TruncatedFinal(digest, blk);
275 req -= blk;
276
277 // All this to catch tail bytes for large curves and small hashes
278 while(req != 0)
279 {
280 hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
281
282 idx += (size_t)HASH::DIGESTSIZE;
283 blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
284 hash.TruncatedFinal(&digest[idx], blk);
285
286 req -= blk;
287 }
288 }
289
290 private:
291
292 // The paper uses Initiator and Recipient - make it classical.
293 enum KeyAgreementRole{ RoleServer = 1, RoleClient };
294
295 DL_GroupParameters<Element> & AccessAbstractGroupParameters() {return m_groupParameters;}
296 const DL_GroupParameters<Element> & GetAbstractGroupParameters() const{return m_groupParameters;}
297
298 GroupParameters m_groupParameters;
299 KeyAgreementRole m_role;
300 };
301
302 /// \brief Hashed Menezes-Qu-Vanstone in GF(p)
303 /// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
304 /// Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
305 /// \sa HMQV, MQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
306 /// \since Crypto++ 5.6.4
307 typedef HMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> HMQV;
308
309 NAMESPACE_END
310
311 #endif
HMQV_Domain::EphemeralPrivateKeyLength
unsigned int EphemeralPrivateKeyLength() const
Provides the size of ephemeral private key.
Definition: hmqv.h:94
HMQV_Domain::GenerateEphemeralPublicKey
void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
return length of ephemeral public keys in this domain
Definition: hmqv.h:108
HMQV_Domain::AgreedValueLength
unsigned int AgreedValueLength() const
return length of agreed value produced
Definition: hmqv.h:69
SecBlock::SizeInBytes
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:811
KeyAgreementAlgorithm::GetMaterial
const CryptoMaterial & GetMaterial() const
Retrieves a reference to Crypto Parameters.
Definition: cryptlib.h:2532
DL_GroupParameters
Interface for Discrete Log (DL) group parameters.
Definition: pubkey.h:753
HMQV_Domain
Hashed Menezes-Qu-Vanstone in GF(p)
Definition: hmqv.h:23
RandomNumberGenerator
Interface for random number generators.
Definition: cryptlib.h:1383
HMQV_Domain::GenerateEphemeralPrivateKey
void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
return length of ephemeral private keys in this domain
Definition: hmqv.h:98
SecByteBlock
SecBlock<byte> typedef.
Definition: secblock.h:1058
algebra.h
Classes for performing mathematics over different fields.
BufferedTransformation
Interface for buffered transformations.
Definition: cryptlib.h:1598
DL_GroupParameters::ExponentiateBase
virtual Element ExponentiateBase(const Integer &exponent) const
Exponentiates the base.
Definition: pubkey.h:839
Integer::One
static const Integer & One()
Integer representing 1.
Definition: integer.cpp:4868
HMQV_Domain::GenerateStaticPrivateKey
void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
generate static private key
Definition: hmqv.h:77
HMQV_Domain::StaticPublicKeyLength
unsigned int StaticPublicKeyLength() const
return length of static public keys in this domain
Definition: hmqv.h:73
HMQV_Domain::Agree
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: hmqv.h:123
CryptoMaterial::DoQuickSanityCheck
void DoQuickSanityCheck() const
Perform a quick sanity check.
Definition: cryptlib.h:2387
HMQV_Domain::AccessCryptoParameters
CryptoParameters & AccessCryptoParameters()
Retrieves a reference to Crypto Parameters.
Definition: hmqv.h:66
HMQV
HMQV_Domain< DL_GroupParameters_GFP_DefaultSafePrime > HMQV
Hashed Menezes-Qu-Vanstone in GF(p)
Definition: hmqv.h:307
Integer
Multiple precision integer with arithmetic operations.
Definition: integer.h:49
gfpcrypt.h
Classes and functions for schemes based on Discrete Logs (DL) over GF(p)
DL_GroupParameters::DecodeElement
virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0
Decodes the element.
DL_BadElement
Exception thrown when an invalid group element is encountered.
Definition: pubkey.h:743
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:535
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69
DL_GroupParameters::ValidateElement
virtual bool ValidateElement(unsigned int level, const Element &element, const DL_FixedBasePrecomputation< Element > *precomp) const =0
Check the element for errors.
sha.h
Classes for SHA-1 and SHA-2 family of message digests.
Integer::BitCount
unsigned int BitCount() const
Determines the number of bits required to represent the Integer.
Definition: integer.cpp:3345
DL_GroupParameters::EncodeElement
virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0
Encodes the element.
CryptoParameters
Interface for crypto prameters.
Definition: cryptlib.h:2435
DL_GroupParameters::GetMaxExponent
virtual Integer GetMaxExponent() const =0
Retrieves the maximum exponent for the group.
HMQV_Domain::EphemeralPublicKeyLength
unsigned int EphemeralPublicKeyLength() const
Provides the size of ephemeral public key.
Definition: hmqv.h:95
CryptoPP
Crypto++ library namespace.
AuthenticatedKeyAgreementDomain
Interface for domains of authenticated key agreement protocols.
Definition: cryptlib.h:2956
DL_GroupParameters::ExponentiateElement
virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const
Exponentiates an element.
Definition: pubkey.h:849
HMQV_Domain::GenerateStaticPublicKey
void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
generate static public key
Definition: hmqv.h:85
HMQV_Domain::StaticPrivateKeyLength
unsigned int StaticPrivateKeyLength() const
return length of static private keys in this domain
Definition: hmqv.h:71
SecBlock::BytePtr
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:804
DL_GroupParameters::GetSubgroupOrder
virtual const Integer & GetSubgroupOrder() const =0
Retrieves the subgroup order.