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  BotanEDDSA.cpp
29 
30  Botan EDDSA asymmetric algorithm implementation
31  *****************************************************************************/
32 
33 #include "config.h"
34 #ifdef WITH_EDDSA
35 #include "log.h"
36 #include "BotanEDDSA.h"
37 #include "BotanRNG.h"
38 #include "CryptoFactory.h"
39 #include "BotanCryptoFactory.h"
40 #include "ECParameters.h"
41 #include "BotanEDKeyPair.h"
42 #include "BotanUtil.h"
43 #include <algorithm>
44 #include <botan/curve25519.h>
45 #include <botan/ed25519.h>
46 // #include <botan/curve448.h>
47 // #include <botan/ed448.h>
48 #include <botan/version.h>
49 #include <iostream>
50 
51 // Constructor
BotanEDDSA()52 BotanEDDSA::BotanEDDSA()
53 {
54 	signer = NULL;
55 	verifier = NULL;
56 }
57 
58 // Destructor
~BotanEDDSA()59 BotanEDDSA::~BotanEDDSA()
60 {
61 	delete signer;
62 	delete verifier;
63 }
64 
65 // Signing functions
sign(PrivateKey * privateKey,const ByteString & dataToSign,ByteString & signature,const AsymMech::Type mechanism,const void *,const size_t)66 bool BotanEDDSA::sign(PrivateKey* privateKey, const ByteString& dataToSign,
67 		      ByteString& signature, const AsymMech::Type mechanism,
68 		      const void* /* param = NULL */, const size_t /* paramLen = 0 */)
69 {
70 	std::string emsa;
71 
72 	if (mechanism == AsymMech::EDDSA)
73 	{
74 		emsa = "Pure";
75 	}
76         else
77         {
78 		ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
79 		return false;
80         }
81 
82 	// Check if the private key is the right type
83 	if (!privateKey->isOfType(BotanEDPrivateKey::type))
84 	{
85 		ERROR_MSG("Invalid key type supplied");
86 
87 		return false;
88 	}
89 
90         BotanEDPrivateKey* pk = (BotanEDPrivateKey*) privateKey;
91         Botan::Ed25519_PrivateKey* botanKey = dynamic_cast<Botan::Ed25519_PrivateKey*>(pk->getBotanKey());
92 
93         if (botanKey == NULL)
94         {
95 		ERROR_MSG("Could not get the Botan private key");
96 
97 		return false;
98 	}
99 
100 	try
101 	{
102 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
103 		signer = new Botan::PK_Signer(*botanKey, *rng->getRNG(), emsa);
104 	}
105 	catch (...)
106 	{
107 		ERROR_MSG("Could not create the signer token");
108 
109 		return false;
110 	}
111 
112 	// Perform the signature operation
113 	std::vector<uint8_t> signResult;
114 	try
115 	{
116 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
117 		signResult = signer->sign_message(dataToSign.const_byte_str(), dataToSign.size(), *rng->getRNG());
118 	}
119 	catch (...)
120 	{
121 		ERROR_MSG("Could not sign the data");
122 
123 		delete signer;
124 		signer = NULL;
125 
126 		return false;
127 	}
128 
129 	// Return the result
130 	signature.resize(signResult.size());
131 	memcpy(&signature[0], signResult.data(), signResult.size());
132 
133 	delete signer;
134 	signer = NULL;
135 
136 	return true;
137 }
138 
139 // Signing functions
signInit(PrivateKey *,const AsymMech::Type,const void *,const size_t)140 bool BotanEDDSA::signInit(PrivateKey* /*privateKey*/, const AsymMech::Type /*mechanism*/,
141 			  const void* /* param = NULL */, const size_t /* paramLen = 0 */)
142 {
143 	ERROR_MSG("EDDSA does not support multi part signing");
144 
145 	return false;
146 }
147 
signUpdate(const ByteString &)148 bool BotanEDDSA::signUpdate(const ByteString& /*dataToSign*/)
149 {
150 	ERROR_MSG("EDDSA does not support multi part signing");
151 
152 	return false;
153 }
154 
signFinal(ByteString &)155 bool BotanEDDSA::signFinal(ByteString& /*signature*/)
156 {
157 	ERROR_MSG("EDDSA does not support multi part signing");
158 
159 	return false;
160 }
161 
162 // Verification functions
verify(PublicKey * publicKey,const ByteString & originalData,const ByteString & signature,const AsymMech::Type mechanism,const void *,const size_t)163 bool BotanEDDSA::verify(PublicKey* publicKey, const ByteString& originalData,
164 			const ByteString& signature, const AsymMech::Type mechanism,
165 			const void* /* param = NULL */, const size_t /* paramLen = 0 */)
166 {
167 	std::string emsa;
168 
169 	if (mechanism == AsymMech::EDDSA)
170 	{
171 		emsa = "Pure";
172 	}
173         else
174         {
175 		ERROR_MSG("Invalid mechanism supplied (%i)", mechanism);
176 
177 		return false;
178 	}
179 
180 	// Check if the public key is the right type
181 	if (!publicKey->isOfType(BotanEDPublicKey::type))
182 	{
183 		ERROR_MSG("Invalid key type supplied");
184 
185 		return false;
186 	}
187 
188 	BotanEDPublicKey* pk = (BotanEDPublicKey*) publicKey;
189 	Botan::Ed25519_PublicKey* botanKey = dynamic_cast<Botan::Ed25519_PublicKey*>(pk->getBotanKey());
190 
191 	if (botanKey == NULL)
192 	{
193 		ERROR_MSG("Could not get the Botan public key");
194 
195 		return false;
196 	}
197 
198 	try
199 	{
200 		verifier = new Botan::PK_Verifier(*botanKey, emsa);
201 	}
202 	catch (...)
203 	{
204 		ERROR_MSG("Could not create the verifier token");
205 
206 		return false;
207 	}
208 
209 	// Perform the verify operation
210 	bool verResult;
211 	try
212 	{
213 		verResult = verifier->verify_message(originalData.const_byte_str(),
214 							originalData.size(),
215 							signature.const_byte_str(),
216 							signature.size());
217 	}
218 	catch (...)
219 	{
220 		ERROR_MSG("Could not check the signature");
221 
222 		delete verifier;
223 		verifier = NULL;
224 
225 		return false;
226 	}
227 
228 	delete verifier;
229 	verifier = NULL;
230 
231 	return verResult;
232 }
233 
234 // Verification functions
verifyInit(PublicKey *,const AsymMech::Type,const void *,const size_t)235 bool BotanEDDSA::verifyInit(PublicKey* /*publicKey*/, const AsymMech::Type /*mechanism*/,
236 			    const void* /* param = NULL */, const size_t /* paramLen = 0 */)
237 {
238 	ERROR_MSG("EDDSA does not support multi part verifying");
239 
240 	return false;
241 }
242 
verifyUpdate(const ByteString &)243 bool BotanEDDSA::verifyUpdate(const ByteString& /*originalData*/)
244 {
245 	ERROR_MSG("EDDSA does not support multi part verifying");
246 
247 	return false;
248 }
249 
verifyFinal(const ByteString &)250 bool BotanEDDSA::verifyFinal(const ByteString& /*signature*/)
251 {
252 	ERROR_MSG("EDDSA does not support multi part verifying");
253 
254 	return false;
255 }
256 
257 // Encryption functions
encrypt(PublicKey *,const ByteString &,ByteString &,const AsymMech::Type)258 bool BotanEDDSA::encrypt(PublicKey* /*publicKey*/, const ByteString& /*data*/,
259 			 ByteString& /*encryptedData*/, const AsymMech::Type /*padding*/)
260 {
261 	ERROR_MSG("EDDSA does not support encryption");
262 
263 	return false;
264 }
265 
266 // Decryption functions
decrypt(PrivateKey *,const ByteString &,ByteString &,const AsymMech::Type)267 bool BotanEDDSA::decrypt(PrivateKey* /*privateKey*/, const ByteString& /*encryptedData*/,
268 			 ByteString& /*data*/, const AsymMech::Type /*padding*/)
269 {
270 	ERROR_MSG("EDDSA does not support decryption");
271 
272 	return false;
273 }
274 
275 // Key factory
generateKeyPair(AsymmetricKeyPair ** ppKeyPair,AsymmetricParameters * parameters,RNG *)276 bool BotanEDDSA::generateKeyPair(AsymmetricKeyPair** ppKeyPair, AsymmetricParameters* parameters, RNG* /*rng = NULL */)
277 {
278 	// Check parameters
279 	if ((ppKeyPair == NULL) ||
280 	    (parameters == NULL))
281 	{
282 		return false;
283 	}
284 
285 	if (!parameters->areOfType(ECParameters::type))
286 	{
287 		ERROR_MSG("Invalid parameters supplied for EDDSA key generation");
288 
289 		return false;
290 	}
291 
292 	ECParameters* params = (ECParameters*) parameters;
293 	Botan::OID oid = BotanUtil::byteString2Oid(params->getEC());
294 
295 	// Generate the key-pair
296 	Botan::Private_Key* eckp = NULL;
297 	try
298 	{
299 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
300 		if (oid == BotanUtil::x25519_oid)
301 		{
302 			eckp = new Botan::Curve25519_PrivateKey(*rng->getRNG());
303 		}
304 		else if (oid == BotanUtil::ed25519_oid)
305 		{
306 			eckp = new Botan::Ed25519_PrivateKey(*rng->getRNG());
307 		}
308 		else
309 		{
310 			return false;
311 		}
312 	}
313 	catch (...)
314 	{
315 		ERROR_MSG("EDDSA key generation failed");
316 
317 		return false;
318 	}
319 
320 	// Create an asymmetric key-pair object to return
321 	BotanEDKeyPair* kp = new BotanEDKeyPair();
322 
323 	((BotanEDPublicKey*) kp->getPublicKey())->setFromBotan(eckp);
324 	((BotanEDPrivateKey*) kp->getPrivateKey())->setFromBotan(eckp);
325 
326 	*ppKeyPair = kp;
327 
328 	// Release the key
329 	delete eckp;
330 
331 	return true;
332 }
333 
deriveKey(SymmetricKey ** ppSymmetricKey,PublicKey * publicKey,PrivateKey * privateKey)334 bool BotanEDDSA::deriveKey(SymmetricKey **ppSymmetricKey, PublicKey* publicKey, PrivateKey* privateKey)
335 {
336 	// Check parameters
337 	if ((ppSymmetricKey == NULL) ||
338 	    (publicKey == NULL) ||
339 	    (privateKey == NULL))
340 	{
341 		return false;
342 	}
343 
344 	// Get keys
345 	BotanEDPublicKey* pubk = (BotanEDPublicKey*) publicKey;
346 	Botan::Curve25519_PublicKey* pub = dynamic_cast<Botan::Curve25519_PublicKey*>(pubk->getBotanKey());
347 	BotanEDPrivateKey* privk = (BotanEDPrivateKey*) privateKey;
348 	Botan::Curve25519_PrivateKey* priv = dynamic_cast<Botan::Curve25519_PrivateKey*>(privk->getBotanKey());
349 	if (pub == NULL || priv == NULL)
350 	{
351 		ERROR_MSG("Failed to get Botan EDDSA keys");
352 
353 		return false;
354 	}
355 
356 	// Derive the secret
357 	Botan::SymmetricKey sk;
358 	try
359 	{
360 		BotanRNG* rng = (BotanRNG*)BotanCryptoFactory::i()->getRNG();
361 		Botan::PK_Key_Agreement ka(*priv, *rng->getRNG(), "Raw");
362 		sk = ka.derive_key(0, pub->public_value());
363 	}
364 	catch (...)
365 	{
366 		ERROR_MSG("Botan EDDSA key agreement failed");
367 
368 		return false;
369 	}
370 
371 	ByteString secret;
372 
373 	// We compensate that Botan removes leading zeros
374 	int size = pubk->getOrderLength();
375 	int keySize = sk.length();
376 	secret.wipe(size);
377 	memcpy(&secret[0] + size - keySize, sk.begin(), keySize);
378 
379 	*ppSymmetricKey = new SymmetricKey(secret.size() * 8);
380 	if (*ppSymmetricKey == NULL)
381 	{
382 		ERROR_MSG("Can't create EDDSA secret");
383 
384 		return false;
385 	}
386 	if (!(*ppSymmetricKey)->setKeyBits(secret))
387 	{
388 		delete *ppSymmetricKey;
389 		*ppSymmetricKey = NULL;
390 		return false;
391 	}
392 
393 	return true;
394 }
395 
getMinKeySize()396 unsigned long BotanEDDSA::getMinKeySize()
397 {
398 	// Only Ed25519 is supported
399 	return 32*8;
400 }
401 
getMaxKeySize()402 unsigned long BotanEDDSA::getMaxKeySize()
403 {
404 	// Only Ed25519 is supported
405 	return 32*8;
406 }
407 
reconstructKeyPair(AsymmetricKeyPair ** ppKeyPair,ByteString & serialisedData)408 bool BotanEDDSA::reconstructKeyPair(AsymmetricKeyPair** ppKeyPair, ByteString& serialisedData)
409 {
410 	// Check input
411 	if ((ppKeyPair == NULL) ||
412 	    (serialisedData.size() == 0))
413 	{
414 		return false;
415 	}
416 
417 	ByteString dPub = ByteString::chainDeserialise(serialisedData);
418 	ByteString dPriv = ByteString::chainDeserialise(serialisedData);
419 
420 	BotanEDKeyPair* kp = new BotanEDKeyPair();
421 
422 	bool rv = true;
423 
424 	if (!((EDPublicKey*) kp->getPublicKey())->deserialise(dPub))
425 	{
426 		rv = false;
427 	}
428 
429 	if (!((EDPrivateKey*) kp->getPrivateKey())->deserialise(dPriv))
430 	{
431 		rv = false;
432 	}
433 
434 	if (!rv)
435 	{
436 		delete kp;
437 
438 		return false;
439 	}
440 
441 	*ppKeyPair = kp;
442 
443 	return true;
444 }
445 
reconstructPublicKey(PublicKey ** ppPublicKey,ByteString & serialisedData)446 bool BotanEDDSA::reconstructPublicKey(PublicKey** ppPublicKey, ByteString& serialisedData)
447 {
448 	// Check input
449 	if ((ppPublicKey == NULL) ||
450 	    (serialisedData.size() == 0))
451 	{
452 		return false;
453 	}
454 
455 	BotanEDPublicKey* pub = new BotanEDPublicKey();
456 
457 	if (!pub->deserialise(serialisedData))
458 	{
459 		delete pub;
460 
461 		return false;
462 	}
463 
464 	*ppPublicKey = pub;
465 
466 	return true;
467 }
468 
reconstructPrivateKey(PrivateKey ** ppPrivateKey,ByteString & serialisedData)469 bool BotanEDDSA::reconstructPrivateKey(PrivateKey** ppPrivateKey, ByteString& serialisedData)
470 {
471 	// Check input
472 	if ((ppPrivateKey == NULL) ||
473 	    (serialisedData.size() == 0))
474 	{
475 		return false;
476 	}
477 
478 	BotanEDPrivateKey* priv = new BotanEDPrivateKey();
479 
480 	if (!priv->deserialise(serialisedData))
481 	{
482 		delete priv;
483 
484 		return false;
485 	}
486 
487 	*ppPrivateKey = priv;
488 
489 	return true;
490 }
491 
newPublicKey()492 PublicKey* BotanEDDSA::newPublicKey()
493 {
494 	return (PublicKey*) new BotanEDPublicKey();
495 }
496 
newPrivateKey()497 PrivateKey* BotanEDDSA::newPrivateKey()
498 {
499 	return (PrivateKey*) new BotanEDPrivateKey();
500 }
501 
newParameters()502 AsymmetricParameters* BotanEDDSA::newParameters()
503 {
504 	return (AsymmetricParameters*) new ECParameters();
505 }
506 
reconstructParameters(AsymmetricParameters ** ppParams,ByteString & serialisedData)507 bool BotanEDDSA::reconstructParameters(AsymmetricParameters** ppParams, ByteString& serialisedData)
508 {
509 	// Check input parameters
510 	if ((ppParams == NULL) || (serialisedData.size() == 0))
511 	{
512 		return false;
513 	}
514 
515 	ECParameters* params = new ECParameters();
516 
517 	if (!params->deserialise(serialisedData))
518 	{
519 		delete params;
520 
521 		return false;
522 	}
523 
524 	*ppParams = params;
525 
526 	return true;
527 }
528 #endif
529