Commit 40b865d2 authored by Johan Pascal's avatar Johan Pascal

Add make doc and improve the code documentation

+ some code cleaning in lime_x3dh_protocol.hpp
parent 2075a166
......@@ -24,6 +24,7 @@ include(CheckSymbolExists)
include(CheckLibraryExists)
include(CMakePushCheckState)
include(CMakePackageConfigHelpers)
include(CPack)
cmake_minimum_required(VERSION 3.0)
project(lime VERSION 0.0.1 LANGUAGES CXX)
......@@ -142,6 +143,17 @@ install(FILES
DESTINATION ${ConfigPackageLocation}
)
# Doxygen
find_package(Doxygen)
if (DOXYGEN_FOUND)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating API documentation with Doxygen" VERBATIM
)
endif()
# CPack settings
set(CPACK_PACKAGE_NAME "lime")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
......@@ -152,4 +164,3 @@ set(CPACK_SOURCE_IGNORE_FILES
"/\\\\..+"
)
include(CPack)
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -26,30 +26,45 @@
namespace lime {
/* This enum identifies the elliptic curve used in lime, the values assigned are used in localStorage and X3DH server
* so do not modify it or we'll loose sync with existing DB and X3DH server */
enum class CurveId : uint8_t {unset=0, c25519=1, c448=2};
/* enum to manage the encryption policy:
* - DRMessage: the plaintext input is encrypted inside the Double Ratchet message(each recipient get a different encryption): not optimal for messages with numerous recipient
* - cipherMessage: the plaintext input is encrypted with a random key and this random key is encrypted to each participant inside the Double Ratchet message(for a single recipient the overhead is 48 bytes)
* - optimizeSize: optimize output size: encrypt in DR message if plaintext is short enougth to beat the overhead introduced by cipher message scheme, otherwise use cipher message. This is the default policy used
/** Identifies the elliptic curve used in lime, the values assigned are used in localStorage and X3DH server
* so do not modify it or we'll loose sync with existing DB and X3DH server
*/
enum class EncryptionPolicy {DRMessage, cipherMessage, optimizeSize};
enum class CurveId : uint8_t {
unset=0, /**< used as default to detected incorrect behavior */
c25519=1, /**< Curve 25519 */
c448=2}; /**< Curve 448-goldilocks */
/* Struct used to manage recipient list for encrypt function input: give a recipient GRUU and get it back with the header which must be sent to recipient with the cipher text*/
/** Manage the encryption policy : how is the user's plaintext encrypted */
enum class EncryptionPolicy {
DRMessage, /**< the plaintext input is encrypted inside the Double Ratchet message(each recipient get a different encryption): not optimal for messages with numerous recipient */
cipherMessage, /**< the plaintext input is encrypted with a random key and this random key is encrypted to each participant inside the Double Ratchet message(for a single recipient the overhead is 48 bytes) */
optimizeSize /**< optimize output size: encrypt in DR message if plaintext is short enougth to beat the overhead introduced by cipher message scheme, otherwise use cipher message. This is the default policy used */
};
/** Used to manage recipient list for encrypt function input: give a recipient GRUU and get it back with the header which must be sent to recipient with the cipher text*/
struct recipientData {
std::string deviceId; // recipient deviceId (shall be GRUU)
bool identityVerified; // after encrypt calls back, it will hold the status of this peer device: identity verified or not
std::vector<uint8_t> cipherHeader; // after encrypt calls back, it will hold the header targeted to the specified recipient. This header may contain an X3DH init message.
const std::string deviceId; /**< recipient deviceId (shall be GRUU) */
bool identityVerified; /**< after encrypt calls back, it will hold the status of this peer device: identity verified or not */
std::vector<uint8_t> cipherHeader; /**< after encrypt calls back, it will hold the header targeted to the specified recipient. This header may contain an X3DH init message. */
/**
* recipient data are built giving a recipient id
* @param[in] deviceId the recipient device Id (its GRUU)
*/
recipientData(const std::string deviceId) : deviceId{deviceId}, identityVerified{false}, cipherHeader{} {};
};
/* Enum of what a Lime callback could possibly say */
enum class callbackReturn : uint8_t {success, fail};
// a callback function must return a code and may return a string(could actually be empty) to detail what's happening
// callback is used on every operation possibly involving a connection to X3DH server: create_user, delete_user, encrypt
using limeCallback = std::function<void(lime::callbackReturn, std::string)>;
/** what a Lime callback could possibly say */
enum class callbackReturn : uint8_t {
success, /**< operation completed successfully */
fail /**< operation failed, we shall have an explanation string too */
};
/** @brief Callback use to give a status on asynchronous operation
* it returns a code and may return a string(could actually be empty) to detail what's happening
* callback is used on every operation possibly involving a connection to X3DH server: create_user, delete_user, encrypt and update
* @param[in] status success or fail
* @param[in] message in case of failure, an explanation, it may be empty
*/
using limeCallback = std::function<void(const lime::callbackReturn status, const std::string message)>;
/* X3DH server communication : these functions prototypes are used to post data and get response from/to the X3DH server */
/**
......@@ -74,7 +89,11 @@ namespace lime {
/* Forward declare the class managing one lime user*/
class LimeGeneric;
/* Manage Lime objects(it's one per user), then adressed using their device Id (GRUU) */
/** Manage Lime objects
* LimeManager is mostly a cache of Lime users, any command get as first parameter the device Id (Lime manage devices only, the link user(sip:uri)<->device(GRUU) is provided by upper level)
* All interactions should take place through the LimeManager object, any endpoint shall have only one LimeManager object instanciated
*/
class LimeManager {
private :
std::unordered_map<std::string, std::shared_ptr<LimeGeneric>> m_users_cache; // cache of already opened Lime Session, identified by user Id (GRUU)
......@@ -83,7 +102,6 @@ namespace lime {
void load_user(std::shared_ptr<LimeGeneric> &user, const std::string &localDeviceId); // helper function, get from m_users_cache of local Storage the requested Lime object
public :
/* LimeManager is mostly a cache of Lime users, any command get as first parameter the device Id (Lime manage devices only, the link user(sip:uri)<->device(GRUU) is provided by upper level) */
/**
* @brief Create a user in local database and publish it on the given X3DH server
......@@ -97,10 +115,14 @@ namespace lime {
* @param[in] initialOPkBatchSize Number of OPks in the first batch uploaded to X3DH server
* @param[in] callback This operation contact the X3DH server and is thus asynchronous, when server responds,
* this callback will be called giving the exit status and an error message in case of failure
* @note
* The initialOPkBatchSize is optionnal, if not used, set to defaults defined in lime::settings
* (not done with param default value as the lime::settings shall not be available in public include)
*/
void create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const uint16_t initialOPkBatchSize, const limeCallback &callback);
/**
* @overload void create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const limeCallback &callback)
*/
void create_user(const std::string &localDeviceId, const std::string &x3dhServerUrl, const lime::CurveId curve, const limeCallback &callback);
/**
......@@ -136,7 +158,7 @@ namespace lime {
*
* @param[in] localDeviceId used to identify which local acount to use and also as the identified source of the message, shall be the GRUU
* @param[in] recipientUserId the Id of intended recipient, shall be a sip:uri of user or conference, is used as associated data to ensure no-one can mess with intended recipient
* @param[in/out] recipients a list of recipientData holding: the recipient device Id(GRUU) and an empty buffer to store the cipherHeader which must then be routed to that recipient
* @param[in,out] recipients a list of recipientData holding: the recipient device Id(GRUU) and an empty buffer to store the cipherHeader which must then be routed to that recipient
* @param[in] plainMessage a buffer holding the message to encrypt, can be text or data.
* @param[out] cipherMessage points to the buffer to store the encrypted message which must be routed to all recipients
* @param[in] callback Performing encryption may involve the X3DH server and is thus asynchronous, when the operation is completed,
......@@ -155,6 +177,7 @@ namespace lime {
* @param[in] localDeviceId used to identify which local acount to use and also as the recipient device ID of the message, shall be the GRUU
* @param[in] recipientUserId the Id of intended recipient, shall be a sip:uri of user or conference, is used as associated data to ensure no-one can mess with intended recipient
* it is not necessarily the sip:uri base of the GRUU as this could be a message from alice first device intended to bob being decrypted on alice second device
* @param[in] senderDeviceId Identify sender Device. This field shall be extracted from signaling data in transport protocol, is used to rebuild the authenticated data associated to the encrypted message
* @param[in] cipherHeader the part of cipher which is targeted to current device
* @param[in] cipherMessage part of cipher routed to all recipient devices
* @param[out] plainMessage the output buffer
......@@ -176,11 +199,15 @@ namespace lime {
* @param[in] OPkServerLowLimit If server holds less OPk than this limit, generate and upload a batch of OPks
* @param[in] OPkBatchSize Number of OPks in a batch uploaded to server
*
* @note
* The last two parameters are optionnal, if not used, set to defaults defined in lime::settings
* (not done with param default value as the lime::settings shall not be available in public include)
*/
void update(const limeCallback &callback);
void update(const limeCallback &callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize);
/**
* @overload void update(const limeCallback &callback)
*/
void update(const limeCallback &callback);
/**
* @brief retrieve self Identity Key, an EdDSA formatted public key
......
......@@ -45,7 +45,7 @@ namespace lime {
* before calling this constructor, user existence in DB is checked and its Uid retrieved
* just load it into Lime class
*
* @param[in/out] localStorage pointer to DB accessor
* @param[in,out] localStorage pointer to DB accessor
* @param[in] deviceId device Id(shall be GRUU), stored in the structure
* @param[in] url URL of the X3DH key server used to publish our keys(retrieved from DB)
* @param[in] X3DH_post_data A function used to communicate with the X3DH server
......@@ -65,7 +65,7 @@ namespace lime {
* @brief Create user constructor
* Create a user in DB, if already existing, throw exception
*
* @param[in/out] localStorage pointer to DB accessor
* @param[in,out] localStorage pointer to DB accessor
* @param[in] deviceId device Id(shall be GRUU), stored in the structure
* @param[in] url URL of the X3DH key server used to publish our keys
* @param[in] X3DH_post_data A function used to communicate with the X3DH server
......
......@@ -48,6 +48,9 @@ namespace lime {
/***** Random Number Generator ********/
/**
* A wrapper around the bctoolbox Random Number Generator
*/
class bctbx_RNG : public RNG {
private :
bctbx_rng_context_t *m_context; // the bctoolbox RNG context
......@@ -101,6 +104,11 @@ bctbx_EDDSAContext_t *bctbx_EDDSAInit(void) {
return bctbx_CreateEDDSAContext(BCTBX_EDDSA_448);
}
#endif // EC448_ENABLED
/**
* a wrapper around bctoolbox Signature algorithm.
* Provides EdDSA on curves 25519 and 448
*/
template <typename Curve>
class bctbx_EDDSA : public Signature<Curve> {
private :
......@@ -140,7 +148,7 @@ class bctbx_EDDSA : public Signature<Curve> {
}
/**
* @Brief generate a new random EdDSA key pair
* @brief generate a new random EdDSA key pair
*
* @param[in] rng The Random Number Generator to be used to generate the private kay
*/
......@@ -224,6 +232,10 @@ bctbx_ECDHContext_t *bctbx_ECDHInit(void) {
}
#endif //EC448_ENABLED
/**
* a wrapper around bctoolbox key exchange algorithm.
* Provides X25519 and X448
*/
template <typename Curve>
class bctbx_ECDH : public keyExchange<Curve> {
private :
......@@ -327,7 +339,7 @@ class bctbx_ECDH : public keyExchange<Curve> {
/**
* @Brief generate a new random ECDH key pair
* @brief generate a new random ECDH key pair
*
* @param[in] rng The Random Number Generator to be used to generate the private kay
*/
......
......@@ -33,38 +33,51 @@ namespace lime {
/**
* @brief force a buffer values to zero in a way that shall prevent the compiler from optimizing it out
*
* @param[in/out] buffer the buffer to be cleared
* @param[in,out] buffer the buffer to be cleared
* @param[in] size buffer size
*/
void cleanBuffer(uint8_t *buffer, size_t size);
/****************************************************************/
/* auto clean fixed size buffer */
/****************************************************************/
/**
* auto clean fixed size buffer(std::array based)
*/
template <size_t T>
struct sBuffer : public std::array<uint8_t, T> {
~sBuffer() {cleanBuffer(this->data(), T);}; // zeroise all buffer when done
/// zeroise all buffer when done
~sBuffer() {cleanBuffer(this->data(), T);};
};
/****************************************************************/
/* auto clean flexible size buffer(uint8_t vector based) */
/****************************************************************/
/**
* auto clean flexible size buffer(uint8_t vector based)
*/
struct sVector : public std::vector<uint8_t> {
~sVector() {cleanBuffer(this->data(), this->size());}; // zeroise all buffer when done
/// zeroise all buffer when done
~sVector() {cleanBuffer(this->data(), this->size());};
};
/****************************************************************/
/* Key Exchange Data structures */
/****************************************************************/
/**
* Base buffer definition for Key Exchange data structure : easy use of array types with correct size
*/
template <typename Base, lime::Xtype dataType>
class X : public std::array<uint8_t, static_cast<size_t>(Base::Xsize(dataType))>{
public :
constexpr static size_t ssize(void) {return Base::Xsize(dataType);}; // provide a static size function to be able to call the function not on an object
X(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::Xsize(dataType), this->begin());} // construct from a std::vector<uint8_t>
/// provide a static size function to be able to call the function not on an object
constexpr static size_t ssize(void) {return Base::Xsize(dataType);};
/// construct from a std::vector<uint8_t>
X(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::Xsize(dataType), this->begin());}
X() {};
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::Xsize(dataType), this->begin());} // copy from a std::vector<uint8_t>
~X() {cleanBuffer(this->data(), Base::Xsize(dataType));}; // zeroise all buffer when done
/// copy from a std::vector<uint8_t>
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::Xsize(dataType), this->begin());}
/// zeroise all buffer when done
~X() {cleanBuffer(this->data(), Base::Xsize(dataType));};
};
/**
* Key pair structure for key exchange algorithm
*/
template <typename Base>
class Xpair {
private:
......@@ -82,16 +95,26 @@ namespace lime {
/****************************************************************/
/* Digital Signature Algorithm data structures */
/****************************************************************/
/**
* Base buffer definition for DSA data structure : easy use of array types with correct size
*/
template <typename Base, lime::DSAtype dataType>
class DSA : public std::array<uint8_t, static_cast<size_t>(Base::DSAsize(dataType))>{
public :
constexpr static size_t ssize(void) {return Base::DSAsize(dataType);}; // provide a static size function to be able to call the function not on an object
DSA(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::DSAsize(dataType), this->begin());} // contruct from a std::vector<uint8_t>
/// provide a static size function to be able to call the function not on an object
constexpr static size_t ssize(void) {return Base::DSAsize(dataType);};
/// contruct from a std::vector<uint8_t>
DSA(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::DSAsize(dataType), this->begin());}
DSA() {};
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::DSAsize(dataType), this->begin());} // copy from a std::vector<uint8_t>
~DSA() {cleanBuffer(this->data(), Base::DSAsize(dataType));}; // zeroise all buffer when done
/// copy from a std::vector<uint8_t>
void assign(std::vector<uint8_t>::const_iterator buffer) {std::copy_n(buffer, Base::DSAsize(dataType), this->begin());}
/// zeroise all buffer when done
~DSA() {cleanBuffer(this->data(), Base::DSAsize(dataType));};
};
/**
* Key pair structure for DSA algorithm
*/
template <typename Base>
class DSApair {
private:
......@@ -110,10 +133,13 @@ namespace lime {
/********************** Crypto Algo interface ****************************************************/
/*************************************************************************************************/
/**
* Random number generator
*/
class RNG {
public:
/**
* @Brief fill given buffer with Random bytes
* @brief fill given buffer with Random bytes
*
* @param[out] buffer point to the beginning of the buffer to be filled with random bytes
* @param[in] size size of the buffer to be filled
......@@ -121,7 +147,7 @@ class RNG {
virtual void randomize(uint8_t *buffer, const size_t size) = 0;
/**
* @Brief fill given buffer with Random bytes
* @brief fill given buffer with Random bytes
*
* @param[out] buffer vector to be filled with random bytes(based on original vector size)
*/
......@@ -130,6 +156,11 @@ class RNG {
virtual ~RNG() = default;
}; //class RNG
/**
* Key exchange wrapper:
* - shall be able to wrap around any algorithm providing key exchange
* - wrapped in algorithms must support key format convertion function from matching Digital Signature algorithm
*/
template <typename Base>
class keyExchange {
public:
......@@ -148,7 +179,7 @@ class keyExchange {
virtual void set_peerPublic(const DSA<Base, lime::DSAtype::publicKey> &peerPublic) = 0; /**< Peer Public key */
/**
* @Brief generate a new random key pair
* @brief generate a new random key pair
*
* @param[in] rng The Random Number Generator to be used to generate the private kay
*/
......@@ -166,6 +197,10 @@ class keyExchange {
virtual ~keyExchange() = default;
}; //class keyExchange
/**
* Digital Signature wrapper
* - shall be able to wrap around any algorithm providing key exchange
*/
template <typename Base>
class Signature {
public:
......@@ -177,7 +212,7 @@ class Signature {
virtual void set_public(const DSA<Base, lime::DSAtype::publicKey> &publicKey) = 0; /**< Self Public key */
/**
* @Brief generate a new random EdDSA key pair
* @brief generate a new random EdDSA key pair
*
* @param[in] rng The Random Number Generator to be used to generate the private kay
*/
......@@ -195,6 +230,10 @@ class Signature {
* @param[out] signature The signature produced from the message with a key pair previously introduced in the object
*/
virtual void sign(const std::vector<uint8_t> &message, DSA<Base, lime::DSAtype::signature> &signature) = 0;
/*
* @overload virtual void sign(const X<Base, lime::Xtype::publicKey> &message, DSA<Base, lime::DSAtype::signature> &signature)
* a convenience function to directly verify a key exchange public key
*/
virtual void sign(const X<Base, lime::Xtype::publicKey> &message, DSA<Base, lime::DSAtype::signature> &signature) = 0;
/**
......@@ -206,6 +245,10 @@ class Signature {
* @return true if the signature is valid, false otherwise
*/
virtual bool verify(const std::vector<uint8_t> &message, const DSA<Base, lime::DSAtype::signature> &signature) = 0;
/*
* @overload virtual bool verify(const X<Base, lime::Xtype::publicKey> &message, const DSA<Base, lime::DSAtype::signature> &signature)
* a convenience function to directly verify a key exchange public key
*/
virtual bool verify(const X<Base, lime::Xtype::publicKey> &message, const DSA<Base, lime::DSAtype::signature> &signature) = 0;
virtual ~Signature() = default;
......@@ -263,7 +306,7 @@ void HMAC_KDF(const uint8_t *const salt, const size_t saltSize, const uint8_t *c
/************************ AEAD interface *************************************/
/**
* @Brief Encrypt and tag using scheme given as template parameter
* @brief Encrypt and tag using scheme given as template parameter
*
* @param[in] key Encryption key
* @param[in] keySize Key buffer length, it must match the selected AEAD scheme or an exception is generated
......@@ -283,7 +326,7 @@ void AEAD_encrypt(const uint8_t *const key, const size_t keySize, const uint8_t
uint8_t *tag, const size_t tagSize, uint8_t *cipher);
/**
* @Brief Authenticate and Decrypt using scheme given as template parameter
* @brief Authenticate and Decrypt using scheme given as template parameter
*
* @param[in] key Encryption key
* @param[in] keySize Key buffer length, it must match the selected AEAD scheme or an exception is generated
......
......@@ -39,7 +39,7 @@ namespace lime {
* @Brief Key Derivation Function used in Root key/Diffie-Hellman Ratchet chain.
* Use HKDF (see RFC5869) to derive CK and RK in one derivation
*
* @param[in/out] RK Input buffer used as salt also to store the 32 first byte of output key material
* @param[in,out] RK Input buffer used as salt also to store the 32 first byte of output key material
* @param[out] CK Output buffer, last 32 bytes of output key material
* @param[in] dh_out Buffer used as input key material
*/
......@@ -66,7 +66,7 @@ namespace lime {
* CK = HMAC-SHA512(CK, hkdf_ck_info)
* hkdf_ck_info and hldf_mk_info being a distincts constants (0x02 and 0x01 as suggested in double ratchet - section 5.2)
*
* @param[in/out] CK Input/output buffer used as key to compute MK and then next CK
* @param[in,out] CK Input/output buffer used as key to compute MK and then next CK
* @param[out] MK Message Key(32 bytes) and IV(16 bytes) computed from HMAC_SHA512 keyed with CK
*/
static void KDF_CK(DRChainKey &CK, DRMKey &MK) noexcept {
......@@ -108,7 +108,7 @@ namespace lime {
* @param[in] plaintext the input message
* @param[in] AD Associated data
* @param[in] headerSize Size of the header included in ciphertext
* @param[in/out] ciphertext buffer holding: header<size depends on DHKey type>, will append to it: ciphertext || auth tag<16 bytes>
* @param[in,out] ciphertext buffer holding: header<size depends on DHKey type>, will append to it: ciphertext || auth tag<16 bytes>
* this vector version need resizing before calling encrypt
*
* @return false if something goes wrong
......
......@@ -45,11 +45,20 @@ namespace lime {
// 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)
/**
* Chain storing the DH and MKs associated with Nr(uint16_t map index)
*/
template <typename Curve>
struct receiverKeyChain {
/// peer public key identifying this chain
X<Curve, lime::Xtype::publicKey> DHr;
/// message keys indexed by Nr
std::unordered_map<std::uint16_t, DRMKey> messageKeys;
/**
* Start a new empty chain
* @param[in] key the peer DH public key used on this chain
*/
receiverKeyChain(X<Curve, lime::Xtype::publicKey> key) :DHr{std::move(key)}, messageKeys{} {};
};
......@@ -110,12 +119,15 @@ namespace lime {
};
/**
* Used for internal management of recipientData, includes the Double Ratchet session shared with the recipient
*/
template <typename Curve>
struct recipientInfos {
std::shared_ptr<DR<Curve>> DRSession; // Session to reach recipient
std::string deviceId; // recipient device Id(gruu)
bool identityVerified; // will hold the status of peer: did we already verified his identity
std::vector<uint8_t> cipherHeader; // will hold the header targeted to this recipient after encryption
std::shared_ptr<DR<Curve>> DRSession; /**< DR Session to reach recipient */
std::string deviceId; /**< recipient deviceId (shall be GRUU) */
bool identityVerified; /**< after encrypt calls back, it will hold the status of this peer device: identity verified or not */
std::vector<uint8_t> cipherHeader; /**< after encrypt calls back, it will hold the header targeted to the specified recipient. This header may contain an X3DH init message. */
recipientInfos() : DRSession{nullptr}, deviceId{}, identityVerified{false}, cipherHeader{} {};
recipientInfos(std::string deviceId) : DRSession{nullptr}, deviceId{deviceId}, identityVerified{false}, cipherHeader{} {};
recipientInfos(std::string deviceId, std::shared_ptr<DR<Curve>> session) : DRSession{session}, deviceId{deviceId}, identityVerified{false}, cipherHeader{} {};
......@@ -127,7 +139,7 @@ namespace lime {
* The plaintext is first encrypted by one randomly generated key using aes-gcm
* The key and IV are then encrypted with DR Session specific to each device
*
* @param[in/out] recipients vector of recipients device id(gruu) and linked DR Session, DR Session are modified by the encryption
* @param[in,out] recipients vector of recipients device id(gruu) and linked DR Session, DR Session are modified by the encryption
* The recipients struct also hold after encryption the encrypted message header targeted to that recipient only
* @param[in] plaintext data to be encrypted
* @param[in] recipientUserId the recipient ID, not specific to a device(could be a sip-uri) or a user(could be a group sip-uri)
......@@ -146,7 +158,7 @@ namespace lime {
* @param[in] sourceDeviceId the device Id of sender(gruu)
* @param[in] recipientDeviceId the recipient ID, specific to current device(gruu)
* @param[in] recipientUserId the recipient ID, not specific to a device(could be a sip-uri) or a user(could be a group sip-uri)
* @param[int/out] DRSessions list of DR Sessions linked to sender device, first one shall be the one registered as active
* @param[int,out] DRSessions list of DR Sessions linked to sender device, first one shall be the one registered as active
* @param[out] cipherHeader message holding the random decryption key encrypted by the DR session
* @param[out] cipherMessage message encrypted with a random generated key(and IV)
* @param[out] plaintext decrypted message
......
......@@ -38,7 +38,7 @@ namespace lime {
template <typename Curve>
struct callbackUserData;
/* templated declaration of Lime can be specialised using C255 or C448 according to the elliptic curve we want to use */
/** templated declaration of Lime can be specialised using C255 or C448 according to the elliptic curve we want to use */
template <typename Curve>
class Lime : public LimeGeneric, public std::enable_shared_from_this<Lime<Curve>> {
private:
......@@ -100,7 +100,7 @@ namespace lime {
* Note: ownership of localStorage pointer is transfered to a shared pointer, private menber of Lime class
*/
Lime(std::unique_ptr<lime::Db> &&localStorage, const std::string &deviceId, const std::string &url, const limeX3DHServerPostData &X3DH_post_data);
Lime(std::unique_ptr<lime::Db> &&localStorage, const std::string &deviceId, const std::string &url, const limeX3DHServerPostData &X3DH_post_data, const long Uid);
Lime(std::unique_ptr<lime::Db> &&localStorage, const std::string &deviceId, const std::string &url, const limeX3DHServerPostData &X3DH_post_data, const long int Uid);
~Lime();
Lime(Lime<Curve> &a) = delete; // can't copy a session, force usage of shared pointers
Lime<Curve> &operator=(Lime<Curve> &a) = delete; // can't copy a session
......@@ -137,35 +137,48 @@ namespace lime {
bool decrypt(const std::string &recipientUserId, const std::string &senderDeviceId, const std::vector<uint8_t> &cipherHeader, const std::vector<uint8_t> &cipherMessage, std::vector<uint8_t> &plainMessage) override;
};
// structure holding user data during callback
/**
* structure holding user data during callback
*/
template <typename Curve>
struct callbackUserData {
// always needed
std::weak_ptr<Lime<Curve>> limeObj; // Lime is owned by the LimeManager, it shall no be destructed, do not own this with a shared_ptr as Lime obj may own the callbackUserData obj thus creating circular reference
const limeCallback callback; // is a lambda closure, not real idea of what is its lifetime but it seems ok to hold it this way
// needed for encryption: get a shared ref to keep params alive
// limeObj is owned by the LimeManager, it shall no be destructed, do not own this with a shared_ptr as Lime obj may own the callbackUserData obj thus creating circular reference
std::weak_ptr<Lime<Curve>> limeObj;
/// is a lambda closure, not real idea of what is its lifetime but it seems ok to hold it this way
const limeCallback callback;
/// Recipient username. Needed for encryption: get a shared ref to keep params alive
std::shared_ptr<const std::string> recipientUserId;
/// Recipient data vector. Needed for encryption: get a shared ref to keep params alive
std::shared_ptr<std::vector<recipientData>> recipients;
/// plaintext. Needed for encryption: get a shared ref to keep params alive
std::shared_ptr<const std::vector<uint8_t>> plainMessage;
/// ciphertext buffer. Needed for encryption: get a shared ref to keep params alive
std::shared_ptr<std::vector<uint8_t>> cipherMessage;
lime::network_state network_state_machine; /* used to run a simple state machine at user creation to perform sequence of packet sending: registerUser, postSPk, postOPks */
lime::EncryptionPolicy encryptionPolicy; /* the encryption policy from the original encryption request(if running an encryption request) */
uint16_t OPkServerLowLimit; /* Used when fetching from server self OPk to check if we shall upload more */
/// used to run a simple state machine at user creation to perform sequence of packet sending: registerUser, postSPk, postOPks
lime::network_state network_state_machine;
/// the encryption policy from the original encryption request(if running an encryption request), copy its value instead of holding a shared_ptr on it
lime::EncryptionPolicy encryptionPolicy;
/// Used when fetching from server self OPk to check if we shall upload more
uint16_t OPkServerLowLimit;
/// Used when fetching from server self OPk : how many will we upload if needed
uint16_t OPkBatchSize;
// created at user create/delete and keys Post. EncryptionPolicy is not used, set it to the default value anyway
/** created at user create/delete and keys Post. EncryptionPolicy is not used, set it to the default value anyway
*/
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef, uint16_t OPkInitialBatchSize=lime::settings::OPk_initialBatchSize, bool startRegisterUserSequence=false)
: limeObj{thiz}, callback{callbackRef},
recipientUserId{nullptr}, recipients{nullptr}, plainMessage{nullptr}, cipherMessage{nullptr}, network_state_machine{startRegisterUserSequence?lime::network_state::sendSPk:lime::network_state::done},
encryptionPolicy(lime::EncryptionPolicy::optimizeSize), OPkServerLowLimit(0), OPkBatchSize(OPkInitialBatchSize) {};
// created at update: getSelfOPks. EncryptionPolicy is not used, set it to the default value anyway
/** created at update: getSelfOPks. EncryptionPolicy is not used, set it to the default value anyway
*/
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize)
: limeObj{thiz}, callback{callbackRef},
recipientUserId{nullptr}, recipients{nullptr}, plainMessage{nullptr}, cipherMessage{nullptr}, network_state_machine{lime::network_state::done},
encryptionPolicy(lime::EncryptionPolicy::optimizeSize), OPkServerLowLimit{OPkServerLowLimit}, OPkBatchSize{OPkBatchSize} {};
// created at encrypt(getPeerBundle)
/** created at encrypt(getPeerBundle)
*/
callbackUserData(std::weak_ptr<Lime<Curve>> thiz, const limeCallback &callbackRef,
std::shared_ptr<const std::string> recipientUserId, std::shared_ptr<std::vector<recipientData>> recipients,
std::shared_ptr<const std::vector<uint8_t>> plainMessage, std::shared_ptr<std::vector<uint8_t>> cipherMessage,
......
......@@ -32,31 +32,47 @@ namespace lime {
/* 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 key Exchznge and signature Algorithms */
struct C255 { // curve 25519, use a 4 chars to identify it to improve code readability
/**
* curve 25519 key size definition, use a 4 chars(C255) to identify it to improve code readability
*/
struct C255 {
static constexpr lime::CurveId curveId() {return lime::CurveId::c25519;};
// for X25519, public, private and shared secret have the same length: 32 bytes
/// 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
/// 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
/**
* curve 448-goldilocks key sizes definition
*/
struct C448 {
static constexpr lime::CurveId curveId() {return lime::CurveId::c448;};
// for X448, public, private and shared secret have the same length 56 bytes
/// 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
/// 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;};
};
// Hash function defines
/**
* SHA512 buffer size define
*/
struct SHA512 {
static constexpr size_t ssize() {return 64;} // maximum output size
/// maximum output size for SHA512 is 64 bytes
static constexpr size_t ssize() {return 64;}
};
// AEAD function defines
/**
* AES256GCM buffers size defines
*/
struct AES256GCM {
static constexpr size_t keySize(void) {return 32;}; // key size is 256 bits
static constexpr size_t tagSize(void) {return 16;}; // authentication tag size is 128 bits
/// key size is 32 bytes
static constexpr size_t keySize(void) {return 32;};
/// we use authentication tag size of 16 bytes
static constexpr size_t tagSize(void) {return 16;};
};
}
......
......@@ -26,8 +26,8 @@
namespace lime {
/* A pure abstract class, implementation used is set by curveId parameter given to insert/load_limeUser function */
/* NOTE: never instanciate directly a Lime object, always use the Lime Factory function as Lime object MUST be held by a shared pointer */
/** A pure abstract class, implementation used is set by curveId parameter given to insert/load_limeUser function
* @note: never instanciate directly a Lime object, always use the Lime Factory function as Lime object MUST be held by a shared pointer */
class LimeGeneric {
public:
......@@ -53,7 +53,7 @@ namespace lime {
* Note: all parameters are shared pointers as the process being asynchronous, the ownership will be taken internally exempting caller to manage the buffers.
*
* @param[in] recipientUserId the Id of intended recipient, shall be a sip:uri of user or conference, is used as associated data to ensure no-one can mess with intended recipient
* @param[in/out] recipients a list of recipientData holding: the recipient device Id(GRUU) and an empty buffer to store the cipherHeader which must then be routed to that recipient
* @param[in,out] recipients a list of recipientData holding: the recipient device Id(GRUU) and an empty buffer to store the cipherHeader which must then be routed to that recipient
* @param[in] plainMessage a buffer holding the message to encrypt, can be text or data.
* @param[in] encryptionPolicy select how to manage the encryption: direct use of Double Ratchet message or encrypt in the cipher message and use the DR message to share the cipher message key
* @param[out] cipherMessage points to the buffer to store the encrypted message which must be routed to all recipients
......
......@@ -41,7 +41,7 @@ namespace lime {
*
* @param[in] filename The path to DB file
*/
Db::Db(string filename) : sql{sqlite3, filename}{
Db::Db(std::string filename) : sql{sqlite3, filename}{
constexpr int db_module_table_not_holding_lime_row = -1;
int userVersion=db_module_table_not_holding_lime_row;
......
......@@ -24,6 +24,10 @@
namespace lime {
/**
* Database access class
* relies on SOCI
*/
class Db {
public:
// soci connexion to DB
......
......@@ -437,7 +437,7 @@ namespace lime {
/**
* @brief Clean user data in case of problem or when we're done, it also process the asynchronous encryption queue
*
* @param[in/out] userData the structure holding the data structure captured by the process response lambda
* @param[in,out] userData the structure holding the data structure captured by the process response lambda
*/
template <typename Curve>
void Lime<Curve>::cleanUserData(std::shared_ptr<callbackUserData<Curve>> userData) {
......
......@@ -24,24 +24,20 @@
namespace lime {
/**
* Holds everything found in a key bundle received from X3DH server
*/
template <typename Curve>
struct X3DH_peerBundle {
std::string deviceId;
DSA<Curve, lime::DSAtype::publicKey> Ik;
X<Curve, lime::Xtype::publicKey> SPk;
uint32_t SPk_id;
DSA<Curve, lime::DSAtype::signature> SPk_sig;
bool haveOPk;
X<Curve, lime::Xtype::publicKey> OPk;
uint32_t OPk_id;
// use uint8_t * constructor for all keys/signatures
X3DH_peerBundle(std::string &&deviceId, const uint8_t *Ik, const uint8_t *SPk, uint32_t SPk_id, const uint8_t *SPk_sig) :
deviceId{deviceId}, Ik{Ik}, SPk{SPk}, SPk_id{SPk_id}, SPk_sig{SPk_sig}, haveOPk{false}, OPk{}, OPk_id{0} {};
X3DH_peerBundle(std::string &&deviceId, const uint8_t *Ik, const uint8_t *SPk, uint32_t SPk_id, const uint8_t *SPk_sig, const uint8_t *OPk, uint32_t OPk_id) :
deviceId{deviceId}, Ik{Ik}, SPk{SPk}, SPk_id{SPk_id}, SPk_sig{SPk_sig}, haveOPk{true}, OPk{OPk}, OPk_id{OPk_id} {};
std::string deviceId; /**< peer device Id */
DSA<Curve, lime::DSAtype::publicKey> Ik; /**< peer device public identity key */
X<Curve, lime::Xtype::publicKey> SPk; /**< peer device current public pre-signed key */
uint32_t SPk_id; /**< id of the peer device current public pre-signed key */
DSA<Curve, lime::DSAtype::signature> SPk_sig; /**< signature of the peer device current public pre-signed key */
bool haveOPk; /**< flag: is this bundle hold a One Time preKey */
X<Curve, lime::Xtype::publicKey> OPk; /**< peer device One Time preKey */
uint32_t OPk_id; /**< id of the peer device current public pre-signed key */