lime_crypto_primitives.cpp 24 KB
Newer Older
Johan Pascal's avatar
Johan Pascal committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
	lime_crypto_primitives.cpp
	@author Johan Pascal
	@copyright 	Copyright (C) 2017  Belledonne Communications SARL

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "lime_crypto_primitives.hpp"
#include "bctoolbox/crypto.h"
#include "bctoolbox/exception.hh"

namespace lime {

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/* template instanciations for Curves 25519 and 448, done  */
#ifdef EC255_ENABLED
	template class X<C255, lime::Xtype::publicKey>;
	template class X<C255, lime::Xtype::privateKey>;
	template class X<C255, lime::Xtype::sharedSecret>;
	template class Xpair<C255>;
	template class DSA<C255, lime::DSAtype::publicKey>;
	template class DSA<C255, lime::DSAtype::privateKey>;
	template class DSA<C255, lime::DSAtype::signature>;
	template class DSApair<C255>;
#endif

#ifdef EC448_ENABLED
	template class X<C448, lime::Xtype::publicKey>;
	template class X<C448, lime::Xtype::privateKey>;
	template class X<C448, lime::Xtype::sharedSecret>;
	template class Xpair<C448>;
	template class DSA<C448, lime::DSAtype::publicKey>;
	template class DSA<C448, lime::DSAtype::privateKey>;
	template class DSA<C448, lime::DSAtype::signature>;
	template class DSApair<C448>;
#endif

Johan Pascal's avatar
Johan Pascal committed
49
/***** Random Number Generator ********/
50 51 52
/**
 * A wrapper around the bctoolbox Random Number Generator
 */
Johan Pascal's avatar
Johan Pascal committed
53 54 55 56
class bctbx_RNG : public RNG {
	private :
		bctbx_rng_context_t *m_context; // the bctoolbox RNG context

johan's avatar
johan committed
57 58 59 60
		/* only bctbx_EDDSA and bctbx_ECDH needs a direct access to the actual RNG context */
		template <typename Curve> friend class bctbx_EDDSA;
		template <typename Curve> friend class bctbx_ECDH;

johan's avatar
johan committed
61 62 63 64 65 66
		/**
		 * @brief access internal RNG context
		 * Used internally by the bctoolbox wrapper, is not exposed to the lime_crypto_primitive API.
		 *
		 * @return a pointer to the RNG context
		 */
Johan Pascal's avatar
Johan Pascal committed
67 68 69 70
		bctbx_rng_context_t *get_context(void) {
			return m_context;
		}

johan's avatar
johan committed
71 72 73
	public:

		/* accessor */
johan's avatar
johan committed
74
		/**
johan's avatar
johan committed
75
		 * @brief fill the given RandomSeed buffer with Random bytes
johan's avatar
johan committed
76
		 *
johan's avatar
johan committed
77
		 * @param[in,out] buffer	point to the beginning of the buffer to be filled with random bytes
johan's avatar
johan committed
78
		 */
johan's avatar
johan committed
79 80
		void randomize(sBuffer<lime::settings::DRrandomSeedSize> &buffer) override {
			bctbx_rng_get(m_context, buffer.data(), buffer.size());
Johan Pascal's avatar
Johan Pascal committed
81
		};
johan's avatar
johan committed
82 83

		/**
johan's avatar
johan committed
84 85 86
		 * @brief Generate a 32 bits unsigned integer(used to generate keys Id)
		 * The MSbit is forced to 0 to avoid dealing with DB misinterpreting unsigned values into signed one
		 * Our random number is actually on 31 bits.
johan's avatar
johan committed
87
		 *
johan's avatar
johan committed
88
		 * @return a random 32 bits unsigned integer
johan's avatar
johan committed
89
		 */
johan's avatar
johan committed
90 91 92 93 94
		uint32_t randomize() override {
			std::array<uint8_t, 4> buffer;
			bctbx_rng_get(m_context, buffer.data(), buffer.size());
			// buffer[0] is shifted by 23 instead of 24 to keep the MSb to 0.
			return (static_cast<uint32_t>(buffer[0])<<23 | static_cast<uint32_t>(buffer[1])<<16 | static_cast<uint32_t>(buffer[2])<<8 | static_cast<uint32_t>(buffer[3]));
Johan Pascal's avatar
Johan Pascal committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
		};

