hmqv.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. // hmqv.h - written and placed in the public domain by Uri Blumenthal
  2. // Shamelessly based upon Wei Dai's MQV source files
  3. #ifndef CRYPTOPP_HMQV_H
  4. #define CRYPTOPP_HMQV_H
  5. /// \file hmqv.h
  6. /// \brief Classes for Hashed Menezes-Qu-Vanstone key agreement in GF(p)
  7. /// \since Crypto++ 5.6.4
  8. #include "gfpcrypt.h"
  9. #include "algebra.h"
  10. #include "sha.h"
  11. NAMESPACE_BEGIN(CryptoPP)
  12. /// \brief Hashed Menezes-Qu-Vanstone in GF(p)
  13. /// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
  14. /// Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
  15. /// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
  16. /// \since Crypto++ 5.6.4
  17. template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
  18. class HMQV_Domain: public AuthenticatedKeyAgreementDomain
  19. {
  20. public:
  21. typedef GROUP_PARAMETERS GroupParameters;
  22. typedef typename GroupParameters::Element Element;
  23. typedef HMQV_Domain<GROUP_PARAMETERS, COFACTOR_OPTION, HASH> Domain;
  24. virtual ~HMQV_Domain() {}
  25. /// \brief Construct a HMQV domain
  26. /// \param clientRole flag indicating initiator or recipient
  27. /// \details <tt>clientRole = true</tt> indicates initiator, and
  28. /// <tt>clientRole = false</tt> indicates recipient or server.
  29. HMQV_Domain(bool clientRole = true)
  30. : m_role(clientRole ? RoleClient : RoleServer) {}
  31. /// \brief Construct a HMQV domain
  32. /// \param params group parameters and options
  33. /// \param clientRole flag indicating initiator or recipient
  34. /// \details <tt>clientRole = true</tt> indicates initiator, and
  35. /// <tt>clientRole = false</tt> indicates recipient or server.
  36. HMQV_Domain(const GroupParameters &params, bool clientRole = true)
  37. : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
  38. /// \brief Construct a HMQV domain
  39. /// \param bt BufferedTransformation with group parameters and options
  40. /// \param clientRole flag indicating initiator or recipient
  41. /// \details <tt>clientRole = true</tt> indicates initiator, and
  42. /// <tt>clientRole = false</tt> indicates recipient or server.
  43. HMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
  44. : m_role(clientRole ? RoleClient : RoleServer)
  45. {m_groupParameters.BERDecode(bt);}
  46. /// \brief Construct a HMQV domain
  47. /// \tparam T1 template parameter used as a constructor parameter
  48. /// \param v1 first parameter
  49. /// \param clientRole flag indicating initiator or recipient
  50. /// \details v1 is passed directly to the GROUP_PARAMETERS object.
  51. /// \details <tt>clientRole = true</tt> indicates initiator, and
  52. /// <tt>clientRole = false</tt> indicates recipient or server.
  53. template <class T1>
  54. HMQV_Domain(T1 v1, bool clientRole = true)
  55. : m_role(clientRole ? RoleClient : RoleServer)
  56. {m_groupParameters.Initialize(v1);}
  57. /// \brief Construct a HMQV domain
  58. /// \tparam T1 template parameter used as a constructor parameter
  59. /// \tparam T2 template parameter used as a constructor parameter
  60. /// \param v1 first parameter
  61. /// \param v2 second parameter
  62. /// \param clientRole flag indicating initiator or recipient
  63. /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
  64. /// \details <tt>clientRole = true</tt> indicates initiator, and
  65. /// <tt>clientRole = false</tt> indicates recipient or server.
  66. template <class T1, class T2>
  67. HMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
  68. : m_role(clientRole ? RoleClient : RoleServer)
  69. {m_groupParameters.Initialize(v1, v2);}
  70. /// \brief Construct a HMQV domain
  71. /// \tparam T1 template parameter used as a constructor parameter
  72. /// \tparam T2 template parameter used as a constructor parameter
  73. /// \tparam T3 template parameter used as a constructor parameter
  74. /// \param v1 first parameter
  75. /// \param v2 second parameter
  76. /// \param v3 third parameter
  77. /// \param clientRole flag indicating initiator or recipient
  78. /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
  79. /// \details <tt>clientRole = true</tt> indicates initiator, and
  80. /// <tt>clientRole = false</tt> indicates recipient or server.
  81. template <class T1, class T2, class T3>
  82. HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
  83. : m_role(clientRole ? RoleClient : RoleServer)
  84. {m_groupParameters.Initialize(v1, v2, v3);}
  85. /// \brief Construct a HMQV domain
  86. /// \tparam T1 template parameter used as a constructor parameter
  87. /// \tparam T2 template parameter used as a constructor parameter
  88. /// \tparam T3 template parameter used as a constructor parameter
  89. /// \tparam T4 template parameter used as a constructor parameter
  90. /// \param v1 first parameter
  91. /// \param v2 second parameter
  92. /// \param v3 third parameter
  93. /// \param v4 third parameter
  94. /// \param clientRole flag indicating initiator or recipient
  95. /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
  96. /// \details <tt>clientRole = true</tt> indicates initiator, and
  97. /// <tt>clientRole = false</tt> indicates recipient or server.
  98. template <class T1, class T2, class T3, class T4>
  99. HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
  100. : m_role(clientRole ? RoleClient : RoleServer)
  101. {m_groupParameters.Initialize(v1, v2, v3, v4);}
  102. public:
  103. /// \brief Retrieves the group parameters for this domain
  104. /// \return the group parameters for this domain as a const reference
  105. const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
  106. /// \brief Retrieves the group parameters for this domain
  107. /// \return the group parameters for this domain as a non-const reference
  108. GroupParameters & AccessGroupParameters() {return m_groupParameters;}
  109. /// \brief Retrieves the crypto parameters for this domain
  110. /// \return the crypto parameters for this domain as a non-const reference
  111. CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
  112. /// \brief Provides the size of the agreed value
  113. /// \return size of agreed value produced in this domain
  114. /// \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>,
  115. /// which means the element is encoded in a non-reversible format. A
  116. /// non-reversible format means its a raw byte array, and it lacks presentation
  117. /// format like an ASN.1 BIT_STRING or OCTET_STRING.
  118. unsigned int AgreedValueLength() const
  119. {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
  120. /// \brief Provides the size of the static private key
  121. /// \return size of static private keys in this domain
  122. /// \details The length is calculated using the byte count of the subgroup order.
  123. unsigned int StaticPrivateKeyLength() const
  124. {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
  125. /// \brief Provides the size of the static public key
  126. /// \return size of static public keys in this domain
  127. /// \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>,
  128. /// which means the element is encoded in a reversible format. A reversible
  129. /// format means it has a presentation format, and its an ANS.1 encoded element
  130. /// or point.
  131. unsigned int StaticPublicKeyLength() const
  132. {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
  133. /// \brief Generate static private key in this domain
  134. /// \param rng a RandomNumberGenerator derived class
  135. /// \param privateKey a byte buffer for the generated private key in this domain
  136. /// \details The private key is a random scalar used as an exponent in the range
  137. /// <tt>[1,MaxExponent()]</tt>.
  138. /// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
  139. void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
  140. {
  141. Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
  142. x.Encode(privateKey, StaticPrivateKeyLength());
  143. }
  144. /// \brief Generate a static public key from a private key in this domain
  145. /// \param rng a RandomNumberGenerator derived class
  146. /// \param privateKey a byte buffer with the previously generated private key
  147. /// \param publicKey a byte buffer for the generated public key in this domain
  148. /// \details The public key is an element or point on the curve, and its stored
  149. /// in a revrsible format. A reversible format means it has a presentation
  150. /// format, and its an ANS.1 encoded element or point.
  151. /// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
  152. void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
  153. {
  154. CRYPTOPP_UNUSED(rng);
  155. const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
  156. Integer x(privateKey, StaticPrivateKeyLength());
  157. Element y = params.ExponentiateBase(x);
  158. params.EncodeElement(true, y, publicKey);
  159. }
  160. /// \brief Provides the size of the ephemeral private key
  161. /// \return size of ephemeral private keys in this domain
  162. /// \details An ephemeral private key is a private key and public key.
  163. /// The serialized size is different than a static private key.
  164. unsigned int EphemeralPrivateKeyLength() const {return StaticPrivateKeyLength() + StaticPublicKeyLength();}
  165. /// \brief Provides the size of the ephemeral public key
  166. /// \return size of ephemeral public keys in this domain
  167. /// \details An ephemeral public key is a public key.
  168. /// The serialized size is the same as a static public key.
  169. unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
  170. /// \brief Generate ephemeral private key in this domain
  171. /// \param rng a RandomNumberGenerator derived class
  172. /// \param privateKey a byte buffer for the generated private key in this domain
  173. /// \pre <tt>COUNTOF(privateKey) == EphemeralPrivateKeyLength()</tt>
  174. void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
  175. {
  176. const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
  177. Integer x(rng, Integer::One(), params.GetMaxExponent());
  178. x.Encode(privateKey, StaticPrivateKeyLength());
  179. Element y = params.ExponentiateBase(x);
  180. params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
  181. }
  182. /// \brief Generate ephemeral public key from a private key in this domain
  183. /// \param rng a RandomNumberGenerator derived class
  184. /// \param privateKey a byte buffer with the previously generated private key
  185. /// \param publicKey a byte buffer for the generated public key in this domain
  186. /// \pre <tt>COUNTOF(publicKey) == EphemeralPublicKeyLength()</tt>
  187. void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
  188. {
  189. CRYPTOPP_UNUSED(rng);
  190. memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
  191. }
  192. /// \brief Derive agreed value or shared secret
  193. /// \param agreedValue the shared secret
  194. /// \param staticPrivateKey your long term private key
  195. /// \param ephemeralPrivateKey your ephemeral private key
  196. /// \param staticOtherPublicKey couterparty's long term public key
  197. /// \param ephemeralOtherPublicKey couterparty's ephemeral public key
  198. /// \param validateStaticOtherPublicKey flag indicating validation
  199. /// \return true upon success, false in case of failure
  200. /// \details Agree() performs the authenticated key agreement. Agree()
  201. /// derives a shared secret from your private keys and couterparty's
  202. /// public keys. Each instance or run of the protocol should use a new
  203. /// ephemeral key pair.
  204. /// \details The other's ephemeral public key will always be validated at
  205. /// Level 1 to ensure it is a point on the curve.
  206. /// <tt>validateStaticOtherPublicKey</tt> determines how thoroughly other's
  207. /// static public key is validated. If you have previously validated the
  208. /// couterparty's static public key, then use
  209. /// <tt>validateStaticOtherPublicKey=false</tt> to save time.
  210. /// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
  211. /// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
  212. /// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
  213. /// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
  214. /// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
  215. bool Agree(byte *agreedValue,
  216. const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
  217. const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
  218. bool validateStaticOtherPublicKey=true) const
  219. {
  220. const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
  221. size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
  222. // Depending on the role, this will hold either A's or B's static
  223. // (long term) public key. AA or BB will then point into tt.
  224. SecByteBlock tt(StaticPublicKeyLength());
  225. try
  226. {
  227. this->GetMaterial().DoQuickSanityCheck();
  228. const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
  229. if(m_role == RoleServer)
  230. {
  231. Integer b(staticPrivateKey, StaticPrivateKeyLength());
  232. Element B = params.ExponentiateBase(b);
  233. params.EncodeElement(true, B, tt);
  234. XX = ephemeralOtherPublicKey;
  235. xxs = EphemeralPublicKeyLength();
  236. YY = ephemeralPrivateKey + StaticPrivateKeyLength();
  237. yys = EphemeralPublicKeyLength();
  238. AA = staticOtherPublicKey;
  239. aas = StaticPublicKeyLength();
  240. BB = tt.BytePtr();
  241. bbs = tt.SizeInBytes();
  242. }
  243. else
  244. {
  245. Integer a(staticPrivateKey, StaticPrivateKeyLength());
  246. Element A = params.ExponentiateBase(a);
  247. params.EncodeElement(true, A, tt);
  248. XX = ephemeralPrivateKey + StaticPrivateKeyLength();
  249. xxs = EphemeralPublicKeyLength();
  250. YY = ephemeralOtherPublicKey;
  251. yys = EphemeralPublicKeyLength();
  252. AA = tt.BytePtr();
  253. aas = tt.SizeInBytes();
  254. BB = staticOtherPublicKey;
  255. bbs = StaticPublicKeyLength();
  256. }
  257. Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
  258. Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
  259. const Integer& q = params.GetSubgroupOrder();
  260. const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
  261. SecByteBlock dd(len), ee(len);
  262. // Compute $d = \hat{H}(X, \hat{B})$
  263. Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
  264. Integer d(dd.BytePtr(), dd.SizeInBytes());
  265. // Compute $e = \hat{H}(Y, \hat{A})$
  266. Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes());
  267. Integer e(ee.BytePtr(), ee.SizeInBytes());
  268. Element sigma;
  269. if(m_role == RoleServer)
  270. {
  271. Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
  272. Integer b(staticPrivateKey, StaticPrivateKeyLength());
  273. Integer s_B = (y + e * b) % q;
  274. Element A = params.DecodeElement(AA, false);
  275. Element X = params.DecodeElement(XX, false);
  276. Element t1 = params.ExponentiateElement(A, d);
  277. Element t2 = m_groupParameters.MultiplyElements(X, t1);
  278. // $\sigma_B}=(X \cdot A^{d})^{s_B}
  279. sigma = params.ExponentiateElement(t2, s_B);
  280. }
  281. else
  282. {
  283. Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
  284. Integer a(staticPrivateKey, StaticPrivateKeyLength());
  285. Integer s_A = (x + d * a) % q;
  286. Element B = params.DecodeElement(BB, false);
  287. Element Y = params.DecodeElement(YY, false);
  288. Element t3 = params.ExponentiateElement(B, e);
  289. Element t4 = m_groupParameters.MultiplyElements(Y, t3);
  290. // $\sigma_A}=(Y \cdot B^{e})^{s_A}
  291. sigma = params.ExponentiateElement(t4, s_A);
  292. }
  293. Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength());
  294. }
  295. catch (DL_BadElement &)
  296. {
  297. CRYPTOPP_ASSERT(0);
  298. return false;
  299. }
  300. return true;
  301. }
  302. protected:
  303. // Hash invocation by client and server differ only in what keys
  304. // each provides.
  305. inline void Hash(const Element* sigma,
  306. const byte* e1, size_t e1len, // Ephemeral key and key length
  307. const byte* s1, size_t s1len, // Static key and key length
  308. byte* digest, size_t dlen) const
  309. {
  310. HASH hash;
  311. size_t idx = 0, req = dlen;
  312. size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
  313. if(sigma)
  314. {
  315. if (e1len != 0 || s1len != 0) {
  316. CRYPTOPP_ASSERT(0);
  317. }
  318. //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
  319. //SecByteBlock sbb(x.MinEncodedSize());
  320. //x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
  321. SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
  322. GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
  323. hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
  324. } else {
  325. if (e1len == 0 || s1len == 0) {
  326. CRYPTOPP_ASSERT(0);
  327. }
  328. hash.Update(e1, e1len);
  329. hash.Update(s1, s1len);
  330. }
  331. hash.TruncatedFinal(digest, blk);
  332. req -= blk;
  333. // All this to catch tail bytes for large curves and small hashes
  334. while(req != 0)
  335. {
  336. hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
  337. idx += (size_t)HASH::DIGESTSIZE;
  338. blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
  339. hash.TruncatedFinal(&digest[idx], blk);
  340. req -= blk;
  341. }
  342. }
  343. private:
  344. // The paper uses Initiator and Recipient - make it classical.
  345. enum KeyAgreementRole { RoleServer = 1, RoleClient };
  346. DL_GroupParameters<Element> & AccessAbstractGroupParameters()
  347. {return m_groupParameters;}
  348. const DL_GroupParameters<Element> & GetAbstractGroupParameters() const
  349. {return m_groupParameters;}
  350. GroupParameters m_groupParameters;
  351. KeyAgreementRole m_role;
  352. };
  353. /// \brief Hashed Menezes-Qu-Vanstone in GF(p)
  354. /// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
  355. /// Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
  356. /// \sa HMQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
  357. /// \since Crypto++ 5.6.4
  358. typedef HMQV_Domain<DL_GroupParameters_GFP_DefaultSafePrime> HMQV;
  359. NAMESPACE_END
  360. #endif