1 /*
2  * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*****************************************************************************
28  BotanDH.cpp
29 
30  Botan Diffie-Hellman asymmetric algorithm implementation
31  *****************************************************************************/
32 
33 #include "config.h"
34 #include "log.h"
35 #include "BotanDH.h"
36 #include "BotanRNG.h"
37 #include "CryptoFactory.h"
38 #include "BotanCryptoFactory.h"
39 #include "DHParameters.h"
40 #include "BotanDHKeyPair.h"
41 #include "BotanUtil.h"
42 #include <algorithm>
43 #include <botan/dl_group.h>
44 #include <botan/dh.h>
45 #include <botan/pubkey.h>
46 #include <botan/version.h>
47 
48 // Signing functions
signInit(PrivateKey *,const AsymMech::Type,const void *,const size_t)49 bool BotanDH::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
50 		       const void* /* param = NULL */, const size_t /* paramLen = 0 */)
51 {
52 	ERROR_MSG("DH does not support signing");
53 
54 	return false;
55 }
56 
signUpdate(const ByteString &)57 bool BotanDH::signUpdate(const ByteString& /*dataToSign*/)
58 {
59 	ERROR_MSG("DH does not support signing");
60 
61 	return false;
62 }
63 
signFinal(ByteString &)64 bool BotanDH::signFinal(ByteString& /*signature*/)
65 {
66 	ERROR_MSG("DH does not support signing");
67 
68 	return false;
69 }
70 
71 // Verification functions
verifyInit(PublicKey *,const AsymMech::Type,const void *,const size_t)72 bool BotanDH::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
73 			 const void* /* param = NULL */, const size_t /* paramLen = 0 */)
74 {
75 	ERROR_MSG("DH does not support verifying");
76 
77 	return false;
78 }
79 
verifyUpdate(const ByteString &)80 bool BotanDH::verifyUpdate(const ByteString& /*originalData*/)
81 {
82 	ERROR_MSG("DH does not support verifying");
83 
84 	return false;
85 }
86 
verifyFinal(const ByteString &)87 bool BotanDH::verifyFinal(const ByteString& /*signature*/)
88 {
89 	ERROR_MSG("DH does not support verifying");
90 
91 	return false;
92 }
93 
94 // Encryption functions
encrypt(PublicKey *,const ByteString &,ByteString &,const AsymMech::Type)95 bool BotanDH::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
96 		      ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
97 {
98 	ERROR_MSG("DH does not support encryption");
99 
100 	return false;
101 }
102 
103 // Decryption functions
decrypt(PrivateKey *,const ByteString &,ByteString &,const AsymMech::Type)104 bool BotanDH::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
105 		      ByteString& /*data*/, const AsymMech::Type /*padding*/)
106 {
107 	ERROR_MSG("DH does not support decryption");
108 
109 	return false;
110 }
111 
112 // Key factory
generateKeyPair(AsymmetricKeyPair ** ppKeyPair,AsymmetricParameters * parameters,RNG *)113 bool BotanDH::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
114 {
115 	// Check parameters
116 	if ((ppKeyPair == NULL) ||
117 	    (parameters == NULL))
118 	{
119 		return false;
120 	}
121 
122 	if (!parameters->areOfType(DHParameters::type))
123 	{
124 		ERROR_MSG("Invalid parameters supplied for DH key generation");
125 
126 		return false;
127 	}
128 
129 	DHParameters* params = (DHParameters*) parameters;
130 
131 	// Generate the key-pair
132 	BotanDH_PrivateKey* dh = NULL;
133 	try
134 	{
135 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
136 
137 		// PKCS#3: 2^(l-1) <= x < 2^l
138 		Botan::BigInt x;
139 		if (params->getXBitLength() > 0)
140 		{
141 			x.randomize(*rng->getRNG(), params->getXBitLength());
142 		}
143 
144 		dh = new BotanDH_PrivateKey(*rng->getRNG(),
145 					Botan::DL_Group(BotanUtil::byteString2bigInt(params->getP()),
146 					BotanUtil::byteString2bigInt(params->getG())),
147 					x);
148 	}
149 	catch (std::exception& e)
150 	{
151 		ERROR_MSG("DH key generation failed with %s", e.what());
152 
153 		return false;
154 	}
155 
156 	// Create an asymmetric key-pair object to return
157 	BotanDHKeyPair* kp = new BotanDHKeyPair();
158 
159 	((BotanDHPublicKey*) kp->getPublicKey())->setFromBotan(dh);
160 	((BotanDHPrivateKey*) kp->getPrivateKey())->setFromBotan(dh);
161 
162 	*ppKeyPair = kp;
163 
164 	// Release the key
165 	delete dh;
166 
167 	return true;
168 }
169 
deriveKey(SymmetricKey ** ppSymmetricKey,PublicKey * publicKey,PrivateKey * privateKey)170 bool BotanDH::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey)
171 {
172 	// Check parameters
173 	if ((ppSymmetricKey == NULL) ||
174 	    (publicKey == NULL) ||
175 	    (privateKey == NULL))
176 	{
177 		return false;
178 	}
179 
180 	// Get keys
181 	Botan::DH_PublicKey* pub = ((BotanDHPublicKey*) publicKey)->getBotanKey();
182 	BotanDH_PrivateKey* priv = ((BotanDHPrivateKey*) privateKey)->getBotanKey();
183 	if (pub == NULL || priv == NULL || priv->impl == NULL)
184 	{
185 		ERROR_MSG("Failed to get Botan DH keys");
186 
187 		return false;
188 	}
189 
190 	// Derive the secret
191 	Botan::SymmetricKey sk;
192 	try
193 	{
194 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
195 		Botan::PK_Key_Agreement ka(*priv->impl, *rng->getRNG(), "Raw");
196 		sk = ka.derive_key(0, pub->public_value());
197 	}
198 	catch (std::exception& e)
199 	{
200 		ERROR_MSG("Botan DH key agreement failed: %s", e.what());
201 
202 		return false;
203 	}
204 
205 	ByteString secret;
206 
207 	// We compensate that Botan removes leading zeros
208 	int size = ((BotanDHPublicKey*) publicKey)->getOutputLength();
209 	int keySize = sk.length();
210 	secret.wipe(size);
211 	memcpy(&secret[0] + size - keySize, sk.begin(), keySize);
212 
213 	*ppSymmetricKey = new SymmetricKey(secret.size() * 8);
214 	if (*ppSymmetricKey == NULL)
215 	{
216 		ERROR_MSG("Can't create DH secret");
217 
218 		return false;
219 	}
220 	if (!(*ppSymmetricKey)->setKeyBits(secret))
221 	{
222 		delete *ppSymmetricKey;
223 		*ppSymmetricKey = NULL;
224 		return false;
225 	}
226 
227 	return true;
228 }
229 
getMinKeySize()230 unsigned long BotanDH::getMinKeySize()
231 {
232 	return 512;
233 }
234 
getMaxKeySize()235 unsigned long BotanDH::getMaxKeySize()
236 {
237 	return 4096;
238 }
239 
generateParameters(AsymmetricParameters ** ppParams,void * parameters,RNG *)240 bool BotanDH::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
241 {
242 	if ((ppParams == NULL) || (parameters == NULL))
243 	{
244 		return false;
245 	}
246 
247 	size_t bitLen = (size_t) parameters;
248 
249 	if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
250 	{
251 		ERROR_MSG("This DH key size is not supported");
252 
253 		return false;
254 	}
255 
256 	Botan::DL_Group* group = NULL;
257 	try
258 	{
259 		BotanRNG* brng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
260 		group = new Botan::DL_Group(*brng->getRNG(), Botan::DL_Group::Strong, bitLen);
261 	}
262 	catch (std::exception& e)
263 	{
264 		ERROR_MSG("Failed to generate %d bit DH parameters: %s", bitLen, e.what());
265 
266 		return false;
267 	}
268 
269 	// Store the DH parameters
270 	DHParameters* params = new DHParameters();
271 
272 	ByteString p = BotanUtil::bigInt2ByteString(group->get_p());
273 	params->setP(p);
274 	ByteString g = BotanUtil::bigInt2ByteString(group->get_g());
275 	params->setG(g);
276 
277 	*ppParams = params;
278 
279 	delete group;
280 
281 	return true;
282 }
283 
reconstructKeyPair(AsymmetricKeyPair ** ppKeyPair,ByteString & serialisedData)284 bool BotanDH::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
285 {
286 	// Check input
287 	if ((ppKeyPair == NULL) ||
288 	    (serialisedData.size() == 0))
289 	{
290 		return false;
291 	}
292 
293 	ByteString dPub = ByteString::chainDeserialise(serialisedData);
294 	ByteString dPriv = ByteString::chainDeserialise(serialisedData);
295 
296 	BotanDHKeyPair* kp = new BotanDHKeyPair();
297 
298 	bool rv = true;
299 
300 	if (!((DHPublicKey*) kp->getPublicKey())->deserialise(dPub))
301 	{
302 		rv = false;
303 	}
304 
305 	if (!((DHPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
306 	{
307 		rv = false;
308 	}
309 
310 	if (!rv)
311 	{
312 		delete kp;
313 
314 		return false;
315 	}
316 
317 	*ppKeyPair = kp;
318 
319 	return true;
320 }
321 
reconstructPublicKey(PublicKey ** ppPublicKey,ByteString & serialisedData)322 bool BotanDH::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
323 {
324 	// Check input
325 	if ((ppPublicKey == NULL) ||
326 	    (serialisedData.size() == 0))
327 	{
328 		return false;
329 	}
330 
331 	BotanDHPublicKey* pub = new BotanDHPublicKey();
332 
333 	if (!pub->deserialise(serialisedData))
334 	{
335 		delete pub;
336 
337 		return false;
338 	}
339 
340 	*ppPublicKey = pub;
341 
342 	return true;
343 }
344 
reconstructPrivateKey(PrivateKey ** ppPrivateKey,ByteString & serialisedData)345 bool BotanDH::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
346 {
347 	// Check input
348 	if ((ppPrivateKey == NULL) ||
349 	    (serialisedData.size() == 0))
350 	{
351 		return false;
352 	}
353 
354 	BotanDHPrivateKey* priv = new BotanDHPrivateKey();
355 
356 	if (!priv->deserialise(serialisedData))
357 	{
358 		delete priv;
359 
360 		return false;
361 	}
362 
363 	*ppPrivateKey = priv;
364 
365 	return true;
366 }
367 
newPublicKey()368 PublicKey* BotanDH::newPublicKey()
369 {
370 	return (PublicKey*) new BotanDHPublicKey();
371 }
372 
newPrivateKey()373 PrivateKey* BotanDH::newPrivateKey()
374 {
375 	return (PrivateKey*) new BotanDHPrivateKey();
376 }
377 
newParameters()378 AsymmetricParameters* BotanDH::newParameters()
379 {
380 	return (AsymmetricParameters*) new DHParameters();
381 }
382 
reconstructParameters(AsymmetricParameters ** ppParams,ByteString & serialisedData)383 bool BotanDH::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
384 {
385 	// Check input parameters
386 	if ((ppParams == NULL) || (serialisedData.size() == 0))
387 	{
388 		return false;
389 	}
390 
391 	DHParameters* params = new DHParameters();
392 
393 	if (!params->deserialise(serialisedData))
394 	{
395 		delete params;
396 
397 		return false;
398 	}
399 
400 	*ppParams = params;
401 
402 	return true;
403 }
404 
405