		bctbx_RNG() {
			m_context = bctbx_rng_context_new();
		}
	
		~bctbx_RNG() {
			bctbx_rng_context_free(m_context);
			m_context = nullptr;
		}
}; // class bctbx_RNG

/* Factory function */
std::shared_ptr<RNG> make_RNG() {
	return std::make_shared<bctbx_RNG>();
}
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/***** Signature  ********************/
/* bctbx_EdDSA specialized constructor */
template <typename Curve>
bctbx_EDDSAContext_t *bctbx_EDDSAInit(void) {
	/* if this template is instanciated the static_assert will fail but will give us an error message with faulty Curve type */
	static_assert(sizeof(Curve) != sizeof(Curve), "You must specialize Signature class constructor for your type");
	return nullptr;
}

#ifdef EC25519_ENABLED
	/* specialise ECDH context creation */
	template <> bctbx_EDDSAContext_t *bctbx_EDDSAInit<C255>(void) {
		return bctbx_CreateEDDSAContext(BCTBX_EDDSA_25519);
	}
#endif // EC25519_ENABLED

#ifdef EC448_ENABLED
	/* specialise ECDH context creation */
	template <> bctbx_EDDSAContext_t *bctbx_EDDSAInit<C448>(void) {
		return bctbx_CreateEDDSAContext(BCTBX_EDDSA_448);
	}
#endif // EC448_ENABLED
133 134 135 136 137

/**
 * a wrapper around bctoolbox Signature algorithm.
 * Provides EdDSA on curves 25519 and 448
 */
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
template <typename Curve>
class bctbx_EDDSA : public Signature<Curve> {
	private :
		bctbx_EDDSAContext_t *m_context; // the EDDSA context
	public :
		/* accessors */
		const DSA<Curve, lime::DSAtype::privateKey> get_secret(void) override { /**< Secret key */
			if (m_context->secretKey == nullptr) {
				throw BCTBX_EXCEPTION << "invalid EdDSA secret key";
			}
			if (DSA<Curve, lime::DSAtype::privateKey>::ssize() != m_context->secretLength) {
				throw BCTBX_EXCEPTION << "Invalid buffer to store EdDSA secret key";
			}
			DSA<Curve, lime::DSAtype::privateKey> s;
			std::copy_n(m_context->secretKey, s.ssize(), s.data());
			return s;
		}
		const DSA<Curve, lime::DSAtype::publicKey> get_public(void) override {/**< Self Public key */
			if (m_context->publicKey == nullptr) {
				throw BCTBX_EXCEPTION << "invalid EdDSA public key";
			}
			if (DSA<Curve, lime::DSAtype::publicKey>::ssize() != m_context->pointCoordinateLength) {
				throw BCTBX_EXCEPTION << "Invalid buffer to store EdDSA public key";
			}
			DSA<Curve, lime::DSAtype::publicKey> p;
			std::copy_n(m_context->publicKey, p.ssize(), p.data());
			return p;
		}

		/* Setting keys */
		void set_secret(const DSA<Curve, lime::DSAtype::privateKey> &secretKey) override { /**< Secret key */
			bctbx_EDDSA_setSecretKey(m_context, secretKey.data(), secretKey.ssize());
		}

		void set_public(const DSA<Curve, lime::DSAtype::publicKey> &publicKey) override { /**< Self Public key */
			bctbx_EDDSA_setPublicKey(m_context, publicKey.data(), publicKey.ssize());
		}

		/**
177
		 * @brief generate a new random EdDSA key pair
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
		 *
		 * @param[in]	rng	The Random Number Generator to be used to generate the private kay
		 */
		void createKeyPair(std::shared_ptr<lime::RNG> rng) override {
			// the dynamic cast will generate an exception if RNG is not actually a bctbx_RNG
			bctbx_EDDSACreateKeyPair(m_context, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, dynamic_cast<lime::bctbx_RNG&>(*rng).get_context());
		}

