fhmqv.h 18 KB

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