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