		/**
		 * @brief Compute the public key using the secret already set in context
		 */
		void derivePublic(void) override {
			bctbx_EDDSADerivePublicKey(m_context);
		}

		/**
		 * @brief Sign a message using the key pair previously set in the object
		 *
		 * @param[in]	message		The message to be signed
		 * @param[out]	signature	The signature produced from the message with a key pair previously introduced in the object
		 */
		void sign(const std::vector<uint8_t> &message, DSA<Curve, lime::DSAtype::signature> &signature) override {
			auto sigSize = signature.size();
			bctbx_EDDSA_sign(m_context, message.data(), message.size(), nullptr, 0, signature.data(), &sigSize);
		}
johan's avatar
johan committed
203 204 205 206
		/**
		 * @overload void bctbx_EDDSA::sign(const X<Curve, lime::Xtype::publicKey> &message, DSA<Curve, lime::DSAtype::signature> &signature)
		 * a convenience function to directly verify a key exchange public key
		 */
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
		void sign(const X<Curve, lime::Xtype::publicKey> &message, DSA<Curve, lime::DSAtype::signature> &signature) override {
			auto sigSize = signature.size();
			bctbx_EDDSA_sign(m_context, message.data(), message.ssize(), nullptr, 0, signature.data(), &sigSize);
		}

		/**
		 * @brief Verify a message signature using the public key previously set in the object
		 *
		 * @param[in]	message		The message signed
		 * @param[in]	signature	The signature produced from the message with a key pair previously introduced in the object
		 *
		 * @return	true if the signature is valid, false otherwise
		 */
		bool verify(const std::vector<uint8_t> &message, const DSA<Curve, lime::DSAtype::signature> &signature) override {
			return (bctbx_EDDSA_verify(m_context, message.data(), message.size(), nullptr, 0, signature.data(), signature.size()) == BCTBX_VERIFY_SUCCESS);
		}
johan's avatar
johan committed
223 224 225 226
		/**
		 * @overload bool bctbx_EDDSA::verify(const X<Curve, lime::Xtype::publicKey> &message, const DSA<Curve, lime::DSAtype::signature> &signature)
		 * a convenience function to directly verify a key exchange public key
		 */
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
		bool verify(const X<Curve, lime::Xtype::publicKey> &message, const DSA<Curve, lime::DSAtype::signature> &signature) override {
			return (bctbx_EDDSA_verify(m_context, message.data(), message.ssize(), nullptr, 0, signature.data(), signature.ssize()) == BCTBX_VERIFY_SUCCESS);
		}

