lime_keys.hpp 7.85 KB
Newer Older
johan's avatar
johan 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
/*
	lime_keys.hpp
	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/>.
*/

#ifndef lime_keys_hpp
#define lime_keys_hpp

#include <algorithm> //std::copy_n
#include <array>
#include <iterator>
#include "bctoolbox/crypto.h"
#include "lime/lime.hpp"

namespace lime {
	// all keys types have an ID byte prepended to it before sending it in any message
	// as recommended in X3DH spec section 2.1
	enum class keyByteId : uint8_t {x25519=0x01, x448=0x02, ed25519=0x81, ed448=0x82};
	// also define in an enum their key size
	enum class keySize : size_t {x25519=BCTBX_ECDH_X25519_PUBLIC_SIZE, x448=BCTBX_ECDH_X448_PUBLIC_SIZE, ed25519=BCTBX_EDDSA_25519_PUBLIC_SIZE, ed448=BCTBX_EDDSA_448_PUBLIC_SIZE};
	enum class sigSize : size_t {ed25519=BCTBX_EDDSA_25519_SIGNATURE_SIZE, ed448=BCTBX_EDDSA_448_SIGNATURE_SIZE};

	/* define needed constant for the curves: self identificatio(used in DB and as parameter from lib users, keys sizes)*/
	/* These structure are used as template argument to enable support for different EC. Some templates specialisation MUST be define in lime_keys.cpp to be able to use them */
	struct C255 { // curve 25519, use a 4 chars to identify it to improve code readability
		static constexpr lime::CurveId curveId() {return lime::CurveId::c25519;};
		static constexpr size_t XkeySize() {return static_cast<size_t>(keySize::x25519);};
		static constexpr uint8_t XkeyByteId() {return static_cast<uint8_t>(keyByteId::x25519);};
		static constexpr size_t EDkeySize() {return static_cast<size_t>(keySize::ed25519);};
		static constexpr size_t EDSigSize() {return static_cast<size_t>(sigSize::ed25519);};
		static constexpr uint8_t EDkeyByteId() {return static_cast<uint8_t>(keyByteId::ed25519);};
	};

	struct C448 { // curve 448-goldilocks
		static constexpr lime::CurveId curveId() {return lime::CurveId::c448;};
		static constexpr size_t XkeySize() {return static_cast<size_t>(keySize::x448);};
		static constexpr uint8_t XkeyByteId() {return static_cast<uint8_t>(keyByteId::x448);};
		static constexpr size_t EDkeySize() {return static_cast<size_t>(keySize::ed448);};
		static constexpr size_t EDSigSize() {return static_cast<size_t>(sigSize::ed448);};
		static constexpr uint8_t EDkeyByteId() {return static_cast<uint8_t>(keyByteId::ed448);};
	};


	/****************************************************************/
	/* ECDH keys                                                    */
	/****************************************************************/
	/* function to create a ECDH context */
	template <typename Curve>
	bctbx_ECDHContext_t *ECDHInit(void);

	template <typename Curve>
	class X : public std::array<uint8_t, static_cast<size_t>(Curve::XkeySize())>{
		public :
			constexpr static size_t keyLength(void) {return Curve::XkeySize();}; // provide a static size function to be able to call the function not on an object
			constexpr static uint8_t byteId(void) {return Curve::XkeyByteId();};
69 70 71
			// construct from a C style buffer
			// WARNING: very dangerous code could lead to read anywhere(X{0} will call this constructor), get rid of it if we manage to use c++ buffer style only - get a bctoolbox/crypto.hpp?
			X(const uint8_t *buffer) {std::copy_n(buffer, Curve::XkeySize(), this->data());}
johan's avatar
johan committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
			X(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::XkeySize(), this->begin());} // construct from a std::vector<uint8_t>
			X() {};
			void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::XkeySize(), this->begin());} // copy from a std::vector<uint8_t>
	};

	/****************************************************************/
	/* EdDSA keys and signature                                     */
	/****************************************************************/
	/* function to create a ECDH context */
	template <typename Curve>
	bctbx_EDDSAContext_t *EDDSAInit(void);

	template <typename Curve>
	class ED : public std::array<uint8_t, static_cast<size_t>(Curve::EDkeySize())>{
		public :
			constexpr static size_t keyLength(void) {return Curve::EDkeySize();}; // provide a static size function to be able to call the function not on an object
			constexpr static uint8_t byteId(void) {return Curve::EDkeyByteId();};
89 90 91
			// construct from a C style buffer
			// WARNING: very dangerous code could lead to read anywhere(ED{0} will call this constructor), get rid of it if we manage to use c++ buffer style only - get a bctoolbox/crypto.hpp?
			ED(const uint8_t *buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->data());}
johan's avatar
johan committed
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
			ED(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->begin());} // contruct from a std::vector<uint8_t>
			ED() {};
			void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::EDkeySize(), this->begin());} // copy from a std::vector<uint8_t>
	};

	template <typename Curve>
	class Signature : public std::array<uint8_t, static_cast<size_t>(Curve::EDSigSize())>{
		public :
			constexpr static size_t signatureLength(void) {return Curve::EDSigSize();}; // provide a static size function to be able to call the function not on an object
			Signature(const uint8_t *buffer) {std::copy_n(buffer, Curve::EDSigSize(), this->data());}
			Signature() {};
	};


	/****************************************************************/
	/* Common structure: key pair                                   */
	/****************************************************************/
	template <typename Key>
	class KeyPair {
		private:
			/* for all supported algo(X25519, X448, ED25519, ED448), private and public keys have the same size, so we use the same type to declare them in a pair */
			Key _pubKey;
			Key _privKey;
		public:
			size_t size(void) {return _pubKey.size();};  // by construction private and public are of the same type so have same size so we can return any size fron this two keys.
			Key &privateKey(void) {return _privKey;};
			Key &publicKey(void) {return _pubKey;};
			KeyPair(Key pub, Key priv):_pubKey(pub),_privKey(priv) {};
			KeyPair(uint8_t *pub, uint8_t *priv):_pubKey{pub},_privKey{priv} {};
			KeyPair() :_pubKey{},_privKey{}{};
			bool operator==(KeyPair<Key> b) const {return (_privKey==b.privateKey() && _pubKey==b.publicKey());};
	};

	/****************************************************************/
	/* Template are instanciated in lime_keys.cpp                   */
	/* Do not re-instiate them elsewhere                            */
	/****************************************************************/
#ifdef EC25519_ENABLED
	/* declare specialisation for C255 */
	template <> bctbx_ECDHContext_t *ECDHInit<C255>(void);
	template <> bctbx_EDDSAContext_t *EDDSAInit<C255>(void);
	/* ask any file including lime_keys.hpp to not instantiate the follownings as it is done in lime_keys.cpp*/
	extern template class X<C255>;
	extern template class ED<C255>;
	extern template class KeyPair<X<C255>>;
	extern template class KeyPair<ED<C255>>;
#endif

#ifdef EC448_ENABLED
	/* declare specialisation for C488 */
	template <> bctbx_ECDHContext_t *ECDHInit<C448>(void);
	template <> bctbx_EDDSAContext_t *EDDSAInit<C448>(void);
	/* ask any file including lime_keys.hpp to not instantiate the follownings as it is done in lime_keys.cpp*/
	extern template class X<C448>;
	extern template class ED<C448>;
	extern template class KeyPair<X<C448>>;
	extern template class KeyPair<ED<C448>>;
#endif

}

#endif /* lime_keys_hpp */