elgamal.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // elgamal.h - originally written and placed in the public domain by Wei Dai
  2. /// \file elgamal.h
  3. /// \brief Classes and functions for ElGamal key agreement and encryption schemes
  4. #ifndef CRYPTOPP_ELGAMAL_H
  5. #define CRYPTOPP_ELGAMAL_H
  6. #include "cryptlib.h"
  7. #include "modexppc.h"
  8. #include "integer.h"
  9. #include "gfpcrypt.h"
  10. #include "pubkey.h"
  11. #include "misc.h"
  12. #include "oids.h"
  13. #include "dsa.h"
  14. #include "asn.h"
  15. NAMESPACE_BEGIN(CryptoPP)
  16. /// \brief ElGamal key agreement and encryption schemes base class
  17. /// \since Crypto++ 1.0
  18. class CRYPTOPP_NO_VTABLE ElGamalBase :
  19. public DL_KeyAgreementAlgorithm_DH<Integer, NoCofactorMultiplication>,
  20. public DL_KeyDerivationAlgorithm<Integer>,
  21. public DL_SymmetricEncryptionAlgorithm
  22. {
  23. public:
  24. virtual ~ElGamalBase() {}
  25. void Derive(const DL_GroupParameters<Integer> &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const
  26. {
  27. CRYPTOPP_UNUSED(groupParams); CRYPTOPP_UNUSED(ephemeralPublicKey);
  28. CRYPTOPP_UNUSED(derivationParams);
  29. agreedElement.Encode(derivedKey, derivedLength);
  30. }
  31. size_t GetSymmetricKeyLength(size_t plainTextLength) const
  32. {
  33. CRYPTOPP_UNUSED(plainTextLength);
  34. return GetGroupParameters().GetModulus().ByteCount();
  35. }
  36. size_t GetSymmetricCiphertextLength(size_t plainTextLength) const
  37. {
  38. unsigned int len = GetGroupParameters().GetModulus().ByteCount();
  39. if (plainTextLength <= GetMaxSymmetricPlaintextLength(len))
  40. return len;
  41. else
  42. return 0;
  43. }
  44. size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const
  45. {
  46. unsigned int len = GetGroupParameters().GetModulus().ByteCount();
  47. CRYPTOPP_ASSERT(len >= 3);
  48. if (cipherTextLength == len)
  49. return STDMIN(255U, len-3);
  50. else
  51. return 0;
  52. }
  53. void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs &parameters) const
  54. {
  55. CRYPTOPP_UNUSED(parameters);
  56. const Integer &p = GetGroupParameters().GetModulus();
  57. unsigned int modulusLen = p.ByteCount();
  58. SecByteBlock block(modulusLen-1);
  59. rng.GenerateBlock(block, modulusLen-2-plainTextLength);
  60. memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength);
  61. block[modulusLen-2] = (byte)plainTextLength;
  62. a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen);
  63. }
  64. DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs &parameters) const
  65. {
  66. CRYPTOPP_UNUSED(parameters);
  67. const Integer &p = GetGroupParameters().GetModulus();
  68. unsigned int modulusLen = p.ByteCount();
  69. if (cipherTextLength != modulusLen)
  70. return DecodingResult();
  71. Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p);
  72. m.Encode(plainText, 1);
  73. unsigned int plainTextLength = plainText[0];
  74. if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen))
  75. return DecodingResult();
  76. m >>= 8;
  77. m.Encode(plainText, plainTextLength);
  78. return DecodingResult(plainTextLength);
  79. }
  80. virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0;
  81. };
  82. /// \brief ElGamal key agreement and encryption schemes default implementation
  83. /// \tparam BASE Base class implementation
  84. /// \tparam SCHEME_OPTIONS Scheme options
  85. /// \tparam KEY ElGamal key classes
  86. /// \since Crypto++ 1.0
  87. template <class BASE, class SCHEME_OPTIONS, class KEY>
  88. class ElGamalObjectImpl :
  89. public DL_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY>,
  90. public ElGamalBase
  91. {
  92. public:
  93. virtual ~ElGamalObjectImpl() {}
  94. size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());}
  95. size_t FixedCiphertextLength() const {return this->CiphertextLength(0);}
  96. const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();}
  97. DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const
  98. {return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);}
  99. protected:
  100. const DL_KeyAgreementAlgorithm<Integer> & GetKeyAgreementAlgorithm() const {return *this;}
  101. const DL_KeyDerivationAlgorithm<Integer> & GetKeyDerivationAlgorithm() const {return *this;}
  102. const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;}
  103. };
  104. /// \brief ElGamal Public Key adapter
  105. /// \tparam BASE PublicKey derived class
  106. /// \details DL_PublicKey_ElGamal provides an override for GetAlgorithmID()
  107. /// to utilize 1.3.14.7.2.1.1. Prior to DL_PublicKey_ElGamal, the ElGamal
  108. /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
  109. /// If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
  110. /// see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
  111. /// the Crypto++ wiki.
  112. /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
  113. /// <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
  114. /// \since Crypto++ 8.3
  115. template <class BASE>
  116. struct DL_PublicKey_ElGamal : public BASE
  117. {
  118. virtual ~DL_PublicKey_ElGamal() {}
  119. /// \brief Retrieves the OID of the algorithm
  120. /// \return OID of the algorithm
  121. /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()
  122. /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal
  123. /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
  124. /// If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
  125. /// see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
  126. /// the Crypto++ wiki.
  127. /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
  128. /// <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
  129. virtual OID GetAlgorithmID() const {
  130. return ASN1::elGamal();
  131. }
  132. };
  133. /// \brief ElGamal Private Key adapter
  134. /// \tparam BASE PrivateKey derived class
  135. /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()
  136. /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal
  137. /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
  138. /// If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
  139. /// see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
  140. /// the Crypto++ wiki.
  141. /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
  142. /// <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
  143. /// \since Crypto++ 8.3
  144. template <class BASE>
  145. struct DL_PrivateKey_ElGamal : public BASE
  146. {
  147. virtual ~DL_PrivateKey_ElGamal() {}
  148. /// \brief Retrieves the OID of the algorithm
  149. /// \return OID of the algorithm
  150. /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()
  151. /// to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal
  152. /// keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().
  153. /// If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
  154. /// see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
  155. /// the Crypto++ wiki.
  156. /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
  157. /// <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
  158. virtual OID GetAlgorithmID() const {
  159. return ASN1::elGamal();
  160. }
  161. /// \brief Check the key for errors
  162. /// \param rng RandomNumberGenerator for objects which use randomized testing
  163. /// \param level level of thoroughness
  164. /// \return true if the tests succeed, false otherwise
  165. /// \details There are four levels of thoroughness:
  166. /// <ul>
  167. /// <li>0 - using this object won't cause a crash or exception
  168. /// <li>1 - this object will probably function, and encrypt, sign, other
  169. /// operations correctly
  170. /// <li>2 - ensure this object will function correctly, and perform
  171. /// reasonable security checks
  172. /// <li>3 - perform reasonable security checks, and do checks that may
  173. /// take a long time
  174. /// </ul>
  175. /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can
  176. /// be used for level 0. Level 1 may not check for weak keys and such.
  177. /// Levels 2 and 3 are recommended.
  178. bool Validate(RandomNumberGenerator &rng, unsigned int level) const
  179. {
  180. // Validate() formerly used DL_PrivateKey_GFP implementation through
  181. // inheritance. However, it would reject keys from other libraries
  182. // like BouncyCastle. The failure was x < q. According to ElGamal's
  183. // paper and the HAC, the private key is selected in over [1,p-1],
  184. // Later Tsiounis and Yung showed the lower limit as [1,q-1] in
  185. // "On the Security of EIGamal Based Encryption". As such, Crypto++
  186. // will generate a key in the range [1,q-1], but accept a key
  187. // in [1,p-1]. Thanks to JPM for finding the reference. Also see
  188. // https://github.com/weidai11/cryptopp/commit/a5a684d92986.
  189. CRYPTOPP_ASSERT(this->GetAbstractGroupParameters().Validate(rng, level));
  190. bool pass = this->GetAbstractGroupParameters().Validate(rng, level);
  191. const Integer &p = this->GetGroupParameters().GetModulus();
  192. const Integer &q = this->GetAbstractGroupParameters().GetSubgroupOrder();
  193. const Integer &x = this->GetPrivateExponent();
  194. // Changed to x < p-1 based on ElGamal's paper and the HAC.
  195. CRYPTOPP_ASSERT(x.IsPositive());
  196. CRYPTOPP_ASSERT(x < p-1);
  197. pass = pass && x.IsPositive() && x < p-1;
  198. if (level >= 1)
  199. {
  200. // Minimum security level due to Tsiounis and Yung.
  201. CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One());
  202. pass = pass && Integer::Gcd(x, q) == Integer::One();
  203. }
  204. return pass;
  205. }
  206. };
  207. /// \brief ElGamal key agreement and encryption schemes keys
  208. /// \details ElGamalKeys provide the algorithm implementation ElGamal key
  209. /// agreement and encryption schemes.
  210. /// \details The ElGamalKeys class used <tt>DL_PrivateKey_GFP_OldFormat</tt>
  211. /// and <tt>DL_PublicKey_GFP_OldFormat</tt> for the <tt>PrivateKey</tt> and
  212. /// <tt>PublicKey</tt> from about Crypto++ 1.0 through Crypto++ 5.6.5. At
  213. /// Crypto++ 6.0 the serialization format was cutover to standard PKCS8 and
  214. /// X509 encodings.
  215. /// \details The ElGamalKeys class [mistakenly] used the OID for DSA from
  216. /// about Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was
  217. /// fixed and now uses ElGamal encryption, which is 1.3.14.7.2.1.1.
  218. /// If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
  219. /// see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
  220. /// the Crypto++ wiki.
  221. /// \details At Crypto++ 8.6 ElGamalKeys were changed to use DL_CryptoKeys_ElGamal
  222. /// due to Issue 1069 and CVE-2021-40530. DL_CryptoKeys_ElGamal group parameters
  223. /// use the subgroup order, and not an estimated work factor.
  224. /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
  225. /// <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>,
  226. /// <A HREF="https://github.com/weidai11/cryptopp/issues/1059">Issue 1059</A>
  227. /// \since Crypto++ 1.0
  228. struct ElGamalKeys
  229. {
  230. /// \brief Implements DL_GroupParameters interface
  231. typedef DL_CryptoKeys_ElGamal::GroupParameters GroupParameters;
  232. /// \brief Implements DL_PrivateKey interface
  233. typedef DL_PrivateKey_ElGamal<DL_CryptoKeys_ElGamal::PrivateKey> PrivateKey;
  234. /// \brief Implements DL_PublicKey interface
  235. typedef DL_PublicKey_ElGamal<DL_CryptoKeys_ElGamal::PublicKey> PublicKey;
  236. };
  237. /// \brief ElGamal encryption scheme with non-standard padding
  238. /// \details ElGamal provide the algorithm implementation ElGamal key
  239. /// agreement and encryption schemes.
  240. /// \details The ElGamal class [mistakenly] used the OID for DSA from about
  241. /// Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was fixed
  242. /// and now uses ElGamal encryption, which is 1.3.14.7.2.1.1.
  243. /// If you need to <tt>Load</tt> an ElGamal key with the wrong OID then
  244. /// see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on
  245. /// the Crypto++ wiki.
  246. /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,
  247. /// <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>
  248. /// \since Crypto++ 1.0
  249. struct ElGamal
  250. {
  251. typedef DL_CryptoSchemeOptions<ElGamal, ElGamalKeys, int, int, int> SchemeOptions;
  252. typedef SchemeOptions::PrivateKey PrivateKey;
  253. typedef SchemeOptions::PublicKey PublicKey;
  254. /// \brief The algorithm name
  255. /// \return the algorithm name
  256. /// \details StaticAlgorithmName returns the algorithm's name as a static
  257. /// member function.
  258. CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";}
  259. /// \brief Implements DL_GroupParameters interface
  260. typedef SchemeOptions::GroupParameters GroupParameters;
  261. /// \brief Implements PK_Encryptor interface
  262. typedef PK_FinalTemplate<ElGamalObjectImpl<DL_EncryptorBase<Integer>, SchemeOptions, SchemeOptions::PublicKey> > Encryptor;
  263. /// \brief Implements PK_Encryptor interface
  264. typedef PK_FinalTemplate<ElGamalObjectImpl<DL_DecryptorBase<Integer>, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor;
  265. };
  266. typedef ElGamal::Encryptor ElGamalEncryptor;
  267. typedef ElGamal::Decryptor ElGamalDecryptor;
  268. NAMESPACE_END
  269. #endif