Commit 7793b80d authored by Johan Pascal's avatar Johan Pascal

RNG, ECDH and EdDSA accessed via CPP dedicated API

parent f05db5ed
......@@ -35,7 +35,6 @@ set(LIME_HEADER_FILES
set(LIME_SOURCE_FILES_C )
set(LIME_SOURCE_FILES_CXX
lime.cpp
lime_keys.cpp
lime_crypto_primitives.cpp
lime_x3dh.cpp
lime_x3dh_protocol.cpp
......
......@@ -59,7 +59,7 @@ namespace lime {
*/
template <typename Curve>
Lime<Curve>::Lime(std::unique_ptr<lime::Db> &&localStorage, const std::string &deviceId, const std::string &url, const limeX3DHServerPostData &X3DH_post_data, const long int Uid)
: m_RNG{bctbx_rng_context_new()}, m_selfDeviceId{deviceId},
: m_RNG{make_RNG()}, m_selfDeviceId{deviceId},
m_Ik{}, m_Ik_loaded(false),
m_localStorage(std::move(localStorage)), m_db_Uid{Uid},
m_X3DH_post_data{X3DH_post_data}, m_X3DH_Server_URL{url},
......@@ -78,24 +78,17 @@ namespace lime {
*/
template <typename Curve>
Lime<Curve>::Lime(std::unique_ptr<lime::Db> &&localStorage, const std::string &deviceId, const std::string &url, const limeX3DHServerPostData &X3DH_post_data)
: m_RNG{bctbx_rng_context_new()}, m_selfDeviceId{deviceId},
: m_RNG{make_RNG()}, m_selfDeviceId{deviceId},
m_Ik{}, m_Ik_loaded(false),
m_localStorage(std::move(localStorage)), m_db_Uid{0},
m_X3DH_post_data{X3DH_post_data}, m_X3DH_Server_URL{url},
m_DR_sessions_cache{}, m_ongoing_encryption{nullptr}, m_encryption_queue{}
{
try {
create_user();
} catch (...) { // if createUser throw an exception we must clean ressource allocated C style by constructor
bctbx_rng_context_free(m_RNG);
throw;
}
create_user();
}
template <typename Curve>
Lime<Curve>::~Lime() {
bctbx_rng_context_free(m_RNG);
}
Lime<Curve>::~Lime() {};
/****************************************************************************/
/* */
......@@ -137,8 +130,8 @@ namespace lime {
BCTBX_SLOGI<<"User "<<m_selfDeviceId<<" updates its SPk";
auto userData = make_shared<callbackUserData<Curve>>(this->shared_from_this(), callback);
// generate and publish the SPk
X<Curve> SPk{};
Signature<Curve> SPk_sig{};
X<Curve, lime::Xtype::publicKey> SPk{};
DSA<Curve, lime::DSAtype::signature> SPk_sig{};
uint32_t SPk_id=0;
X3DH_generate_SPk(SPk, SPk_sig, SPk_id);
std::vector<uint8_t> X3DHmessage{};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -22,13 +22,12 @@
#include <array>
#include <string>
#include <unordered_map>
#include "bctoolbox/crypto.h"
#include <vector>
#include <memory>
#include "lime_settings.hpp"
#include "lime_defines.hpp"
#include "lime_keys.hpp"
#include "lime_crypto_primitives.hpp"
namespace lime {
......@@ -39,17 +38,24 @@ namespace lime {
enum class DRSessionDbStatus : uint8_t {clean, dirty_encrypt, dirty_decrypt, dirty_ratchet, dirty};
// Double Rachet chain keys: Root key, Sender and receiver keys are 32 bytes arrays
using DRChainKey = std::array<uint8_t, lime::settings::DRChainKeySize>;
class DRChainKey : public std::array<uint8_t, lime::settings::DRChainKeySize> {
public:
~DRChainKey() {cleanBuffer(this->data(), lime::settings::DRChainKeySize);}
};
// Double Ratchet Message keys : 32 bytes of encryption key followed by 16 bytes of IV
using DRMKey = std::array<uint8_t, lime::settings::DRMessageKeySize+lime::settings::DRMessageIVSize>;
class DRMKey : public std::array<uint8_t, lime::settings::DRMessageKeySize+lime::settings::DRMessageIVSize> {
public:
~DRMKey() {cleanBuffer(this->data(), lime::settings::DRMessageKeySize+lime::settings::DRMessageIVSize);}
};
// Shared Associated Data : stored at session initialisation, given by upper level(X3DH), shall be derived from Identity and Identity keys of sender and recipient, fixed size for storage convenience
using SharedADBuffer = std::array<uint8_t, lime::settings::DRSessionSharedADSize>;
// Chain storing the DH and MKs associated with Nr(uint16_t map index)
template <typename Curve>
struct receiverKeyChain {
X<Curve> DHr;
X<Curve, lime::Xtype::publicKey> DHr;
std::unordered_map<std::uint16_t, DRMKey> messageKeys;
receiverKeyChain(X<Curve> key) :DHr{std::move(key)}, messageKeys{} {};
receiverKeyChain(X<Curve, lime::Xtype::publicKey> key) :DHr{std::move(key)}, messageKeys{} {};
};
/**
......@@ -62,9 +68,9 @@ namespace lime {
class DR {
private:
/* State variables for Double Ratchet, see Double Ratchet spec section 3.2 for details */
X<Curve> m_DHr; // Remote public key
X<Curve, lime::Xtype::publicKey> m_DHr; // Remote public key
bool m_DHr_valid; // do we have a valid remote public key, flag used to spot the first message arriving at session creation in receiver mode
KeyPair<X<Curve>> m_DHs; // self Key pair
Xpair<Curve> m_DHs; // self Key pair
DRChainKey m_RK; // 32 bytes root key
DRChainKey m_CKs; // 32 bytes key chain for sending
DRChainKey m_CKr; // 32 bytes key chain for receiving
......@@ -74,7 +80,7 @@ namespace lime {
std::vector<lime::receiverKeyChain<Curve>> m_mkskipped; // list of skipped message indexed by DH receiver public key and Nr, store MK generated during on-going decrypt, lookup is done directly in DB.
/* helpers variables */
bctbx_rng_context_t *m_RNG; // Random Number Generator context
std::shared_ptr<RNG> m_RNG; // Random Number Generator context
long int m_dbSessionId; // used to store row id from Database Storage
uint16_t m_usedNr; // store the index of message key used for decryption if it came from mkskipped db
long m_usedDHid; // store the index of DHr message key used for decryption if it came from mkskipped db(not zero only if used)
......@@ -87,17 +93,17 @@ namespace lime {
/*helpers functions */
void skipMessageKeys(const uint16_t until, const int limit); /* check if we skipped some messages in current receiving chain, generate and store in session intermediate message keys */
void DHRatchet(const X<Curve> &headerDH); /* perform a Diffie-Hellman ratchet using the given peer public key */
void DHRatchet(const X<Curve, lime::Xtype::publicKey> &headerDH); /* perform a Diffie-Hellman ratchet using the given peer public key */
/* local storage related implemented in lime_localStorage.cpp */
bool session_save(); /* save/update session in database : updated component depends m_dirty value */
bool session_load(); /* load session in database */
bool trySkippedMessageKeys(const uint16_t Nr, const X<Curve> &DHr, DRMKey &MK); /* check in DB if we have a message key matching public DH and Ns */
bool trySkippedMessageKeys(const uint16_t Nr, const X<Curve, lime::Xtype::publicKey> &DHr, DRMKey &MK); /* check in DB if we have a message key matching public DH and Ns */
public:
DR() = delete; // make sure the Double Ratchet is not initialised without parameters
DR(lime::Db *localStorage, const DRChainKey &SK, const SharedADBuffer &AD, const X<Curve> &peerPublicKey, long int peerDeviceId, long int selfDeviceId, const std::vector<uint8_t> &X3DH_initMessage, bctbx_rng_context_t *RNG_context); // call to initialise a session for sender: we have Shared Key and peer Public key
DR(lime::Db *localStorage, const DRChainKey &SK, const SharedADBuffer &AD, const KeyPair<X<Curve>> &selfKeyPair, long int peerDeviceId, long int selfDeviceId, bctbx_rng_context_t *RNG_context); // call at initialisation of a session for receiver: we have Share Key and self key pair
DR(lime::Db *localStorage, long sessionId, bctbx_rng_context_t *RNG_context); // load session from DB
DR(lime::Db *localStorage, const DRChainKey &SK, const SharedADBuffer &AD, const X<Curve, lime::Xtype::publicKey> &peerPublicKey, long int peerDeviceId, long int selfDeviceId, const std::vector<uint8_t> &X3DH_initMessage, std::shared_ptr<RNG> RNG_context); // call to initialise a session for sender: we have Shared Key and peer Public key
DR(lime::Db *localStorage, const DRChainKey &SK, const SharedADBuffer &AD, const Xpair<Curve> &selfKeyPair, long int peerDeviceId, long int selfDeviceId, std::shared_ptr<RNG> RNG_context); // call at initialisation of a session for receiver: we have Share Key and self key pair
DR(lime::Db *localStorage, long sessionId, std::shared_ptr<RNG> RNG_context); // load session from DB
DR(DR<Curve> &a) = delete; // can't copy a session, force usage of shared pointers
DR<Curve> &operator=(DR<Curve> &a) = delete; // can't copy a session
~DR();
......
......@@ -54,7 +54,7 @@ namespace lime {
* Packets types are : regular or x3dhinit
* - regular packet does not contain x3dh init message
* - x3dh init packet includes x3dh init message in the header as follow:
* haveOPk <flag 1 byte> || self Ik < ED<Curve>::keyLength() bytes > || Ek < X<Curve>::keyLenght() bytes> || peer SPk id < 4 bytes > || [peer OPk id(if flag is set)<4bytes>]
* haveOPk <flag 1 byte> || self Ik < DSA<Curve, lime::DSAtype::publicKey>::ssize() bytes > || Ek < X<Curve, lime::Xtype::publicKey>::keyLenght() bytes> || peer SPk id < 4 bytes > || [peer OPk id(if flag is set)<4bytes>]
*
*/
......@@ -65,12 +65,12 @@ namespace lime {
*/
template <typename Curve>
constexpr size_t headerSize() {
return 7 + X<Curve>::keyLength();
return 7 + X<Curve, lime::Xtype::publicKey>::ssize();
}
/**
* @brief build an X3DH init message to insert in DR header
* haveOPk <flag 1 byte> || self Ik < ED<Curve>::keyLength() bytes > || Ek < X<Curve>::keyLenght() bytes> || peer SPk id < 4 bytes > || [peer OPk id(if flag is set)<4bytes>]
* haveOPk <flag 1 byte> || self Ik < DSA<Curve, lime::DSAtype::publicKey>::ssize() bytes > || Ek < X<Curve, lime::Xtype::publicKey>::keyLenght() bytes> || peer SPk id < 4 bytes > || [peer OPk id(if flag is set)<4bytes>]
*
* @param[out] message the X3DH init message
* @param[in] Ik self public identity key
......@@ -81,7 +81,7 @@ namespace lime {
*
*/
template <typename Curve>
void buildMessage_X3DHinit(std::vector<uint8_t> &message, const ED<Curve> &Ik, const X<Curve> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept {
void buildMessage_X3DHinit(std::vector<uint8_t> &message, const DSA<Curve, lime::DSAtype::publicKey> &Ik, const X<Curve, lime::Xtype::publicKey> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept {
// make sure message is cleared and set its first byte to OPk flag
message.assign(1, static_cast<uint8_t>(OPk_flag?DR_X3DH_OPk_flag::withOPk:DR_X3DH_OPk_flag::withoutOPk));
message.reserve(1+Ik.size()+Ek.size()+4+(OPk_flag?4:0));
......@@ -115,15 +115,15 @@ namespace lime {
* @param[out] OPk_flag true if an OPk flag was present in the message
*/
template <typename Curve>
void parseMessage_X3DHinit(const std::vector<uint8_t>message, ED<Curve> &Ik, X<Curve> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept {
void parseMessage_X3DHinit(const std::vector<uint8_t>message, DSA<Curve, lime::DSAtype::publicKey> &Ik, X<Curve, lime::Xtype::publicKey> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept {
OPk_flag = (message[0] == static_cast<uint8_t>(DR_X3DH_OPk_flag::withOPk))?true:false;
size_t index = 1;
Ik.assign(message.cbegin()+index);
index += ED<Curve>::keyLength();
index += DSA<Curve, lime::DSAtype::publicKey>::ssize();
Ek.assign(message.cbegin()+index);
index += X<Curve>::keyLength();
index += X<Curve, lime::Xtype::publicKey>::ssize();
SPk_id = static_cast<uint32_t>(message[index])<<24 |
static_cast<uint32_t>(message[index+1])<<16 |
......@@ -162,7 +162,7 @@ namespace lime {
return false;
}
// check length
size_t x3dh_initMessageSize = 1 + ED<Curve>::keyLength() + X<Curve>::keyLength() + 4; // size of X3DH init message without OPk
size_t x3dh_initMessageSize = 1 + DSA<Curve, lime::DSAtype::publicKey>::ssize() + X<Curve, lime::Xtype::publicKey>::ssize() + 4; // size of X3DH init message without OPk
if (message[3] == 1) { // there is an OPk
x3dh_initMessageSize += 4;
}
......@@ -193,7 +193,7 @@ namespace lime {
* @param[in] X3DH_initMessage A buffer holding an X3DH init message to be inserted in header, if empty packet type is set to regular
*/
template <typename Curve>
void buildMessage_header(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<Curve> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept {
void buildMessage_header(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<Curve, lime::Xtype::publicKey> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept {
// Header is one buffer composed of:
// Version Number<1 byte> || packet Type <1 byte> || curve Id <1 byte> || [<x3d init <variable>] || Ns <2 bytes> || PN <2 bytes> || Key type byte Id(1 byte) || self public key<DHKey::size bytes>
header.assign(1, static_cast<uint8_t>(double_ratchet_protocol::DR_v01));
......@@ -234,12 +234,12 @@ namespace lime {
// packet type <1 byte> ||
// curve id <1 byte> ||
// Ns<2 bytes> || PN <2 bytes> ||
// DHs < X<Curve>::keyLength() >
// DHs < X<Curve, lime::Xtype::publicKey>::ssize() >
m_size = headerSize<Curve>(); // headerSize is the size when no X3DJ init is present
if (header.size() >= m_size) { //header shall be actually longer because buffer pass is the whole message
m_Ns = header[3]<<8|header[4];
m_PN = header[5]<<8|header[6];
m_DHs = X<Curve>{header.data()+7}; // DH key start after header other infos
m_DHs = X<Curve, lime::Xtype::publicKey>{header.cbegin()+7}; // DH key start after header other infos
m_valid = true;
}
break;
......@@ -250,14 +250,14 @@ namespace lime {
// curve id <1 byte> ||
// x3dh init message <variable> ||
// Ns<2 bytes> || PN <2 bytes> ||
// DHs < X<Curve>::keyLength() >
// DHs < X<Curve, lime::Xtype::publicKey>::ssize() >
//
// x3dh init is : haveOPk <flag 1 byte : 0 no OPk, 1 OPk > ||
// self Ik < ED<Curve>::keyLength() bytes > ||
// Ek < X<Curve>::keyLenght() bytes > ||
// self Ik < DSA<Curve, lime::DSAtype::publicKey>::ssize() bytes > ||
// Ek < X<Curve, lime::Xtype::publicKey>::keyLenght() bytes > ||
// peer SPk id < 4 bytes > ||
// [peer OPk id < 4 bytes >] {0,1} according to haveOPk flag
size_t x3dh_initMessageSize = 1 + ED<Curve>::keyLength() + X<Curve>::keyLength() + 4; // add size of X3DH init message without OPk
size_t x3dh_initMessageSize = 1 + DSA<Curve, lime::DSAtype::publicKey>::ssize() + X<Curve, lime::Xtype::publicKey>::ssize() + 4; // add size of X3DH init message without OPk
if (header[3] == 1) { // there is an OPk
x3dh_initMessageSize += 4;
}
......@@ -267,7 +267,7 @@ namespace lime {
if (header.size() >= m_size) { //header shall be actually longer because buffer pass is the whole message
m_Ns = header[3+x3dh_initMessageSize]<<8|header[4+x3dh_initMessageSize];
m_PN = header[5+x3dh_initMessageSize]<<8|header[6+x3dh_initMessageSize];
m_DHs = X<Curve>{header.data()+7+x3dh_initMessageSize}; // DH key start after header other infos
m_DHs = X<Curve, lime::Xtype::publicKey>{header.cbegin()+7+x3dh_initMessageSize}; // DH key start after header other infos
m_valid = true;
}
}
......@@ -284,18 +284,18 @@ namespace lime {
/* Instanciate templated functions */
#ifdef EC25519_ENABLED
template void buildMessage_X3DHinit<C255>(std::vector<uint8_t> &message, const ED<C255> &Ik, const X<C255> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
template void parseMessage_X3DHinit<C255>(const std::vector<uint8_t>message, ED<C255> &Ik, X<C255> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
template void buildMessage_X3DHinit<C255>(std::vector<uint8_t> &message, const DSA<C255, lime::DSAtype::publicKey> &Ik, const X<C255, lime::Xtype::publicKey> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
template void parseMessage_X3DHinit<C255>(const std::vector<uint8_t>message, DSA<C255, lime::DSAtype::publicKey> &Ik, X<C255, lime::Xtype::publicKey> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
template bool parseMessage_get_X3DHinit<C255>(const std::vector<uint8_t> &message, std::vector<uint8_t> &X3DH_initMessage) noexcept;
template void buildMessage_header<C255>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C255> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
template void buildMessage_header<C255>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C255, lime::Xtype::publicKey> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
template class DRHeader<C255>;
#endif
#ifdef EC448_ENABLED
template void buildMessage_X3DHinit<C448>(std::vector<uint8_t> &message, const ED<C448> &Ik, const X<C448> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
template void parseMessage_X3DHinit<C448>(const std::vector<uint8_t>message, ED<C448> &Ik, X<C448> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
template void buildMessage_X3DHinit<C448>(std::vector<uint8_t> &message, const DSA<C448, lime::DSAtype::publicKey> &Ik, const X<C448, lime::Xtype::publicKey> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
template void parseMessage_X3DHinit<C448>(const std::vector<uint8_t>message, DSA<C448, lime::DSAtype::publicKey> &Ik, X<C448, lime::Xtype::publicKey> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
template bool parseMessage_get_X3DHinit<C448>(const std::vector<uint8_t> &message, std::vector<uint8_t> &X3DH_initMessage) noexcept;
template void buildMessage_header<C448>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C448> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
template void buildMessage_header<C448>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C448, lime::Xtype::publicKey> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
template class DRHeader<C448>;
#endif
......
......@@ -20,13 +20,13 @@
#ifndef lime_double_ratchet_protocol_hpp
#define lime_double_ratchet_protocol_hpp
#include "lime_keys.hpp"
#include "lime_crypto_primitives.hpp"
namespace lime {
namespace double_ratchet_protocol {
/**
* @brief build an X3DH init message to insert in DR header
* haveOPk <flag 1 byte> || self Ik < ED<Curve>::keyLength() bytes > || Ek < X<Curve>::keyLenght() bytes> || peer SPk id < 4 bytes > || [peer OPk id(if flag is set)<4bytes>]
* haveOPk <flag 1 byte> || self Ik < DSA<Curve, lime::DSAtype::publicKey>::ssize() bytes > || Ek < X<Curve, Xtype::publicKey>::ssize() bytes> || peer SPk id < 4 bytes > || [peer OPk id(if flag is set)<4bytes>]
*
* @param[out] message the X3DH init message
* @param[in] Ik self public identity key
......@@ -37,7 +37,7 @@ namespace lime {
*
*/
template <typename Curve>
void buildMessage_X3DHinit(std::vector<uint8_t> &message, const ED<Curve> &Ik, const X<Curve> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
void buildMessage_X3DHinit(std::vector<uint8_t> &message, const DSA<Curve, lime::DSAtype::publicKey> &Ik, const X<Curve, lime::Xtype::publicKey> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
/**
* @brief Parse the X3DH init message and extract peer Ik, peer Ek, self SPk id and seld OPk id if present
......@@ -54,7 +54,7 @@ namespace lime {
* @param[out] OPk_flag true if an OPk flag was present in the message
*/
template <typename Curve>
void parseMessage_X3DHinit(const std::vector<uint8_t>message, ED<Curve> &Ik, X<Curve> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
void parseMessage_X3DHinit(const std::vector<uint8_t>message, DSA<Curve, lime::DSAtype::publicKey> &Ik, X<Curve, lime::Xtype::publicKey> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
/**
* @brief check the message for presence of X3DH init in the header, extract it if there is one
......@@ -78,7 +78,7 @@ namespace lime {
* @param[in] X3DH_initMessage A buffer holding an X3DH init message to be inserted in header, if empty packet type is set to regular
*/
template <typename Curve>
void buildMessage_header(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<Curve> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
void buildMessage_header(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<Curve, lime::Xtype::publicKey> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
/**
* DR message header: helper class and functions to parse message header and access its components
......@@ -88,7 +88,7 @@ namespace lime {
class DRHeader {
private:
uint16_t m_Ns,m_PN; // Sender chain and Previous Sender chain indexes.
X<Curve> m_DHs; // Public key
X<Curve, lime::Xtype::publicKey> m_DHs; // Public key
bool m_valid; // is this header valid?
size_t m_size; // store the size of parsed header
......@@ -96,7 +96,7 @@ namespace lime {
/* data member accessors (read only) */
uint16_t Ns(void) const {return m_Ns;}
uint16_t PN(void) const {return m_PN;}
const X<Curve> &DHs(void) const {return m_DHs;}
const X<Curve, lime::Xtype::publicKey> &DHs(void) const {return m_DHs;}
bool valid(void) const {return m_valid;}
size_t size(void) {return m_size;}
......@@ -108,18 +108,18 @@ namespace lime {
/* this templates are intanciated in lime_double_ratchet_procotocol.cpp, do not re-instanciate it anywhere else */
#ifdef EC25519_ENABLED
extern template void buildMessage_X3DHinit<C255>(std::vector<uint8_t> &message, const ED<C255> &Ik, const X<C255> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
extern template void parseMessage_X3DHinit<C255>(const std::vector<uint8_t>message, ED<C255> &Ik, X<C255> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
extern template void buildMessage_X3DHinit<C255>(std::vector<uint8_t> &message, const DSA<C255, lime::DSAtype::publicKey> &Ik, const X<C255, lime::Xtype::publicKey> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
extern template void parseMessage_X3DHinit<C255>(const std::vector<uint8_t>message, DSA<C255, lime::DSAtype::publicKey> &Ik, X<C255, lime::Xtype::publicKey> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
extern template bool parseMessage_get_X3DHinit<C255>(const std::vector<uint8_t> &message, std::vector<uint8_t> &X3DH_initMessage) noexcept;
extern template void buildMessage_header<C255>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C255> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
extern template void buildMessage_header<C255>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C255, lime::Xtype::publicKey> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
extern template class DRHeader<C255>;
#endif
#ifdef EC448_ENABLED
extern template void buildMessage_X3DHinit<C448>(std::vector<uint8_t> &message, const ED<C448> &Ik, const X<C448> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
extern template void parseMessage_X3DHinit<C448>(const std::vector<uint8_t>message, ED<C448> &Ik, X<C448> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
extern template void buildMessage_X3DHinit<C448>(std::vector<uint8_t> &message, const DSA<C448, lime::DSAtype::publicKey> &Ik, const X<C448, lime::Xtype::publicKey> &Ek, const uint32_t SPk_id, const uint32_t OPk_id, const bool OPk_flag) noexcept;
extern template void parseMessage_X3DHinit<C448>(const std::vector<uint8_t>message, DSA<C448, lime::DSAtype::publicKey> &Ik, X<C448, lime::Xtype::publicKey> &Ek, uint32_t &SPk_id, uint32_t &OPk_id, bool &OPk_flag) noexcept;
extern template bool parseMessage_get_X3DHinit<C448>(const std::vector<uint8_t> &message, std::vector<uint8_t> &X3DH_initMessage) noexcept;
extern template void buildMessage_header<C448>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C448> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
extern template void buildMessage_header<C448>(std::vector<uint8_t> &header, const uint16_t Ns, const uint16_t PN, const X<C448, lime::Xtype::publicKey> &DHs, const std::vector<uint8_t> X3DH_initMessage) noexcept;
extern template class DRHeader<C448>;
#endif
/* These constants are needed only for tests purpose, otherwise their usage is internal only */
......
......@@ -26,7 +26,7 @@
#include "lime/lime.hpp"
#include "lime_lime.hpp"
#include "lime_keys.hpp"
#include "lime_crypto_primitives.hpp"
#include "lime_localStorage.hpp"
#include "lime_double_ratchet.hpp"
#include "lime_x3dh_protocol.hpp"
......@@ -44,11 +44,11 @@ namespace lime {
private:
/*** data members ***/
/* general purpose */
bctbx_rng_context_t *m_RNG; // Random Number Generator context
std::shared_ptr<RNG> m_RNG; // Random Number Generator context
std::string m_selfDeviceId; // self device Id, shall be the GRUU
/* X3DH keys */
KeyPair<ED<Curve>> m_Ik; // our identity key pair, is loaded from DB only if requested(to sign a SPK or to perform X3DH init)
DSApair<Curve> m_Ik; // our identity key pair, is loaded from DB only if requested(to sign a SPK or to perform X3DH init)
bool m_Ik_loaded; // did we load the Ik yet?
/* local storage related */
......@@ -74,14 +74,14 @@ namespace lime {
void get_SelfIdentityKey(); // check our Identity key pair is loaded in Lime object, retrieve it from DB if it isn't
void cache_DR_sessions(std::vector<recipientInfos<Curve>> &internal_recipients, std::vector<std::string> &missing_devices); // loop on internal recipient an try to load in DR session cache the one which have no session attached
void get_DRSessions(const std::string &senderDeviceId, const long int ignoreThisDRSessionId, std::vector<std::shared_ptr<DR<Curve>>> &DRSessions); // load from local storage in DRSessions all DR session matching the peerDeviceId, ignore the one picked by id in 2nd arg
long int store_peerDevice(const std::string &peerDeviceId, const ED<Curve> &Ik); // store given peer Device Id and public identity key, return the Id used in table to store it
long int store_peerDevice(const std::string &peerDeviceId, const DSA<Curve, lime::DSAtype::publicKey> &Ik); // store given peer Device Id and public identity key, return the Id used in table to store it
/* X3DH related - part related to exchange with server or localStorage - implemented in lime_x3dh_protocol.cpp or lime_localStorage.cpp */
void X3DH_generate_SPk(X<Curve> &publicSPk, Signature<Curve> &SPk_sig, uint32_t &SPk_id); // generate a new Signed Pre-Key key pair, store it in DB and set its public key, signature and Id in given params
void X3DH_generate_OPks(std::vector<X<Curve>> &publicOPks, std::vector<uint32_t> &OPk_ids, const uint16_t OPk_number); // generate a new batch of OPks, store them in base and fill the vector with information to be sent to X3DH server
void X3DH_get_SPk(uint32_t SPk_id, KeyPair<X<Curve>> &SPk); // retrieve matching SPk from localStorage, throw an exception if not found
void X3DH_generate_SPk(X<Curve, lime::Xtype::publicKey> &publicSPk, DSA<Curve, lime::DSAtype::signature> &SPk_sig, uint32_t &SPk_id); // generate a new Signed Pre-Key key pair, store it in DB and set its public key, signature and Id in given params
void X3DH_generate_OPks(std::vector<X<Curve, lime::Xtype::publicKey>> &publicOPks, std::vector<uint32_t> &OPk_ids, const uint16_t OPk_number); // generate a new batch of OPks, store them in base and fill the vector with information to be sent to X3DH server
void X3DH_get_SPk(uint32_t SPk_id, Xpair<Curve> &SPk); // retrieve matching SPk from localStorage, throw an exception if not found
bool is_currentSPk_valid(void); // check validity of current SPk
void X3DH_get_OPk(uint32_t OPk_id, KeyPair<X<Curve>> &SPk); // retrieve matching OPk from localStorage, throw an exception if not found
void X3DH_get_OPk(uint32_t OPk_id, Xpair<Curve> &OPk); // retrieve matching OPk from localStorage, throw an exception if not found
void X3DH_updateOPkStatus(const std::vector<uint32_t> &OPkIds); // update OPks to tag those not anymore on X3DH server but not used and destroyed yet
/* X3DH related - part related to X3DH DR session initiation, implemented in lime_x3dh.cpp */
void X3DH_init_sender_session(const std::vector<X3DH_peerBundle<Curve>> &peersBundle); // compute a sender X3DH using the data from peer bundle, then create and load the DR_Session
......
/*
lime_keys.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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define BCTBX_LOG_DOMAIN "lime"
#include <bctoolbox/logging.h>
#include "lime_keys.hpp"
namespace lime {
/****************************************************************/
/* ECDH keys */
/****************************************************************/
/* function to create a ECDH context */
template <typename Curve>
bctbx_ECDHContext_t *ECDHInit(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 sessionsInit<> for your type: correctly initialise the ECDH context");
return nullptr;
}
#ifdef EC25519_ENABLED
/* specialise ECDH context creation */
template <> bctbx_ECDHContext_t *ECDHInit<C255>(void) {
return bctbx_CreateECDHContext(BCTBX_ECDH_X25519);
}
#endif
#ifdef EC448_ENABLED
/* specialise ECDH context creation */
template <> bctbx_ECDHContext_t *ECDHInit<C448>(void) {
return bctbx_CreateECDHContext(BCTBX_ECDH_X448);
}
#endif
/****************************************************************/
/* EdDSA keys */
/****************************************************************/
/* function to create a EDDSA context */
template <typename Curve>
bctbx_EDDSAContext_t *EDDSAInit(void) {
/* if this template is instanciated the static_assert will fail but will give us an error message with DRType */
static_assert(sizeof(Curve) != sizeof(Curve), "You must specialize sessionsInit<> for your type: correctly initialise the ECDH context");
return nullptr;
}
#ifdef EC25519_ENABLED
/* specialise EDDSA context creation */
template <> bctbx_EDDSAContext_t *EDDSAInit<C255>(void) {
return bctbx_CreateEDDSAContext(BCTBX_EDDSA_25519);
}
#endif
#ifdef EC448_ENABLED
/* specialise EDDSA context creation */
template <> bctbx_EDDSAContext_t *EDDSAInit<C448>(void) {
return bctbx_CreateEDDSAContext(BCTBX_EDDSA_448);
}
#endif
/* template instanciations for Curves 25519 and 448, done */
#ifdef EC255_ENABLED
template class X<C255>;
template class ED<C255>;
template class KeyPair<X<C255>>;
template class KeyPair<ED<C255>>;
#endif
#ifdef EC448_ENABLED
template class X<C448>;
template class ED<C448>;
template class KeyPair<X<C448>>;
template class KeyPair<ED<C448>>;
#endif
}
......@@ -23,125 +23,30 @@
#include <algorithm> //std::copy_n
#include <array>
#include <iterator>
#include "bctoolbox/crypto.h"
#include "lime/lime.hpp"
namespace lime {
// define available keys and signatures sizes in an enum (forward define from bctoolbox/crypto.h)
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};
// Data structure type enumerations
enum class Xtype {publicKey, privateKey, sharedSecret}; // key Echange has public key, private key and shared secret
enum class DSAtype {publicKey, privateKey, signature}; // Signature has public key, private key and signature
/* 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 */
/* define needed constant for the curves: self identificatio(used in DB and as parameter from lib users, data structures sizes)*/
/* These structure are used as template argument to enable support for different Algorithms */
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 size_t EDkeySize() {return static_cast<size_t>(keySize::ed25519);};
static constexpr size_t EDSigSize() {return static_cast<size_t>(sigSize::ed25519);};
// for X25519, public, private and shared secret have the same length: 32 bytes
static constexpr size_t Xsize(lime::Xtype dataType) {return 32;};
// for Ed25519, public and private key have the same length: 32 bytes, signature is 64 bytes long
static constexpr size_t DSAsize(lime::DSAtype dataType) {return (dataType != lime::DSAtype::signature)?32:64;};
};
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 size_t EDkeySize() {return static_cast<size_t>(keySize::ed448);};
static constexpr size_t EDSigSize() {return static_cast<size_t>(sigSize::ed448);};
// for X448, public, private and shared secret have the same length 56 bytes
static constexpr size_t Xsize(lime::Xtype dataType) {return 56;};
// for Ed448, public and private key have the same length 57 bytes, signature is 114 bytes long
static constexpr size_t DSAsize(lime::DSAtype dataType) {return (dataType != lime::DSAtype::signature)?57:114;};
};
/****************************************************************/
/* 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
// 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());}
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
// 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());}
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(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::EDSigSize(), this->begin());}
Signature() {};
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Curve::EDSigSize(), this->begin());} // copy from a std::vector<uint8_t>
};
/****************************************************************/
/* 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 */
This diff is collapsed.
This diff is collapsed.
......@@ -103,7 +103,7 @@ namespace lime {
// registerUser : Identity Key<EDDSA Public Key length>
template <typename Curve>
void buildMessage_registerUser(std::vector<uint8_t> &message, const ED<Curve> &Ik) noexcept {
void buildMessage_registerUser(std::vector<uint8_t> &message, const DSA<Curve, lime::DSAtype::publicKey> &Ik) noexcept {
// create the header
message = X3DH_makeHeader(x3dh_message_type::registerUser, Curve::curveId());
// append the Ik
......@@ -122,7 +122,7 @@ namespace lime {
// SPk Signature<Signature Length> ||