		/**
		 * ctor/dtor
		 */
		bctbx_EDDSA() {
			m_context = bctbx_EDDSAInit<Curve>();
		}
		~bctbx_EDDSA(){
			/* perform proper destroy cleaning buffers*/
			bctbx_DestroyEDDSAContext(m_context);
			m_context = nullptr;
		}
}; // class bctbx_EDDSA
Johan Pascal's avatar
Johan Pascal committed
243 244 245 246 247 248 249

/***** Key Exchange ******************/

/* bctbx_ECDH specialized constructor */
template <typename Curve>
bctbx_ECDHContext_t *bctbx_ECDHInit(void) {
	/* if this template is instanciated the static_assert will fail but will give us an error message with faulty Curve type */
250
	static_assert(sizeof(Curve) != sizeof(Curve), "You must specialize keyExchange class contructor for your type");
Johan Pascal's avatar
Johan Pascal committed
251 252 253 254 255 256 257 258
	return nullptr;
}

#ifdef EC25519_ENABLED
	/* specialise ECDH context creation */
	template <> bctbx_ECDHContext_t *bctbx_ECDHInit<C255>(void) {
		return bctbx_CreateECDHContext(BCTBX_ECDH_X25519);
	}
259
#endif //EC25519_ENABLED
Johan Pascal's avatar
Johan Pascal committed
260 261 262 263 264 265

#ifdef EC448_ENABLED
	/* specialise ECDH context creation */
	template <> bctbx_ECDHContext_t *bctbx_ECDHInit<C448>(void) {
		return bctbx_CreateECDHContext(BCTBX_ECDH_X448);
	}
266
#endif //EC448_ENABLED
Johan Pascal's avatar
Johan Pascal committed
267

268 269 270 271
/**
 * a wrapper around bctoolbox key exchange algorithm.
 * Provides X25519 and X448
 */
Johan Pascal's avatar
Johan Pascal committed
272 273 274
template <typename Curve>
class bctbx_ECDH : public keyExchange<Curve> {
	private :
275
		bctbx_ECDHContext_t *m_context; // the ECDH context
Johan Pascal's avatar
Johan Pascal committed
276 277
	public :
		/* accessors */
278
		const X<Curve, lime::Xtype::privateKey> get_secret(void) override { /**< Secret key */
Johan Pascal's avatar
Johan Pascal committed
279 280 281
			if (m_context->secret == nullptr) {
				throw BCTBX_EXCEPTION << "invalid ECDH secret key";
			}
282
			if (X<Curve, lime::Xtype::privateKey>::ssize() != m_context->secretLength) {
Johan Pascal's avatar
Johan Pascal committed
283 284
				throw BCTBX_EXCEPTION << "Invalid buffer to store ECDH secret key";
			}
285 286
			X<Curve, lime::Xtype::privateKey> s;
			std::copy_n(m_context->secret, s.ssize(), s.data());
Johan Pascal's avatar
Johan Pascal committed
287 288
			return s;
		}
289
		const X<Curve, lime::Xtype::publicKey> get_selfPublic(void) override {/**< Self Public key */
Johan Pascal's avatar
Johan Pascal committed
290 291 292
			if (m_context->selfPublic == nullptr) {
				throw BCTBX_EXCEPTION << "invalid ECDH self public key";
			}
293
			if (X<Curve, lime::Xtype::publicKey>::ssize() != m_context->pointCoordinateLength) {
Johan Pascal's avatar
Johan Pascal committed
294 295
				throw BCTBX_EXCEPTION << "Invalid buffer to store ECDH self public key";
			}
296 297
			X<Curve, lime::Xtype::publicKey> p;
			std::copy_n(m_context->selfPublic, p.ssize(), p.data());
Johan Pascal's avatar
Johan Pascal committed
298 299
			return p;
		}
300
		const X<Curve, lime::Xtype::publicKey> get_peerPublic(void) override { /**< Peer Public key */
Johan Pascal's avatar
Johan Pascal committed
301 302 303
			if (m_context->peerPublic == nullptr) {
				throw BCTBX_EXCEPTION << "invalid ECDH peer public key";
			}
304
			if (X<Curve, lime::Xtype::publicKey>::ssize() != m_context->pointCoordinateLength) {
Johan Pascal's avatar
Johan Pascal committed
305 306
				throw BCTBX_EXCEPTION << "Invalid buffer to store ECDH peer public key";
			}
307 308
			X<Curve, lime::Xtype::publicKey> p;
			std::copy_n(m_context->peerPublic, p.ssize(), p.data());
Johan Pascal's avatar
Johan Pascal committed
309 310
			return p;
		}
311
		const X<Curve, lime::Xtype::sharedSecret> get_sharedSecret(void) override { /**< ECDH output */
Johan Pascal's avatar
Johan Pascal committed
312 313 314
			if (m_context->sharedSecret == nullptr) {
				throw BCTBX_EXCEPTION << "invalid ECDH shared secret";
			}
315
			if (X<Curve, lime::Xtype::sharedSecret>::ssize() != m_context->pointCoordinateLength) {
Johan Pascal's avatar
Johan Pascal committed
316 317
				throw BCTBX_EXCEPTION << "Invalid buffer to store ECDH output";
			}
318 319
			X<Curve, lime::Xtype::sharedSecret> s;
			std::copy_n(m_context->sharedSecret, s.ssize(), s.data());
Johan Pascal's avatar
Johan Pascal committed
320 321 322
			return s;
		}

323 324 325 326

