1#ifndef CRYPTOPP_ELGAMAL_H
2#define CRYPTOPP_ELGAMAL_H
3
4#include "modexppc.h"
5#include "dsa.h"
6
7NAMESPACE_BEGIN(CryptoPP)
8
9class CRYPTOPP_NO_VTABLE ElGamalBase : public DL_KeyAgreementAlgorithm_DH<Integer, NoCofactorMultiplication>,
10					public DL_KeyDerivationAlgorithm<Integer>,
11					public DL_SymmetricEncryptionAlgorithm
12{
13public:
14	void Derive(const DL_GroupParameters<Integer> &groupParams, byte *derivedKey, size_t derivedLength, const Integer &agreedElement, const Integer &ephemeralPublicKey, const NameValuePairs &derivationParams) const
15	{
16		agreedElement.Encode(derivedKey, derivedLength);
17	}
18
19	size_t GetSymmetricKeyLength(size_t plainTextLength) const
20	{
21		return GetGroupParameters().GetModulus().ByteCount();
22	}
23
24	size_t GetSymmetricCiphertextLength(size_t plainTextLength) const
25	{
26		unsigned int len = GetGroupParameters().GetModulus().ByteCount();
27		if (plainTextLength <= GetMaxSymmetricPlaintextLength(len))
28			return len;
29		else
30			return 0;
31	}
32
33	size_t GetMaxSymmetricPlaintextLength(size_t cipherTextLength) const
34	{
35		unsigned int len = GetGroupParameters().GetModulus().ByteCount();
36		if (cipherTextLength == len)
37			return STDMIN(255U, len-3);
38		else
39			return 0;
40	}
41
42	void SymmetricEncrypt(RandomNumberGenerator &rng, const byte *key, const byte *plainText, size_t plainTextLength, byte *cipherText, const NameValuePairs &parameters) const
43	{
44		const Integer &p = GetGroupParameters().GetModulus();
45		unsigned int modulusLen = p.ByteCount();
46
47		SecByteBlock block(modulusLen-1);
48		rng.GenerateBlock(block, modulusLen-2-plainTextLength);
49		memcpy(block+modulusLen-2-plainTextLength, plainText, plainTextLength);
50		block[modulusLen-2] = (byte)plainTextLength;
51
52		a_times_b_mod_c(Integer(key, modulusLen), Integer(block, modulusLen-1), p).Encode(cipherText, modulusLen);
53	}
54
55	DecodingResult SymmetricDecrypt(const byte *key, const byte *cipherText, size_t cipherTextLength, byte *plainText, const NameValuePairs &parameters) const
56	{
57		const Integer &p = GetGroupParameters().GetModulus();
58		unsigned int modulusLen = p.ByteCount();
59
60		if (cipherTextLength != modulusLen)
61			return DecodingResult();
62
63		Integer m = a_times_b_mod_c(Integer(cipherText, modulusLen), Integer(key, modulusLen).InverseMod(p), p);
64
65		m.Encode(plainText, 1);
66		unsigned int plainTextLength = plainText[0];
67		if (plainTextLength > GetMaxSymmetricPlaintextLength(modulusLen))
68			return DecodingResult();
69		m >>= 8;
70		m.Encode(plainText, plainTextLength);
71		return DecodingResult(plainTextLength);
72	}
73
74	virtual const DL_GroupParameters_GFP & GetGroupParameters() const =0;
75};
76
77template <class BASE, class SCHEME_OPTIONS, class KEY>
78class ElGamalObjectImpl : public DL_ObjectImplBase<BASE, SCHEME_OPTIONS, KEY>, public ElGamalBase
79{
80public:
81	size_t FixedMaxPlaintextLength() const {return this->MaxPlaintextLength(FixedCiphertextLength());}
82	size_t FixedCiphertextLength() const {return this->CiphertextLength(0);}
83
84	const DL_GroupParameters_GFP & GetGroupParameters() const {return this->GetKey().GetGroupParameters();}
85
86	DecodingResult FixedLengthDecrypt(RandomNumberGenerator &rng, const byte *cipherText, byte *plainText) const
87		{return Decrypt(rng, cipherText, FixedCiphertextLength(), plainText);}
88
89protected:
90	const DL_KeyAgreementAlgorithm<Integer> & GetKeyAgreementAlgorithm() const {return *this;}
91	const DL_KeyDerivationAlgorithm<Integer> & GetKeyDerivationAlgorithm() const {return *this;}
92	const DL_SymmetricEncryptionAlgorithm & GetSymmetricEncryptionAlgorithm() const {return *this;}
93};
94
95struct ElGamalKeys
96{
97	typedef DL_CryptoKeys_GFP::GroupParameters GroupParameters;
98	typedef DL_PrivateKey_GFP_OldFormat<DL_CryptoKeys_GFP::PrivateKey> PrivateKey;
99	typedef DL_PublicKey_GFP_OldFormat<DL_CryptoKeys_GFP::PublicKey> PublicKey;
100};
101
102//! ElGamal encryption scheme with non-standard padding
103struct ElGamal
104{
105	typedef DL_CryptoSchemeOptions<ElGamal, ElGamalKeys, int, int, int> SchemeOptions;
106
107	static const char * StaticAlgorithmName() {return "ElgamalEnc/Crypto++Padding";}
108
109	typedef SchemeOptions::GroupParameters GroupParameters;
110	//! implements PK_Encryptor interface
111	typedef PK_FinalTemplate<ElGamalObjectImpl<DL_EncryptorBase<Integer>, SchemeOptions, SchemeOptions::PublicKey> > Encryptor;
112	//! implements PK_Decryptor interface
113	typedef PK_FinalTemplate<ElGamalObjectImpl<DL_DecryptorBase<Integer>, SchemeOptions, SchemeOptions::PrivateKey> > Decryptor;
114};
115
116typedef ElGamal::Encryptor ElGamalEncryptor;
117typedef ElGamal::Decryptor ElGamalDecryptor;
118
119NAMESPACE_END
120
121#endif
122