1 // dh.h - originally written and placed in the public domain by Wei Dai
2 
3 /// \file dh.h
4 /// \brief Classes for Diffie-Hellman key exchange
5 
6 #ifndef CRYPTOPP_DH_H
7 #define CRYPTOPP_DH_H
8 
9 #include "cryptlib.h"
10 #include "gfpcrypt.h"
11 #include "algebra.h"
12 
NAMESPACE_BEGIN(CryptoPP)13 NAMESPACE_BEGIN(CryptoPP)
14 
15 /// \brief Diffie-Hellman domain
16 /// \tparam GROUP_PARAMETERS group parameters
17 /// \tparam COFACTOR_OPTION cofactor multiplication option
18 /// \details A Diffie-Hellman domain is a set of parameters that must be shared
19 ///   by two parties in a key agreement protocol, along with the algorithms
20 ///   for generating key pairs and deriving agreed values.
21 /// \details For COFACTOR_OPTION, see CofactorMultiplicationOption.
22 /// \sa DL_SimpleKeyAgreementDomainBase
23 /// \since Crypto++ 1.0
24 template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption>
25 class DH_Domain : public DL_SimpleKeyAgreementDomainBase<typename GROUP_PARAMETERS::Element>
26 {
27 	typedef DL_SimpleKeyAgreementDomainBase<typename GROUP_PARAMETERS::Element> Base;
28 
29 public:
30 	typedef GROUP_PARAMETERS GroupParameters;
31 	typedef typename GroupParameters::Element Element;
32 	typedef DL_KeyAgreementAlgorithm_DH<Element, COFACTOR_OPTION> DH_Algorithm;
33 	typedef DH_Domain<GROUP_PARAMETERS, COFACTOR_OPTION> Domain;
34 
35 	virtual ~DH_Domain() {}
36 
37 	/// \brief Construct a Diffie-Hellman domain
38 	DH_Domain() {}
39 
40 	/// \brief Construct a Diffie-Hellman domain
41 	/// \param params group parameters and options
42 	DH_Domain(const GroupParameters &params)
43 		: m_groupParameters(params) {}
44 
45 	/// \brief Construct a Diffie-Hellman domain
46 	/// \param bt BufferedTransformation with group parameters and options
47 	DH_Domain(BufferedTransformation &bt)
48 		{m_groupParameters.BERDecode(bt);}
49 
50 	/// \brief Create a Diffie-Hellman domain
51 	/// \tparam T2 template parameter used as a constructor parameter
52 	/// \param v1 RandomNumberGenerator derived class
53 	/// \param v2 second parameter
54 	/// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
55 	template <class T2>
56 	DH_Domain(RandomNumberGenerator &v1, const T2 &v2)
57 		{m_groupParameters.Initialize(v1, v2);}
58 
59 	/// \brief Create a Diffie-Hellman domain
60 	/// \tparam T2 template parameter used as a constructor parameter
61 	/// \tparam T3 template parameter used as a constructor parameter
62 	/// \param v1 RandomNumberGenerator derived class
63 	/// \param v2 second parameter
64 	/// \param v3 third parameter
65 	/// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
66 	template <class T2, class T3>
67 	DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3)
68 		{m_groupParameters.Initialize(v1, v2, v3);}
69 
70 	/// \brief Create a Diffie-Hellman domain
71 	/// \tparam T2 template parameter used as a constructor parameter
72 	/// \tparam T3 template parameter used as a constructor parameter
73 	/// \tparam T4 template parameter used as a constructor parameter
74 	/// \param v1 RandomNumberGenerator derived class
75 	/// \param v2 second parameter
76 	/// \param v3 third parameter
77 	/// \param v4 fourth parameter
78 	/// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
79 	template <class T2, class T3, class T4>
80 	DH_Domain(RandomNumberGenerator &v1, const T2 &v2, const T3 &v3, const T4 &v4)
81 		{m_groupParameters.Initialize(v1, v2, v3, v4);}
82 
83 	/// \brief Construct a Diffie-Hellman domain
84 	/// \tparam T1 template parameter used as a constructor parameter
85 	/// \tparam T2 template parameter used as a constructor parameter
86 	/// \param v1 first parameter
87 	/// \param v2 second parameter
88 	/// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
89 	template <class T1, class T2>
90 	DH_Domain(const T1 &v1, const T2 &v2)
91 		{m_groupParameters.Initialize(v1, v2);}
92 
93 	/// \brief Construct a Diffie-Hellman domain
94 	/// \tparam T1 template parameter used as a constructor parameter
95 	/// \tparam T2 template parameter used as a constructor parameter
96 	/// \tparam T3 template parameter used as a constructor parameter
97 	/// \param v1 first parameter
98 	/// \param v2 second parameter
99 	/// \param v3 third parameter
100 	/// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
101 	template <class T1, class T2, class T3>
102 	DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3)
103 		{m_groupParameters.Initialize(v1, v2, v3);}
104 
105 	/// \brief Construct a Diffie-Hellman domain
106 	/// \tparam T1 template parameter used as a constructor parameter
107 	/// \tparam T2 template parameter used as a constructor parameter
108 	/// \tparam T3 template parameter used as a constructor parameter
109 	/// \tparam T4 template parameter used as a constructor parameter
110 	/// \param v1 first parameter
111 	/// \param v2 second parameter
112 	/// \param v3 third parameter
113 	/// \param v4 fourth parameter
114 	/// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
115 	template <class T1, class T2, class T3, class T4>
116 	DH_Domain(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4)
117 		{m_groupParameters.Initialize(v1, v2, v3, v4);}
118 
119 	/// \brief Retrieves the group parameters for this domain
120 	/// \return the group parameters for this domain as a const reference
121 	const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
122 	/// \brief Retrieves the group parameters for this domain
123 	/// \return the group parameters for this domain as a non-const reference
124 	GroupParameters & AccessGroupParameters() {return m_groupParameters;}
125 
126 	/// \brief Generate a public key from a private key in this domain
127 	/// \param rng RandomNumberGenerator derived class
128 	/// \param privateKey byte buffer with the previously generated private key
129 	/// \param publicKey byte buffer for the generated public key in this domain
130 	/// \details If using a FIPS 140-2 validated library on Windows, then this class will perform
131 	///   a self test to ensure the key pair is pairwise consistent. Non-FIPS and non-Windows
132 	///   builds of the library do not provide FIPS validated cryptography, so the code should be
133 	///   removed by the optimizer.
134 	/// \pre <tt>COUNTOF(publicKey) == PublicKeyLength()</tt>
135 	void GeneratePublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
136 	{
137 		Base::GeneratePublicKey(rng, privateKey, publicKey);
138 
139 		if (FIPS_140_2_ComplianceEnabled())
140 		{
141 			SecByteBlock privateKey2(this->PrivateKeyLength());
142 			this->GeneratePrivateKey(rng, privateKey2);
143 
144 			SecByteBlock publicKey2(this->PublicKeyLength());
145 			Base::GeneratePublicKey(rng, privateKey2, publicKey2);
146 
147 			SecByteBlock agreedValue(this->AgreedValueLength()), agreedValue2(this->AgreedValueLength());
148 			bool agreed1 = this->Agree(agreedValue, privateKey, publicKey2);
149 			bool agreed2 = this->Agree(agreedValue2, privateKey2, publicKey);
150 
151 			if (!agreed1 || !agreed2 || agreedValue != agreedValue2)
152 				throw SelfTestFailure(this->AlgorithmName() + ": pairwise consistency test failed");
153 		}
154 	}
155 
156 	static std::string CRYPTOPP_API StaticAlgorithmName()
157 		{return GroupParameters::StaticAlgorithmNamePrefix() + DH_Algorithm::StaticAlgorithmName();}
158 	std::string AlgorithmName() const {return StaticAlgorithmName();}
159 
160 private:
161 	const DL_KeyAgreementAlgorithm<Element> & GetKeyAgreementAlgorithm() const
162 		{return Singleton<DH_Algorithm>().Ref();}
163 	DL_GroupParameters<Element> & AccessAbstractGroupParameters()
164 		{return m_groupParameters;}
165 
166 	GroupParameters m_groupParameters;
167 };
168 
169 CRYPTOPP_DLL_TEMPLATE_CLASS DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime>;
170 
171 /// \brief Diffie-Hellman in GF(p)
172 /// \details DH() class is a typedef of DH_Domain(). The documentation that follows
173 ///   does not exist. Rather the documentation was created in response to <a href="https://github.com/weidai11/cryptopp/issues/328">Issue
174 ///   328, Diffie-Hellman example code not compiling</a>.
175 /// \details Generally speaking, a DH() object is ephemeral and is intended to execute one instance of the Diffie-Hellman protocol. The
176 ///   private and public key parts are not intended to be set or persisted. Rather, a new set of domain parameters are generated each
177 ///   time an object is created.
178 /// \details Once a DH() object is created, once can retrieve the ephemeral public key for the other party with code similar to the
179 ///   following.
180 /// <pre>   AutoSeededRandomPool prng;
181 ///   Integer p, q, g;
182 ///   PrimeAndGenerator pg;
183 ///
184 ///   pg.Generate(1, prng, 512, 511);
185 ///   p = pg.Prime();
186 ///   q = pg.SubPrime();
187 ///   g = pg.Generator();
188 ///
189 ///   DH dh(p, q, g);
190 ///   SecByteBlock t1(dh.PrivateKeyLength()), t2(dh.PublicKeyLength());
191 ///   dh.GenerateKeyPair(prng, t1, t2);
192 ///   Integer k1(t1, t1.size()), k2(t2, t2.size());
193 ///
194 ///   cout << "Private key:\n";
195 ///   cout << hex << k1 << endl;
196 ///
197 ///   cout << "Public key:\n";
198 ///   cout << hex << k2 << endl;</pre>
199 ///
200 /// \details Output of the program above will be similar to the following.
201 /// <pre>   $ ./cryptest.exe
202 ///   Private key:
203 ///   72b45a42371545e9d4880f48589aefh
204 ///   Public key:
205 ///   45fdb13f97b1840626f0250cec1dba4a23b894100b51fb5d2dd13693d789948f8bfc88f9200014b2
206 ///   ba8dd8a6debc471c69ef1e2326c61184a2eca88ec866346bh</pre>
207 /// \sa <a href="http://www.cryptopp.com/wiki/Diffie-Hellman">Diffie-Hellman on the Crypto++ wiki</a> and
208 ///   <a href="http://www.weidai.com/scan-mirror/ka.html#DH">Diffie-Hellman</a> in GF(p) with key validation
209 /// \since Crypto++ 1.0
210 #if defined(CRYPTOPP_DOXYGEN_PROCESSING)
211 struct DH : public DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime>
212 {
213 	typedef DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime> GroupParameters;
214 	typedef GroupParameters::Element Element;
215 
~DHDH216 	virtual ~DH() {}
217 
218 	/// \brief Create an uninitialized Diffie-Hellman object
DHDH219 	DH() : DH_Domain() {}
220 
221 	/// \brief Initialize a Diffie-Hellman object
222 	/// \param bt BufferedTransformation with group parameters and options
DHDH223 	DH(BufferedTransformation &bt) : DH_Domain(bt) {}
224 
225 	/// \brief Initialize a Diffie-Hellman object
226 	/// \param params group parameters and options
DHDH227 	DH(const GroupParameters &params) : DH_Domain(params) {}
228 
229 	/// \brief Create a Diffie-Hellman object
230 	/// \param rng a RandomNumberGenerator derived class
231 	/// \param modulusBits the size of the modulus, in bits
232 	/// \details This function overload of Initialize() creates a new Diffie-Hellman object because it
233 	///   takes a RandomNumberGenerator() as a parameter.
DHDH234 	DH(RandomNumberGenerator &rng, unsigned int modulusBits) : DH_Domain(rng, modulusBits) {}
235 
236 	/// \brief Initialize a Diffie-Hellman object
237 	/// \param p the modulus
238 	/// \param g the generator
DHDH239 	DH(const Integer &p, const Integer &g) : DH_Domain(p, g) {}
240 
241 	/// \brief Initialize a Diffie-Hellman object
242 	/// \param p the modulus
243 	/// \param q the subgroup order
244 	/// \param g the generator
DHDH245 	DH(const Integer &p, const Integer &q, const Integer &g) : DH_Domain(p, q, g) {}
246 
247 	/// \brief Creates a Diffie-Hellman object
248 	/// \param rng a RandomNumberGenerator derived class
249 	/// \param modulusBits the size of the modulus, in bits
250 	/// \details This function overload of Initialize() creates a new Diffie-Hellman object because it
251 	///   takes a RandomNumberGenerator() as a parameter.
InitializeDH252 	void Initialize(RandomNumberGenerator &rng, unsigned int modulusBits)
253 		{AccessGroupParameters().Initialize(rng, modulusBits);}
254 
255 	/// \brief Initialize a Diffie-Hellman object
256 	/// \param p the modulus
257 	/// \param g the generator
InitializeDH258 	void Initialize(const Integer &p, const Integer &g)
259 		{AccessGroupParameters().Initialize(p, g);}
260 
261 	/// \brief Initialize a Diffie-Hellman object
262 	/// \param p the modulus
263 	/// \param q the subgroup order
264 	/// \param g the generator
InitializeDH265 	void Initialize(const Integer &p, const Integer &q, const Integer &g)
266 		{AccessGroupParameters().Initialize(p, q, g);}
267 };
268 #else
269 // The real DH class is a typedef.
270 typedef DH_Domain<DL_GroupParameters_GFP_DefaultSafePrime> DH;
271 #endif
272 
273 NAMESPACE_END
274 
275 #endif
276