		/* Setting keys, accept Signature keys */
		void set_secret(const X<Curve, lime::Xtype::privateKey> &secret) override { /**< Secret key */
			bctbx_ECDHSetSecretKey(m_context, secret.data(), secret.ssize());
Johan Pascal's avatar
Johan Pascal committed
327 328
		}

329 330 331 332 333 334 335 336 337 338
		void set_secret(const DSA<Curve, lime::DSAtype::privateKey> &secret) override { /**< Secret key */
			// we must create a temporary bctbx_EDDSA context and set the given key in
			auto tmp_context = bctbx_EDDSAInit<Curve>();
			bctbx_EDDSA_setSecretKey(tmp_context, secret.data(), secret.ssize());

			// Convert
			bctbx_EDDSA_ECDH_privateKeyConversion(tmp_context, m_context);

			// Cleaning
			bctbx_DestroyEDDSAContext(tmp_context);
Johan Pascal's avatar
Johan Pascal committed
339
		}
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370

		void set_selfPublic(const X<Curve, lime::Xtype::publicKey> &selfPublic) override { /**< Self Public key */
			bctbx_ECDHSetSelfPublicKey(m_context, selfPublic.data(), selfPublic.ssize());
		}

		void set_selfPublic(const DSA<Curve, lime::DSAtype::publicKey> &selfPublic) override { /**< Self Public key */
			// we must create a temporary bctbx_EDDSA context and set the given key in
			auto tmp_context = bctbx_EDDSAInit<Curve>();
			bctbx_EDDSA_setPublicKey(tmp_context, selfPublic.data(), selfPublic.ssize());

			// Convert in self Public
			bctbx_EDDSA_ECDH_publicKeyConversion(tmp_context, m_context, BCTBX_ECDH_ISSELF);

			// Cleaning
			bctbx_DestroyEDDSAContext(tmp_context);
		}

		void set_peerPublic(const X<Curve, lime::Xtype::publicKey> &peerPublic) override {; /**< Peer Public key */
			bctbx_ECDHSetPeerPublicKey(m_context, peerPublic.data(), peerPublic.ssize());
		}

		void set_peerPublic(const DSA<Curve, lime::DSAtype::publicKey> &peerPublic) override {; /**< Peer Public key */
			// we must create a temporary bctbx_EDDSA context and set the given key in
			auto tmp_context = bctbx_EDDSAInit<Curve>();
			bctbx_EDDSA_setPublicKey(tmp_context, peerPublic.data(), peerPublic.ssize());

			// Convert in peer Public
			bctbx_EDDSA_ECDH_publicKeyConversion(tmp_context, m_context, BCTBX_ECDH_ISPEER);

			// Cleaning
			bctbx_DestroyEDDSAContext(tmp_context);
Johan Pascal's avatar
Johan Pascal committed
371 372 373 374
		}


		/**
375
		 * @brief generate a new random ECDH key pair
Johan Pascal's avatar
Johan Pascal committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
		 *
		 * @param[in]	rng	The Random Number Generator to be used to generate the private kay
		 */
		void createKeyPair(std::shared_ptr<lime::RNG> rng) override {
			// the dynamic cast will generate an exception if RNG is not actually a bctbx_RNG
			bctbx_ECDHCreateKeyPair(m_context, (int (*)(void *, uint8_t *, size_t))bctbx_rng_get, dynamic_cast<lime::bctbx_RNG&>(*rng).get_context());
		}

		/**
		 * @brief Compute the self public key using the secret already set in context
		 */
		void deriveSelfPublic(void) override {
			bctbx_ECDHDerivePublicKey(m_context);
		}

		/**
		 * @brief Perform the ECDH computation, shared secret is then available in the object via get_sharedSecret
		 */
		void computeSharedSecret(void) override {
			 bctbx_ECDHComputeSecret(m_context, nullptr, nullptr);
		}

