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 BotanDSA.cpp
29
30 Botan DSA asymmetric algorithm implementation
31 *****************************************************************************/
32
33 #include "config.h"
34 #include "log.h"
35 #include "BotanDSA.h"
36 #include "BotanRNG.h"
37 #include "CryptoFactory.h"
38 #include "BotanCryptoFactory.h"
39 #include "DSAParameters.h"
40 #include "BotanDSAKeyPair.h"
41 #include "BotanUtil.h"
42 #include <algorithm>
43 #include <botan/dl_group.h>
44 #include <botan/dsa.h>
45 #include <iostream>
46
47 // Constructor
BotanDSA()48 BotanDSA::BotanDSA()
49 {
50 signer = NULL;
51 verifier = NULL;
52 }
53
54 // Destructor
~BotanDSA()55 BotanDSA::~BotanDSA()
56 {
57 delete signer;
58 delete verifier;
59 }
60
61 // Signing functions
sign(PrivateKey * privateKey,const ByteString & dataToSign,ByteString & signature,const AsymMech::Type mechanism,const void * param,const size_t paramLen)62 bool BotanDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
63 ByteString& signature, const AsymMech::Type mechanism,
64 const void* param /* = NULL */, const size_t paramLen /* = 0 */)
65 {
66 std::string emsa;
67
68 if (mechanism == AsymMech::DSA)
69 {
70 emsa = "Raw";
71 }
72 else
73 {
74 // Call default implementation
75 return AsymmetricAlgorithm::sign(privateKey, dataToSign, signature, mechanism, param, paramLen);
76 }
77
78 // Check if the private key is the right type
79 if (!privateKey->isOfType(BotanDSAPrivateKey::type))
80 {
81 ERROR_MSG("Invalid key type supplied");
82
83 return false;
84 }
85
86 BotanDSAPrivateKey* pk = (BotanDSAPrivateKey*) privateKey;
87 Botan::DSA_PrivateKey* botanKey = pk->getBotanKey();
88
89 if (!botanKey)
90 {
91 ERROR_MSG("Could not get the Botan private key");
92
93 return false;
94 }
95
96 try
97 {
98 BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
99 signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
100 }
101 catch (...)
102 {
103 ERROR_MSG("Could not create the signer token");
104
105 return false;
106 }
107
108 // Perform the signature operation
109 std::vector<uint8_t> signResult;
110 try
111 {
112 BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
113 signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
114 }
115 catch (...)
116 {
117 ERROR_MSG("Could not sign the data");
118
119 delete signer;
120 signer = NULL;
121
122 return false;
123 }
124
125 // Return the result
126 signature.resize(signResult.size());
127 memcpy(&signature[0], signResult.data(), signResult.size());
128
129 delete signer;
130 signer = NULL;
131
132 return true;
133 }
134
signInit(PrivateKey * privateKey,const AsymMech::Type mechanism,const void * param,const size_t paramLen)135 bool BotanDSA::signInit(PrivateKey* privateKey, const AsymMech::Type mechanism,
136 const void* param /* = NULL */, const size_t paramLen /* = 0 */)
137 {
138 if (!AsymmetricAlgorithm::signInit(privateKey, mechanism, param, paramLen))
139 {
140 return false;
141 }
142
143 // Check if the private key is the right type
144 if (!privateKey->isOfType(BotanDSAPrivateKey::type))
145 {
146 ERROR_MSG("Invalid key type supplied");
147
148 ByteString dummy;
149 AsymmetricAlgorithm::signFinal(dummy);
150
151 return false;
152 }
153
154 std::string emsa;
155
156 switch (mechanism)
157 {
158 case AsymMech::DSA_SHA1:
159 emsa = "EMSA1(SHA-160)";
160 break;
161 case AsymMech::DSA_SHA224:
162 emsa = "EMSA1(SHA-224)";
163 break;
164 case AsymMech::DSA_SHA256:
165 emsa = "EMSA1(SHA-256)";
166 break;
167 case AsymMech::DSA_SHA384:
168 emsa = "EMSA1(SHA-384)";
169 break;
170 case AsymMech::DSA_SHA512:
171 emsa = "EMSA1(SHA-512)";
172 break;
173 default:
174 ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
175
176 ByteString dummy;
177 AsymmetricAlgorithm::signFinal(dummy);
178
179 return false;
180 }
181
182 BotanDSAPrivateKey* pk = (BotanDSAPrivateKey*) currentPrivateKey;
183 Botan::DSA_PrivateKey* botanKey = pk->getBotanKey();
184
185 if (!botanKey)
186 {
187 ERROR_MSG("Could not get the Botan private key");
188
189 ByteString dummy;
190 AsymmetricAlgorithm::signFinal(dummy);
191
192 return false;
193 }
194
195 try
196 {
197 BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
198 signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
199 }
200 catch (...)
201 {
202 ERROR_MSG("Could not create the signer token");
203
204 ByteString dummy;
205 AsymmetricAlgorithm::signFinal(dummy);
206
207 return false;
208 }
209
210 return true;
211 }
212
signUpdate(const ByteString & dataToSign)213 bool BotanDSA::signUpdate(const ByteString& dataToSign)
214 {
215 if (!AsymmetricAlgorithm::signUpdate(dataToSign))
216 {
217 return false;
218 }
219
220 try
221 {
222 if (dataToSign.size() != 0)
223 {
224 signer->update(dataToSign.const_byte_str(),
225 dataToSign.size());
226 }
227 }
228 catch (...)
229 {
230 ERROR_MSG("Could not add data to signer token");
231
232 ByteString dummy;
233 AsymmetricAlgorithm::signFinal(dummy);
234
235 delete signer;
236 signer = NULL;
237
238 return false;
239 }
240
241 return true;
242 }
243
signFinal(ByteString & signature)244 bool BotanDSA::signFinal(ByteString& signature)
245 {
246 if (!AsymmetricAlgorithm::signFinal(signature))
247 {
248 return false;
249 }
250
251 // Perform the signature operation
252 std::vector<uint8_t> signResult;
253 try
254 {
255 BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
256 signResult = signer->signature(*rng->getRNG());
257 }
258 catch (...)
259 {
260 ERROR_MSG("Could not sign the data");
261
262 delete signer;
263 signer = NULL;
264
265 return false;
266 }
267
268 // Return the result
269 signature.resize(signResult.size());
270 memcpy(&signature[0], signResult.data(), signResult.size());
271
272 delete signer;
273 signer = NULL;
274
275 return true;
276 }
277
278 // Verification functions
verify(PublicKey * publicKey,const ByteString & originalData,const ByteString & signature,const AsymMech::Type mechanism,const void * param,const size_t paramLen)279 bool BotanDSA::verify(PublicKey* publicKey, const ByteString& originalData,
280 const ByteString& signature, const AsymMech::Type mechanism,
281 const void* param /* = NULL */, const size_t paramLen /* = 0 */)
282 {
283 std::string emsa;
284
285 if (mechanism == AsymMech::DSA)
286 {
287 emsa = "Raw";
288 }
289 else
290 {
291 // Call the generic function
292 return AsymmetricAlgorithm::verify(publicKey, originalData, signature, mechanism, param, paramLen);
293 }
294
295 // Check if the public key is the right type
296 if (!publicKey->isOfType(BotanDSAPublicKey::type))
297 {
298 ERROR_MSG("Invalid key type supplied");
299
300 return false;
301 }
302
303 BotanDSAPublicKey* pk = (BotanDSAPublicKey*) publicKey;
304 Botan::DSA_PublicKey* botanKey = pk->getBotanKey();
305
306 if (!botanKey)
307 {
308 ERROR_MSG("Could not get the Botan public key");
309
310 return false;
311 }
312
313 try
314 {
315 verifier = new Botan::PK_Verifier(*botanKey, emsa);
316 }
317 catch (...)
318 {
319 ERROR_MSG("Could not create the verifier token");
320
321 return false;
322 }
323
324 // Perform the verify operation
325 bool verResult;
326 try
327 {
328 verResult = verifier->verify_message(originalData.const_byte_str(),
329 originalData.size(),
330 signature.const_byte_str(),
331 signature.size());
332 }
333 catch (...)
334 {
335 ERROR_MSG("Could not check the signature");
336
337 delete verifier;
338 verifier = NULL;
339
340 return false;
341 }
342
343 delete verifier;
344 verifier = NULL;
345
346 return verResult;
347 }
348
verifyInit(PublicKey * publicKey,const AsymMech::Type mechanism,const void * param,const size_t paramLen)349 bool BotanDSA::verifyInit(PublicKey* publicKey, const AsymMech::Type mechanism,
350 const void* param /* = NULL */, const size_t paramLen /* = 0 */)
351 {
352 if (!AsymmetricAlgorithm::verifyInit(publicKey, mechanism, param, paramLen))
353 {
354 return false;
355 }
356
357 // Check if the public key is the right type
358 if (!publicKey->isOfType(BotanDSAPublicKey::type))
359 {
360 ERROR_MSG("Invalid key type supplied");
361
362 ByteString dummy;
363 AsymmetricAlgorithm::verifyFinal(dummy);
364
365 return false;
366 }
367
368 std::string emsa;
369
370 switch (mechanism)
371 {
372 case AsymMech::DSA_SHA1:
373 emsa = "EMSA1(SHA-160)";
374 break;
375 case AsymMech::DSA_SHA224:
376 emsa = "EMSA1(SHA-224)";
377 break;
378 case AsymMech::DSA_SHA256:
379 emsa = "EMSA1(SHA-256)";
380 break;
381 case AsymMech::DSA_SHA384:
382 emsa = "EMSA1(SHA-384)";
383 break;
384 case AsymMech::DSA_SHA512:
385 emsa = "EMSA1(SHA-512)";
386 break;
387 default:
388 ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
389
390 ByteString dummy;
391 AsymmetricAlgorithm::verifyFinal(dummy);
392
393 return false;
394 }
395
396 BotanDSAPublicKey* pk = (BotanDSAPublicKey*) currentPublicKey;
397 Botan::DSA_PublicKey* botanKey = pk->getBotanKey();
398
399 if (!botanKey)
400 {
401 ERROR_MSG("Could not get the Botan public key");
402
403 ByteString dummy;
404 AsymmetricAlgorithm::verifyFinal(dummy);
405
406 return false;
407 }
408
409 try
410 {
411 verifier = new Botan::PK_Verifier(*botanKey, emsa);
412 }
413 catch (...)
414 {
415 ERROR_MSG("Could not create the verifier token");
416
417 ByteString dummy;
418 AsymmetricAlgorithm::verifyFinal(dummy);
419
420 return false;
421 }
422
423 return true;
424 }
425
verifyUpdate(const ByteString & originalData)426 bool BotanDSA::verifyUpdate(const ByteString& originalData)
427 {
428 if (!AsymmetricAlgorithm::verifyUpdate(originalData))
429 {
430 return false;
431 }
432
433 try
434 {
435 if (originalData.size() != 0)
436 {
437 verifier->update(originalData.const_byte_str(),
438 originalData.size());
439 }
440 }
441 catch (...)
442 {
443 ERROR_MSG("Could not add data to the verifier token");
444
445 ByteString dummy;
446 AsymmetricAlgorithm::verifyFinal(dummy);
447
448 delete verifier;
449 verifier = NULL;
450
451 return false;
452 }
453
454 return true;
455 }
456
verifyFinal(const ByteString & signature)457 bool BotanDSA::verifyFinal(const ByteString& signature)
458 {
459 if (!AsymmetricAlgorithm::verifyFinal(signature))
460 {
461 return false;
462 }
463
464 // Perform the verify operation
465 bool verResult;
466 try
467 {
468 verResult = verifier->check_signature(signature.const_byte_str(), signature.size());
469 }
470 catch (...)
471 {
472 ERROR_MSG("Could not check the signature");
473
474 delete verifier;
475 verifier = NULL;
476
477 return false;
478 }
479
480 delete verifier;
481 verifier = NULL;
482
483 return verResult;
484 }
485
486 // Encryption functions
encrypt(PublicKey *,const ByteString &,ByteString &,const AsymMech::Type)487 bool BotanDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
488 ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
489 {
490 ERROR_MSG("DSA does not support encryption");
491
492 return false;
493 }
494
495 // Decryption functions
decrypt(PrivateKey *,const ByteString &,ByteString &,const AsymMech::Type)496 bool BotanDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
497 ByteString& /*data*/, const AsymMech::Type /*padding*/)
498 {
499 ERROR_MSG("DSA does not support decryption");
500
501 return false;
502 }
503
504 // Key factory
generateKeyPair(AsymmetricKeyPair ** ppKeyPair,AsymmetricParameters * parameters,RNG *)505 bool BotanDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
506 {
507 // Check parameters
508 if ((ppKeyPair == NULL) ||
509 (parameters == NULL))
510 {
511 return false;
512 }
513
514 if (!parameters->areOfType(DSAParameters::type))
515 {
516 ERROR_MSG("Invalid parameters supplied for DSA key generation");
517
518 return false;
519 }
520
521 DSAParameters* params = (DSAParameters*) parameters;
522
523 // Generate the key-pair
524 Botan::DSA_PrivateKey* dsa = NULL;
525 try
526 {
527 BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
528 dsa = new Botan::DSA_PrivateKey(*rng->getRNG(),
529 Botan::DL_Group(BotanUtil::byteString2bigInt(params->getP()),
530 BotanUtil::byteString2bigInt(params->getQ()),
531 BotanUtil::byteString2bigInt(params->getG())));
532 }
533 catch (...)
534 {
535 ERROR_MSG("DSA key generation failed");
536
537 return false;
538 }
539
540 // Create an asymmetric key-pair object to return
541 BotanDSAKeyPair* kp = new BotanDSAKeyPair();
542
543 ((BotanDSAPublicKey*) kp->getPublicKey())->setFromBotan(dsa);
544 ((BotanDSAPrivateKey*) kp->getPrivateKey())->setFromBotan(dsa);
545
546 *ppKeyPair = kp;
547
548 // Release the key
549 delete dsa;
550
551 return true;
552 }
553
getMinKeySize()554 unsigned long BotanDSA::getMinKeySize()
555 {
556 return 512;
557 }
558
getMaxKeySize()559 unsigned long BotanDSA::getMaxKeySize()
560 {
561 // Taken from OpenSSL
562 return 10000;
563 }
564
generateParameters(AsymmetricParameters ** ppParams,void * parameters,RNG *)565 bool BotanDSA::generateParameters(AsymmetricParameters** ppParams, void* parameters /* = NULL */, RNG* /*rng = NULL*/)
566 {
567 if ((ppParams == NULL) || (parameters == NULL))
568 {
569 return false;
570 }
571
572 size_t bitLen = (size_t) parameters;
573
574 if (bitLen < getMinKeySize() || bitLen > getMaxKeySize())
575 {
576 ERROR_MSG("This DSA key size is not supported");
577
578 return false;
579 }
580
581 Botan::DL_Group* group = NULL;
582 // Taken from OpenSSL
583 size_t qLen = bitLen >= 2048 ? 256 : 160;
584 try
585 {
586 BotanRNG* brng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
587 group = new Botan::DL_Group(*brng->getRNG(), Botan::DL_Group::Prime_Subgroup, bitLen, qLen);
588 }
589 catch (std::exception& e)
590 {
591 ERROR_MSG("Failed to generate %d bit DSA parameters: %s", bitLen, e.what());
592
593 return false;
594 }
595
596 // Store the DSA parameters
597 DSAParameters* params = new DSAParameters();
598
599 ByteString p = BotanUtil::bigInt2ByteString(group->get_p());
600 params->setP(p);
601 ByteString q = BotanUtil::bigInt2ByteString(group->get_q());
602 params->setQ(q);
603 ByteString g = BotanUtil::bigInt2ByteString(group->get_g());
604 params->setG(g);
605
606 *ppParams = params;
607
608 delete group;
609
610 return true;
611 }
612
reconstructKeyPair(AsymmetricKeyPair ** ppKeyPair,ByteString & serialisedData)613 bool BotanDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
614 {
615 // Check input
616 if ((ppKeyPair == NULL) ||
617 (serialisedData.size() == 0))
618 {
619 return false;
620 }
621
622 ByteString dPub = ByteString::chainDeserialise(serialisedData);
623 ByteString dPriv = ByteString::chainDeserialise(serialisedData);
624
625 BotanDSAKeyPair* kp = new BotanDSAKeyPair();
626
627 bool rv = true;
628
629 if (!((DSAPublicKey*) kp->getPublicKey())->deserialise(dPub))
630 {
631 rv = false;
632 }
633
634 if (!((DSAPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
635 {
636 rv = false;
637 }
638
639 if (!rv)
640 {
641 delete kp;
642
643 return false;
644 }
645
646 *ppKeyPair = kp;
647
648 return true;
649 }
650
reconstructPublicKey(PublicKey ** ppPublicKey,ByteString & serialisedData)651 bool BotanDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
652 {
653 // Check input
654 if ((ppPublicKey == NULL) ||
655 (serialisedData.size() == 0))
656 {
657 return false;
658 }
659
660 BotanDSAPublicKey* pub = new BotanDSAPublicKey();
661
662 if (!pub->deserialise(serialisedData))
663 {
664 delete pub;
665
666 return false;
667 }
668
669 *ppPublicKey = pub;
670
671 return true;
672 }
673
reconstructPrivateKey(PrivateKey ** ppPrivateKey,ByteString & serialisedData)674 bool BotanDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
675 {
676 // Check input
677 if ((ppPrivateKey == NULL) ||
678 (serialisedData.size() == 0))
679 {
680 return false;
681 }
682
683 BotanDSAPrivateKey* priv = new BotanDSAPrivateKey();
684
685 if (!priv->deserialise(serialisedData))
686 {
687 delete priv;
688
689 return false;
690 }
691
692 *ppPrivateKey = priv;
693
694 return true;
695 }
696
newPublicKey()697 PublicKey* BotanDSA::newPublicKey()
698 {
699 return (PublicKey*) new BotanDSAPublicKey();
700 }
701
newPrivateKey()702 PrivateKey* BotanDSA::newPrivateKey()
703 {
704 return (PrivateKey*) new BotanDSAPrivateKey();
705 }
706
newParameters()707 AsymmetricParameters* BotanDSA::newParameters()
708 {
709 return (AsymmetricParameters*) new DSAParameters();
710 }
711
reconstructParameters(AsymmetricParameters ** ppParams,ByteString & serialisedData)712 bool BotanDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
713 {
714 // Check input parameters
715 if ((ppParams == NULL) || (serialisedData.size() == 0))
716 {
717 return false;
718 }
719
720 DSAParameters* params = new DSAParameters();
721
722 if (!params->deserialise(serialisedData))
723 {
724 delete params;
725
726 return false;
727 }
728
729 *ppParams = params;
730
731 return true;
732 }
733
734