Commit 6067f91d authored by Johan Pascal's avatar Johan Pascal

Encrypted payload can be in DR message

Select encryption policy:
- force the payload to be encrypted in Double ratchet message
- force the patload to be encrypted in a separate cipher Message (was the only policy till now)
- optimize output size: select best policy based on message size and recipient number(default policy)

Todo: get the policy selection API available at lime manager level
parent c86e40b9
......@@ -30,6 +30,13 @@ namespace lime {
* 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
*/
enum class EncryptionPolicy {DRMessage, cipherMessage, optimizeSize};
/* 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*/
struct recipientData {
std::string deviceId; // recipient deviceId (shall be GRUU)
......
This diff is collapsed.
......@@ -103,8 +103,8 @@ namespace lime {
DR<Curve> &operator=(DR<Curve> &a) = delete; // can't copy a session
~DR();
void ratchetEncrypt(const lime::sVector &plaintext, std::vector<uint8_t> &&AD, std::vector<uint8_t> &ciphertext);
bool ratchetDecrypt(const std::vector<uint8_t> &cipherText, const std::vector<uint8_t> &AD, lime::sVector &plaintext);
void ratchetEncrypt(const std::vector<uint8_t> &plaintext, std::vector<uint8_t> &&AD, std::vector<uint8_t> &ciphertext, const bool payloadDirectEncryption);
bool ratchetDecrypt(const std::vector<uint8_t> &cipherText, const std::vector<uint8_t> &AD, std::vector<uint8_t> &plaintext, const bool payloadDirectEncryption);
long int dbSessionId(void) const {return m_dbSessionId;}; // retrieve the session's local storage id
bool isActive(void) const {return m_active_status;} // return the current status of session
};
......@@ -133,9 +133,11 @@ namespace lime {
* @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[in] sourceDeviceId the Id of sender device(gruu)
* @param[out] cipherMessage message encrypted with a random generated key(and IV)
* @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
* default is optimized output size mode.
*/
template <typename Curve>
void encryptMessage(std::vector<recipientInfos<Curve>>& recipients, const std::vector<uint8_t>& plaintext, const std::string& recipientUserId, const std::string& sourceDeviceId, std::vector<uint8_t>& cipherMessage);
void encryptMessage(std::vector<recipientInfos<Curve>>& recipients, const std::vector<uint8_t>& plaintext, const std::string& recipientUserId, const std::string& sourceDeviceId, std::vector<uint8_t>& cipherMessage, const lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeSize);
/**
* @brief Decrypt a message
......@@ -170,12 +172,12 @@ namespace lime {
/* this templates are instanciated once in the lime_double_ratchet.cpp file, explicitly tell anyone including this header that there is no need to re-instanciate them */
#ifdef EC25519_ENABLED
extern template class DR<C255>;
extern template void encryptMessage<C255>(std::vector<recipientInfos<C255>>& recipients, const std::vector<uint8_t>& plaintext, const std::string& recipientUserId, const std::string& sourceDeviceId, std::vector<uint8_t>& cipherMessage);
extern template void encryptMessage<C255>(std::vector<recipientInfos<C255>>& recipients, const std::vector<uint8_t>& plaintext, const std::string& recipientUserId, const std::string& sourceDeviceId, std::vector<uint8_t>& cipherMessage, const lime::EncryptionPolicy encryptionPolicy);
extern template std::shared_ptr<DR<C255>> decryptMessage<C255>(const std::string& sourceDeviceId, const std::string& recipientDeviceId, const std::string& recipientUserId, std::vector<std::shared_ptr<DR<C255>>>& DRSessions, const std::vector<uint8_t>& cipherHeader, const std::vector<uint8_t>& cipherMessage, std::vector<uint8_t>& plaintext);
#endif
#ifdef EC448_ENABLED
extern template class DR<C448>;
extern template void encryptMessage<C448>(std::vector<recipientInfos<C448>>& recipients, const std::vector<uint8_t>& plaintext, const std::string& recipientUserId, const std::string& sourceDeviceId, std::vector<uint8_t>& cipherMessage);
extern template void encryptMessage<C448>(std::vector<recipientInfos<C448>>& recipients, const std::vector<uint8_t>& plaintext, const std::string& recipientUserId, const std::string& sourceDeviceId, std::vector<uint8_t>& cipherMessage, const lime::EncryptionPolicy encryptionPolicy);
extern template std::shared_ptr<DR<C448>> decryptMessage<C448>(const std::string& sourceDeviceId, const std::string& recipientDeviceId, const std::string& recipientUserId, std::vector<std::shared_ptr<DR<C448>>>& DRSessions, const std::vector<uint8_t>& cipherHeader, const std::vector<uint8_t>& cipherMessage, std::vector<uint8_t>& plaintext);
#endif
......
......@@ -179,18 +179,23 @@ namespace lime {
* @brief Build a header string from needed info
* header is: Protocol Version Number<1 byte> || Message Type <1 byte> || curveId <1 byte> || [X3DH Init message <variable>] || Ns<2 bytes> || PN<2 bytes> || DHs<...>
*
* @param[out] header output buffer
* @param[in] Ns Index of sending chain
* @param[in] PN Index of previous sending chain
* @param[in] DHs Current DH public key
* @param[in] X3DH_initMessage A buffer holding an X3DH init message to be inserted in header. If empty message type X3DH init flag is not set
* @param[out] header the buffer containing header to be sent to recipient
* @param[in] Ns Index of sending chain
* @param[in] PN Index of previous sending chain
* @param[in] DHs Current DH public key
* @param[in] X3DH_initMessage A buffer holding an X3DH init message to be inserted in header. If empty message type X3DH init flag is not set
* @param[in] payloadDirectEncryption Set the Payload Direct Encryption flag in header
*/
template <typename Curve>
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 {
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, const bool payloadDirectEncryption) noexcept {
// Header is one buffer composed of:
// Version Number<1 byte> || message 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));
uint8_t messageType = 0;
if (payloadDirectEncryption) { // if requested, turn the payload direct encryption flag on
messageType |= static_cast<uint8_t>(lime::double_ratchet_protocol::DR_message_type::payload_direct_encryption_flag); // turn on the flag
}
if (X3DH_initMessage.size()>0) { // we do have an X3DH init message to insert in the header
messageType |= static_cast<uint8_t>(lime::double_ratchet_protocol::DR_message_type::X3DH_init_flag); // turn on the flag
header.push_back(messageType);
......@@ -284,7 +289,7 @@ namespace lime {
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, lime::Xtype::publicKey> &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, const bool payloadDirectEncryption) noexcept;
template class DRHeader<C255>;
#endif
......@@ -292,7 +297,7 @@ namespace lime {
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, lime::Xtype::publicKey> &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, const bool payloadDirectEncryption) noexcept;
template class DRHeader<C448>;
#endif
......
......@@ -71,14 +71,15 @@ namespace lime {
* @brief Build a header string from needed info
* header is: Protocol Version Number<1 byte> || Message Type <1 byte> || curveId <1 byte> || [X3DH Init message <variable>] || Ns<4 bytes> || PN<4 bytes> || DHs<...>
*
* @param[out] header the buffer containing header to be sent to recipient
* @param[in] Ns Index of sending chain
* @param[in] PN Index of previous sending chain
* @param[in] DHs Current DH public key
* @param[in] X3DH_initMessage A buffer holding an X3DH init message to be inserted in header. If empty message type X3DH init flag is not set
* @param[out] header the buffer containing header to be sent to recipient
* @param[in] Ns Index of sending chain
* @param[in] PN Index of previous sending chain
* @param[in] DHs Current DH public key
* @param[in] X3DH_initMessage A buffer holding an X3DH init message to be inserted in header. If empty message type X3DH init flag is not set
* @param[in] payloadDirectEncryption Set the Payload Direct Encryption flag in header
*/
template <typename Curve>
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;
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, const bool payloadDirectEncryption) noexcept;
/**
* DR message header: helper class and functions to parse message header and access its components
......@@ -113,7 +114,7 @@ namespace lime {
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, lime::Xtype::publicKey> &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, const bool payloadDirectEncryption) noexcept;
extern template class DRHeader<C255>;
#endif
......@@ -121,7 +122,7 @@ namespace lime {
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, lime::Xtype::publicKey> &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, const bool payloadDirectEncryption) noexcept;
extern template class DRHeader<C448>;
#endif
/* These constants are needed only for tests purpose, otherwise their usage is internal only to double_ratchet_protocol.hpp */
......
......@@ -247,6 +247,15 @@ void dr_devicesInit(std::string dbBaseFilename, std::vector<std::vector<std::vec
}
}
bool DR_message_payloadDirectEncrypt(std::vector<uint8_t> &message) {
// checks on length to at least perform more checks
if (message.size()<4) return false;
//
// check protocol version
if (message[0] != static_cast<uint8_t>(lime::double_ratchet_protocol::DR_v01)) return false;
return (message[1]&static_cast<uint8_t>(lime::double_ratchet_protocol::DR_message_type::payload_direct_encryption_flag));
}
bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message) {
bool dummy;
......@@ -261,27 +270,48 @@ bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message, bool &haveOPk) {
if (message[0] != static_cast<uint8_t>(lime::double_ratchet_protocol::DR_v01)) return false;
// check message type: we must have a X3DH init message
if (!(message[1]&static_cast<uint8_t>(lime::double_ratchet_protocol::DR_message_type::X3DH_init_flag))) return false;
// check packet length, packet is :
// header<3 bytes>, X3DH init packet, Ns+PN<4 bytes>, DHs<X<Curve>::keyLength>, Cipher message RandomSeed<32 bytes>, key auth tag<16 bytes> = <55 + X<Curve>::keyLengh + X3DH init size>
bool payload_direct_encryption = (message[1]&static_cast<uint8_t>(lime::double_ratchet_protocol::DR_message_type::payload_direct_encryption_flag));
/* check message length :
* message with payload not included (DR payload is a fixed 32 byte random seed)
* - header<3 bytes>, X3DH init packet, Ns+PN<4 bytes>, DHs<X<Curve>::keyLength>, Cipher message RandomSeed<32 bytes>, key auth tag<16 bytes> = <55 + X<Curve>::keyLengh + X3DH init size>
* message with payload included
* - header<3 bytes>, X3DH init packet, Ns+PN<4 bytes>, DHs<X<Curve>::keyLength>, Payload<variable size>, key auth tag<16 bytes> = <23 + X<Curve>::keyLengh + X3DH init size>
*/
// X3DH init size = OPk_flag<1 byte> + selfIK<DSA<Curve>::keyLength> + EK<X<Curve>::keyLenght> + SPk id<4 bytes> + OPk id (if flag is 1)<4 bytes>
switch (message[2]) {
case static_cast<uint8_t>(lime::CurveId::c25519):
if (message[3] == 0x00) { // no OPk in the X3DH init message
if (message.size() != (55 + X<C255, lime::Xtype::publicKey>::ssize() + 5 + DSA<C255, lime::DSAtype::publicKey>::ssize() + X<C255, lime::Xtype::publicKey>::ssize())) return false;
if (payload_direct_encryption) {
if (message.size() <= (23 + X<C255, lime::Xtype::publicKey>::ssize() + 5 + DSA<C255, lime::DSAtype::publicKey>::ssize() + X<C255, lime::Xtype::publicKey>::ssize())) return false;
} else {
if (message.size() != (55 + X<C255, lime::Xtype::publicKey>::ssize() + 5 + DSA<C255, lime::DSAtype::publicKey>::ssize() + X<C255, lime::Xtype::publicKey>::ssize())) return false;
}
haveOPk=false;
} else { // OPk present in the X3DH init message
if (message.size() != (55 + X<C255, lime::Xtype::publicKey>::ssize() + 9 + DSA<C255, lime::DSAtype::publicKey>::ssize() + X<C255, lime::Xtype::publicKey>::ssize())) return false;
if (payload_direct_encryption) {
if (message.size() <= (23 + X<C255, lime::Xtype::publicKey>::ssize() + 9 + DSA<C255, lime::DSAtype::publicKey>::ssize() + X<C255, lime::Xtype::publicKey>::ssize())) return false;
} else {
if (message.size() != (55 + X<C255, lime::Xtype::publicKey>::ssize() + 9 + DSA<C255, lime::DSAtype::publicKey>::ssize() + X<C255, lime::Xtype::publicKey>::ssize())) return false;
}
haveOPk=true;
}
return true;
break;
case static_cast<uint8_t>(lime::CurveId::c448):
if (message[3] == 0x00) { // no OPk in the X3DH init message
if (message.size() != (55 + X<C448, lime::Xtype::publicKey>::ssize() + 5 + DSA<C448, lime::DSAtype::publicKey>::ssize() + X<C448, lime::Xtype::publicKey>::ssize())) return false;
if (payload_direct_encryption) {
if (message.size() <= (23 + X<C448, lime::Xtype::publicKey>::ssize() + 5 + DSA<C448, lime::DSAtype::publicKey>::ssize() + X<C448, lime::Xtype::publicKey>::ssize())) return false;
} else {
if (message.size() != (55 + X<C448, lime::Xtype::publicKey>::ssize() + 5 + DSA<C448, lime::DSAtype::publicKey>::ssize() + X<C448, lime::Xtype::publicKey>::ssize())) return false;
}
haveOPk=false;
} else { // OPk present in the X3DH init message
if (message.size() != (55 + X<C448, lime::Xtype::publicKey>::ssize() + 9 + DSA<C448, lime::DSAtype::publicKey>::ssize() + X<C448, lime::Xtype::publicKey>::ssize())) return false;
if (payload_direct_encryption) {
if (message.size() <= (23 + X<C448, lime::Xtype::publicKey>::ssize() + 9 + DSA<C448, lime::DSAtype::publicKey>::ssize() + X<C448, lime::Xtype::publicKey>::ssize())) return false;
} else {
if (message.size() != (55 + X<C448, lime::Xtype::publicKey>::ssize() + 9 + DSA<C448, lime::DSAtype::publicKey>::ssize() + X<C448, lime::Xtype::publicKey>::ssize())) return false;
}
haveOPk=true;
}
return true;
......
......@@ -76,6 +76,8 @@ struct sessionDetails {
template <typename Curve>
void dr_devicesInit(std::string dbBaseFilename, std::vector<std::vector<std::vector<std::vector<sessionDetails<Curve>>>>> &users, std::vector<std::string> &usernames, std::vector<std::string> &createdDBfiles, std::shared_ptr<RNG> RNG_context);
/* return true if the message buffer is a DR message wiht the paylod direct encryption flag set */
bool DR_message_payloadDirectEncrypt(std::vector<uint8_t> &message);
/* return true if the message buffer is a valid DR message holding a X3DH init one in its header */
bool DR_message_holdsX3DHInit(std::vector<uint8_t> &message);
/* this version will set the OPk status in the given bool if a packet is found */
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment