Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:55:02

0001 // elgamal.h - originally written and placed in the public domain by Wei Dai

0002 
0003 /// \file elgamal.h

0004 /// \brief Classes and functions for ElGamal key agreement and encryption schemes

0005 
0006 #ifndef CRYPTOPP_ELGAMAL_H
0007 #define CRYPTOPP_ELGAMAL_H
0008 
0009 #include "cryptlib.h"
0010 #include "modexppc.h"
0011 #include "integer.h"
0012 #include "gfpcrypt.h"
0013 #include "pubkey.h"
0014 #include "misc.h"
0015 #include "oids.h"
0016 #include "dsa.h"
0017 #include "asn.h"
0018 
0019 NAMESPACE_BEGIN(CryptoPP)
0020 
0021 /// \brief ElGamal key agreement and encryption schemes base class

0022 /// \since Crypto++ 1.0

0023 class CRYPTOPP_NO_VTABLE ElGamalBase :
0024     public DL_KeyAgreementAlgorithm_DH<Integer, NoCofactorMultiplication>,
0025     public DL_KeyDerivationAlgorithm<Integer>,
0026     public DL_SymmetricEncryptionAlgorithm
0027 {
0028 public:
0029     virtual ~ElGamalBase() {}
0030 
0031     void Derive(const DL_GroupParameters<Integer> &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const
0032     {
0033         CRYPTOPP_UNUSED(groupParams); CRYPTOPP_UNUSED(ephemeralPublicKey);
0034         CRYPTOPP_UNUSED(derivationParams);
0035         agreedElement.Encode(derivedKey, derivedLength);
0036     }
0037 
0038     size_t GetSymmetricKeyLength(size_t plainTextLength) const
0039     {
0040         CRYPTOPP_UNUSED(plainTextLength);
0041         return GetGroupParameters().GetModulus().ByteCount();
0042     }
0043 
0044     size_t GetSymmetricCiphertextLength(size_t plainTextLength) const
0045     {
0046         unsigned int len = GetGroupParameters().GetModulus().ByteCount();
0047         if (plainTextLength <= GetMaxSymmetricPlaintextLength(len))
0048             return len;
0049         else
0050             return 0;
0051     }
0052 
0053     size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const
0054     {
0055         unsigned int len = GetGroupParameters().GetModulus().ByteCount();
0056         CRYPTOPP_ASSERT(len >= 3);
0057 
0058         if (cipherTextLength == len)
0059             return STDMIN(255U, len-3);
0060         else
0061             return 0;
0062     }
0063 
0064     void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs &parameters) const
0065     {
0066         CRYPTOPP_UNUSED(parameters);
0067         const Integer &p = GetGroupParameters().GetModulus();
0068         unsigned int modulusLen = p.ByteCount();
0069 
0070         SecByteBlock block(modulusLen-1);
0071         rng.GenerateBlock(block, modulusLen-2-plainTextLength);
0072         std::memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength);
0073         block[modulusLen-2] = (byte)plainTextLength;
0074 
0075         a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen);
0076     }
0077 
0078     DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs &parameters) const
0079     {
0080         CRYPTOPP_UNUSED(parameters);
0081         const Integer &p = GetGroupParameters().GetModulus();
0082         unsigned int modulusLen = p.ByteCount();
0083 
0084         if (cipherTextLength != modulusLen)
0085             return DecodingResult();
0086 
0087         Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p);
0088 
0089         m.Encode(plainText, 1);
0090         unsigned int plainTextLength = plainText[0];
0091         if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen))
0092             return DecodingResult();
0093         m >>= 8;
0094         m.Encode(plainText, plainTextLength);
0095         return DecodingResult(plainTextLength);
0096     }
0097 
0098     virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0;
0099 };
0100 
0101 /// \brief ElGamal key agreement and encryption schemes default implementation

0102 /// \tparam BASE Base class implementation

0103 /// \tparam SCHEME_OPTIONS Scheme options

0104 /// \tparam KEY ElGamal key classes

0105 /// \since Crypto++ 1.0

0106 template <class BASE, class SCHEME_OPTIONS, class KEY>
0107 class ElGamalObjectImpl :
0108     public DL_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY>,
0109     public ElGamalBase
0110 {
0111 public:
0112     virtual ~ElGamalObjectImpl() {}
0113 
0114     size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());}
0115     size_t FixedCiphertextLength() const {return this->CiphertextLength(0);}
0116 
0117     const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();}
0118 
0119     DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const
0120         {return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);}
0121 
0122 protected:
0123     const DL_KeyAgreementAlgorithm<Integer> & GetKeyAgreementAlgorithm() const {return *this;}
0124     const DL_KeyDerivationAlgorithm<Integer> & GetKeyDerivationAlgorithm() const {return *this;}
0125     const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;}
0126 };
0127 
0128 /// \brief ElGamal Public Key adapter

0129 /// \tparam BASE PublicKey derived class

0130 /// \details DL_PublicKey_ElGamal provides an override for GetAlgorithmID()

0131 ///  to utilize 1.3.14.7.2.1.1. Prior to DL_PublicKey_ElGamal, the ElGamal

0132 ///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().

0133 ///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then

0134 ///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on

0135 ///  the Crypto++ wiki.

0136 /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,

0137 ///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>

0138 /// \since Crypto++ 8.3

0139 template <class BASE>
0140 struct DL_PublicKey_ElGamal : public BASE
0141 {
0142     virtual ~DL_PublicKey_ElGamal() {}
0143 
0144     /// \brief Retrieves the OID of the algorithm

0145     /// \return OID of the algorithm

0146     /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()

0147     ///  to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal

0148     ///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().

0149     ///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then

0150     ///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on

0151     ///  the Crypto++ wiki.

0152     /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,

0153     ///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>

0154     virtual OID GetAlgorithmID() const {
0155         return ASN1::elGamal();
0156     }
0157 };
0158 
0159 /// \brief ElGamal Private Key adapter

0160 /// \tparam BASE PrivateKey derived class

0161 /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()

0162 ///  to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal

0163 ///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().

0164 ///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then

0165 ///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on

0166 ///  the Crypto++ wiki.

0167 /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,

0168 ///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>

0169 /// \since Crypto++ 8.3

0170 template <class BASE>
0171 struct DL_PrivateKey_ElGamal : public BASE
0172 {
0173     virtual ~DL_PrivateKey_ElGamal() {}
0174 
0175     /// \brief Retrieves the OID of the algorithm

0176     /// \return OID of the algorithm

0177     /// \details DL_PrivateKey_ElGamal provides an override for GetAlgorithmID()

0178     ///  to utilize 1.3.14.7.2.1.1. Prior to DL_PrivateKey_ElGamal, the ElGamal

0179     ///  keys [mistakenly] used the OID from DSA due to DL_GroupParmaters_GFP().

0180     ///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then

0181     ///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on

0182     ///  the Crypto++ wiki.

0183     /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,

0184     ///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>

0185     virtual OID GetAlgorithmID() const {
0186         return ASN1::elGamal();
0187     }
0188 
0189     /// \brief Check the key for errors

0190     /// \param rng RandomNumberGenerator for objects which use randomized testing

0191     /// \param level level of thoroughness

0192     /// \return true if the tests succeed, false otherwise

0193     /// \details There are four levels of thoroughness:

0194     ///   <ul>

0195     ///   <li>0 - using this object won't cause a crash or exception

0196     ///   <li>1 - this object will probably function, and encrypt, sign, other

0197     ///           operations correctly

0198     ///   <li>2 - ensure this object will function correctly, and perform

0199     ///           reasonable security checks

0200     ///   <li>3 - perform reasonable security checks, and do checks that may

0201     ///           take a long time

0202     ///   </ul>

0203     /// \details Level 0 does not require a RandomNumberGenerator. A NullRNG() can

0204     ///  be used for level 0. Level 1 may not check for weak keys and such.

0205     ///  Levels 2 and 3 are recommended.

0206     bool Validate(RandomNumberGenerator &rng, unsigned int level) const
0207     {
0208         // Validate() formerly used DL_PrivateKey_GFP implementation through

0209         // inheritance. However, it would reject keys from other libraries

0210         // like BouncyCastle. The failure was x < q. According to ElGamal's

0211         // paper and the HAC, the private key is selected in over [1,p-1],

0212         // Later Tsiounis and Yung showed the lower limit as [1,q-1] in

0213         // "On the Security of EIGamal Based Encryption". As such, Crypto++

0214         // will generate a key in the range [1,q-1], but accept a key

0215         // in [1,p-1]. Thanks to JPM for finding the reference. Also see

0216         // https://github.com/weidai11/cryptopp/commit/a5a684d92986.

0217 
0218         CRYPTOPP_ASSERT(this->GetAbstractGroupParameters().Validate(rng, level));
0219         bool pass = this->GetAbstractGroupParameters().Validate(rng, level);
0220 
0221         const Integer &p = this->GetGroupParameters().GetModulus();
0222         const Integer &q = this->GetAbstractGroupParameters().GetSubgroupOrder();
0223         const Integer &x = this->GetPrivateExponent();
0224 
0225         // Changed to x < p-1 based on ElGamal's paper and the HAC.

0226         CRYPTOPP_ASSERT(x.IsPositive());
0227         CRYPTOPP_ASSERT(x < p-1);
0228         pass = pass && x.IsPositive() && x < p-1;
0229 
0230         if (level >= 1)
0231         {
0232             // Minimum security level due to Tsiounis and Yung.

0233             CRYPTOPP_ASSERT(Integer::Gcd(x, q) == Integer::One());
0234             pass = pass && Integer::Gcd(x, q) == Integer::One();
0235         }
0236         return pass;
0237     }
0238 };
0239 
0240 /// \brief ElGamal key agreement and encryption schemes keys

0241 /// \details ElGamalKeys provide the algorithm implementation ElGamal key

0242 ///  agreement and encryption schemes.

0243 /// \details The ElGamalKeys class used <tt>DL_PrivateKey_GFP_OldFormat</tt>

0244 ///  and <tt>DL_PublicKey_GFP_OldFormat</tt> for the <tt>PrivateKey</tt> and

0245 ///  <tt>PublicKey</tt> from about Crypto++ 1.0 through Crypto++ 5.6.5. At

0246 ///  Crypto++ 6.0 the serialization format was cutover to standard PKCS8 and

0247 ///  X509 encodings.

0248 /// \details The ElGamalKeys class [mistakenly] used the OID for DSA from

0249 ///  about Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was

0250 ///  fixed and now uses ElGamal encryption, which is 1.3.14.7.2.1.1.

0251 ///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then

0252 ///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on

0253 ///  the Crypto++ wiki.

0254 /// \details At Crypto++ 8.6 ElGamalKeys were changed to use DL_CryptoKeys_ElGamal

0255 ///  due to Issue 1069 and CVE-2021-40530. DL_CryptoKeys_ElGamal group parameters

0256 ///  use the subgroup order, and not an estimated work factor.

0257 /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,

0258 ///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>,

0259 ///  <A HREF="https://github.com/weidai11/cryptopp/issues/1059">Issue 1059</A>

0260 /// \since Crypto++ 1.0

0261 struct ElGamalKeys
0262 {
0263     /// \brief Implements DL_GroupParameters interface

0264     typedef DL_CryptoKeys_ElGamal::GroupParameters GroupParameters;
0265     /// \brief Implements DL_PrivateKey interface

0266     typedef DL_PrivateKey_ElGamal<DL_CryptoKeys_ElGamal::PrivateKey> PrivateKey;
0267     /// \brief Implements DL_PublicKey interface

0268     typedef DL_PublicKey_ElGamal<DL_CryptoKeys_ElGamal::PublicKey> PublicKey;
0269 };
0270 
0271 /// \brief ElGamal encryption scheme with non-standard padding

0272 /// \details ElGamal provide the algorithm implementation ElGamal key

0273 ///  agreement and encryption schemes.

0274 /// \details The ElGamal class [mistakenly] used the OID for DSA from about

0275 ///  Crypto++ 1.0 through Crypto++ 8.2. At Crypto++ 8.3 the OID was fixed

0276 ///  and now uses ElGamal encryption, which is 1.3.14.7.2.1.1.

0277 ///  If you need to <tt>Load</tt> an ElGamal key with the wrong OID then

0278 ///  see <A HREF="https://www.cryptopp.com/wiki/ElGamal">ElGamal</A> on

0279 ///  the Crypto++ wiki.

0280 /// \sa <A HREF="https://github.com/weidai11/cryptopp/issues/876">Issue 876</A>,

0281 ///  <A HREF="https://github.com/weidai11/cryptopp/issues/567">Issue 567</A>

0282 /// \since Crypto++ 1.0

0283 struct ElGamal
0284 {
0285     typedef DL_CryptoSchemeOptions<ElGamal, ElGamalKeys, int, int, int> SchemeOptions;
0286     typedef SchemeOptions::PrivateKey PrivateKey;
0287     typedef SchemeOptions::PublicKey PublicKey;
0288 
0289     /// \brief The algorithm name

0290     /// \return the algorithm name

0291     /// \details StaticAlgorithmName returns the algorithm's name as a static

0292     ///  member function.

0293     CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";}
0294 
0295     /// \brief Implements DL_GroupParameters interface

0296     typedef SchemeOptions::GroupParameters GroupParameters;
0297     /// \brief Implements PK_Encryptor interface

0298     typedef PK_FinalTemplate<ElGamalObjectImpl<DL_EncryptorBase<Integer>, SchemeOptions, SchemeOptions::PublicKey> > Encryptor;
0299     /// \brief Implements PK_Encryptor interface

0300     typedef PK_FinalTemplate<ElGamalObjectImpl<DL_DecryptorBase<Integer>, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor;
0301 };
0302 
0303 typedef ElGamal::Encryptor ElGamalEncryptor;
0304 typedef ElGamal::Decryptor ElGamalDecryptor;
0305 
0306 NAMESPACE_END
0307 
0308 #endif