		/**
		 * ctor/dtor
		 */
		bctbx_ECDH() {
			m_context = bctbx_ECDHInit<Curve>();
		}
		~bctbx_ECDH(){
			/* perform proper destroy cleaning buffers*/
			bctbx_DestroyECDHContext(m_context);
			m_context = nullptr;
		}
}; // class bctbx_ECDH

411

412
/* Factory functions */
johan's avatar
johan committed
413 414 415
template <typename Curve>
std::shared_ptr<keyExchange<Curve>> make_keyExchange() {
	return std::make_shared<bctbx_ECDH<Curve>>();
Johan Pascal's avatar
Johan Pascal committed
416 417
}

johan's avatar
johan committed
418 419 420
template <typename Curve>
std::shared_ptr<Signature<Curve>> make_Signature() {
	return std::make_shared<bctbx_EDDSA<Curve>>();
421 422
}

423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
/* HMAC templates */
/* HMAC must use a specialized template */
template <typename hashAlgo>
void HMAC(const uint8_t *const key, const size_t keySize, const uint8_t *const input, const size_t inputSize, uint8_t *hash, size_t hashSize) {
	/* if this template is instanciated the static_assert will fail but will give us an error message with faulty Curve type */
	static_assert(sizeof(hashAlgo) != sizeof(hashAlgo), "You must specialize HMAC_KDF function template");
}
template <typename hashAlgo>
void HMAC(const std::vector<uint8_t> &key, const std::vector<uint8_t> &input, std::array<uint8_t, hashAlgo::ssize()> &hash) {
	/* if this template is instanciated the static_assert will fail but will give us an error message with faulty Curve type */
	static_assert(sizeof(hashAlgo) != sizeof(hashAlgo), "You must specialize HMAC_KDF function template");
}

/* HMAC specialized template for SHA512 */
template <> void HMAC<SHA512>(const uint8_t *const key, const size_t keySize, const uint8_t *const input, const size_t inputSize, uint8_t *hash, size_t hashSize) {
	bctbx_hmacSha512(key, keySize, input, inputSize, std::min(SHA512::ssize(),hashSize), hash);
}
template <> void HMAC<SHA512>(const std::vector<uint8_t> &key, const std::vector<uint8_t> &input, std::array<uint8_t, SHA512::ssize()> &hash) {
	bctbx_hmacSha512(key.data(), key.size(), input.data(), input.size(), SHA512::ssize(), hash.data());
}

/* generic implementation, of HKDF RFC-5869 */
template <typename hashAlgo, typename infoType>
void HMAC_KDF(const uint8_t *const salt, const size_t saltSize, const uint8_t *const ikm, const size_t ikmSize, const infoType &info, uint8_t *output, size_t outputSize) {
	std::array<uint8_t, hashAlgo::ssize()> prk; // hold the output of pre-computation, as we use SHA512 gets a 64 bytes
	// extraction
	HMAC<hashAlgo>(salt, saltSize, ikm, ikmSize, prk.data(), prk.size());

	// expansion round 0
	std::vector<uint8_t> T(info.cbegin(), info.cend());
	T.push_back(0x01);
	HMAC<hashAlgo>(prk.data(), prk.size(), T.data(), T.size(), output, outputSize);

	// successives expansion rounds
	size_t index = std::min(outputSize, hashAlgo::ssize());
	for(uint8_t i=0x02; index < outputSize; i++) {
		T.assign(output+(i-2)*hashAlgo::ssize(), output+(i-1)*hashAlgo::ssize());
		T.insert(T.end(), info.cbegin(), info.cend());
		T.push_back(i);
		HMAC<hashAlgo>(prk.data(), prk.size(), T.data(), T.size(), output+index, outputSize-index);
		index += hashAlgo::ssize();
	}
	cleanBuffer(prk.data(), prk.size());
	cleanBuffer(T.data(), T.size());
}
template <typename hashAlgo, typename infoType>
void HMAC_KDF(const std::vector<uint8_t> &salt, const std::vector<uint8_t> &ikm, const infoType &info, uint8_t *output, size_t outputSize) {
	HMAC_KDF<SHA512>(salt.data(), salt.size(), ikm.data(), ikm.size(), info, output, outputSize);
};

/* instanciate HMAC_KDF template with SHA512 and string or vector info */
template void HMAC<SHA512>(const uint8_t *const key, const size_t keySize, const uint8_t *const input, const size_t inputSize, uint8_t *hash, size_t hashSize);
template void HMAC_KDF<SHA512, std::vector<uint8_t>>(const uint8_t *const salt, const size_t saltSize, const uint8_t *const ikm, const size_t ikmSize, const std::vector<uint8_t> &info, uint8_t *output, size_t outputSize);
template void HMAC_KDF<SHA512, std::string>(const uint8_t *const salt, const size_t saltSize, const uint8_t *const ikm, const size_t ikmSize, const std::string &info, uint8_t *output, size_t outputSize);
template void HMAC_KDF<SHA512, std::vector<uint8_t>>(const std::vector<uint8_t> &salt, const std::vector<uint8_t> &ikm, const std::vector<uint8_t> &info, uint8_t *output, size_t outputSize);
template void HMAC_KDF<SHA512, std::string>(const std::vector<uint8_t> &salt, const std::vector<uint8_t> &ikm, const std::string &info, uint8_t *output, size_t outputSize);

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
/* AEAD template must be specialized */
template <typename AEADAlgo>
void AEAD_encrypt(const uint8_t *const key, const size_t keySize, const uint8_t *const IV, const size_t IVSize,
		const uint8_t *const plain, const size_t plainSize, const uint8_t *const AD, const size_t ADSize,
		uint8_t *tag, const size_t tagSize, uint8_t *cipher) {
	/* if this template is instanciated the static_assert will fail but will give us an error message with faulty type */
	static_assert(sizeof(AEADAlgo) != sizeof(AEADAlgo), "You must specialize AEAD_encrypt function template");
}

template <typename AEADAlgo>
bool AEAD_decrypt(const uint8_t *const key, const size_t keySize, const uint8_t *const IV, const size_t IVSize,
		const uint8_t *const cipher, const size_t cipherSize, const uint8_t *const AD, const size_t ADSize,
		const uint8_t *const tag, const size_t tagSize, uint8_t *plain) {
	/* if this template is instanciated the static_assert will fail but will give us an error message with faulty type */
	static_assert(sizeof(AEADAlgo) != sizeof(AEADAlgo), "You must specialize AEAD_decrypt function template");
	return false;
}

/* AEAD scheme specialiazed template with AES256-GCM, 16 bytes auth tag */
template <> void AEAD_encrypt<AES256GCM>(const uint8_t *const key, const size_t keySize, const uint8_t *const IV, const size_t IVSize,
		const uint8_t *const plain, const size_t plainSize, const uint8_t *const AD, const size_t ADSize,
		uint8_t *tag, const size_t tagSize, uint8_t *cipher) {
	/* perforn checks on sizes */
	if (keySize != AES256GCM::keySize() || tagSize != AES256GCM::tagSize()) {
		throw BCTBX_EXCEPTION << "invalid arguments for AEAD_encrypt AES256-GCM";
	}
	auto ret = bctbx_aes_gcm_encrypt_and_tag(key, keySize, plain, plainSize, AD, ADSize, IV, IVSize, tag, tagSize, cipher);
	if (ret != 0) {
		throw BCTBX_EXCEPTION << "AEAD_encrypt AES256-GCM error: "<<ret;
	}
}

template <> bool AEAD_decrypt<AES256GCM>(const uint8_t *const key, const size_t keySize, const uint8_t *const IV, const size_t IVSize,
		const uint8_t *const cipher, const size_t cipherSize, const uint8_t *const AD, const size_t ADSize,
		const uint8_t *const tag, const size_t tagSize, uint8_t *plain) {
	/* perforn checks on sizes */
	if (keySize != AES256GCM::keySize() || tagSize != AES256GCM::tagSize()) {
		throw BCTBX_EXCEPTION << "invalid arguments for AEAD_decrypt AES256-GCM";
	}
	auto ret = bctbx_aes_gcm_decrypt_and_auth(key, keySize, cipher, cipherSize, AD, ADSize, IV, IVSize, tag, tagSize, plain);
	if (ret == 0) return true;
	if (ret == BCTBX_ERROR_AUTHENTICATION_FAILED) return false;
	throw BCTBX_EXCEPTION << "AEAD_decrypt AES256-GCM error: "<<ret;
}

525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
/* check buffer length are in sync with bctoolbox ones */
#ifdef EC25519_ENABLED
	static_assert(BCTBX_ECDH_X25519_PUBLIC_SIZE == X<C255, Xtype::publicKey>::ssize(), "bctoolbox and local defines mismatch");
	// for ECDH public value and shared secret have the same size
	static_assert(BCTBX_ECDH_X25519_PUBLIC_SIZE == X<C255, Xtype::sharedSecret>::ssize(), "bctoolbox and local defines mismatch");
	static_assert(BCTBX_ECDH_X25519_PRIVATE_SIZE == X<C255, Xtype::privateKey>::ssize(), "bctoolbox and local defines mismatch");

	static_assert(BCTBX_EDDSA_25519_PUBLIC_SIZE == DSA<C255, DSAtype::publicKey>::ssize(), "bctoolbox and local defines mismatch");
	static_assert(BCTBX_EDDSA_25519_PRIVATE_SIZE == DSA<C255, DSAtype::privateKey>::ssize(), "bctoolbox and local defines mismatch");
	static_assert(BCTBX_EDDSA_25519_SIGNATURE_SIZE == DSA<C255, DSAtype::signature>::ssize(), "bctoolbox and local defines mismatch");
#endif //EC25519_ENABLED

#ifdef EC448_ENABLED
	static_assert(BCTBX_ECDH_X448_PUBLIC_SIZE == X<C448, Xtype::publicKey>::ssize(), "bctoolbox and local defines mismatch");
	// for ECDH public value and shared secret have the same size
	static_assert(BCTBX_ECDH_X448_PUBLIC_SIZE == X<C448, Xtype::sharedSecret>::ssize(), "bctoolbox and local defines mismatch");
	static_assert(BCTBX_ECDH_X448_PRIVATE_SIZE == X<C448, Xtype::privateKey>::ssize(), "bctoolbox and local defines mismatch");

	static_assert(BCTBX_EDDSA_448_PUBLIC_SIZE == DSA<C448, DSAtype::publicKey>::ssize(), "bctoolbox and local defines mismatch");
	static_assert(BCTBX_EDDSA_448_PRIVATE_SIZE == DSA<C448, DSAtype::privateKey>::ssize(), "bctoolbox and local defines mismatch");
	static_assert(BCTBX_EDDSA_448_SIGNATURE_SIZE == DSA<C448, DSAtype::signature>::ssize(), "bctoolbox and local defines mismatch");
#endif //EC448_ENABLED
Johan Pascal's avatar
Johan Pascal committed
547

548 549 550 551 552
void cleanBuffer(uint8_t *buffer, size_t size) {
	bctbx_clean(buffer, size);
}

/* template instanciations for Curve 25519 and Curve 448 */
Johan Pascal's avatar
Johan Pascal committed
553 554
#ifdef EC25519_ENABLED
	template class bctbx_ECDH<C255>;
555
	template class bctbx_EDDSA<C255>;
Johan Pascal's avatar
Johan Pascal committed
556
	template std::shared_ptr<keyExchange<C255>> make_keyExchange();
557 558
	template std::shared_ptr<Signature<C255>> make_Signature();
#endif //EC25519_ENABLED
Johan Pascal's avatar
Johan Pascal committed
559 560 561

#ifdef EC448_ENABLED
	template class bctbx_ECDH<C448>;
562
	template class bctbx_EDDSA<C448>;
Johan Pascal's avatar
Johan Pascal committed
563
	template std::shared_ptr<keyExchange<C448>> make_keyExchange();
564 565
	template std::shared_ptr<Signature<C448>> make_Signature();
#endif //EC448_ENABLED
Johan Pascal's avatar
Johan Pascal committed
566 567 568 569 570


} // namespace lime