Commit 1e047a13 authored by Johan Pascal's avatar Johan Pascal

Add optimizeGlobalBandwidth encryption policy

+ speed up encryption policy test
parent 42c08101
......@@ -38,7 +38,8 @@ namespace lime {
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 */
optimizeUploadSize, /**< optimize upload size: encrypt in DR message if plaintext is short enougth to beat the overhead introduced by cipher message scheme, otherwise use cipher message. Selection is made on upload size only. This is the default policy used */
optimizeGlobalBandwidth /**< optimize bandwith usage: encrypt in DR message if plaintext is short enougth to beat the overhead introduced by cipher message scheme, otherwise use cipher message. Selection is made on uploadand download(from server to recipients) sizes added. */
};
/** 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*/
......@@ -168,7 +169,7 @@ namespace lime {
* @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.
*/
void encrypt(const std::string &localDeviceId, 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, const limeCallback &callback, lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeSize);
void encrypt(const std::string &localDeviceId, 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, const limeCallback &callback, lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeUploadSize);
/**
* @brief Decrypt the given message
......
......@@ -416,11 +416,28 @@ namespace lime {
payloadDirectEncryption = false;
break;
case lime::EncryptionPolicy::optimizeSize:
default: // to make compiler happy but it shal not be necessary
// Default encryption policy : go for the optimal output size. All other parts being equal, size of output data is
case lime::EncryptionPolicy::optimizeGlobalBandwidth:
// optimize the global bandwith consumption: upload size to server + donwload size from server to recipient
// server is considered to act cleverly and select the DR message to be send to server not just forward everything to the recipient for them to sort out which is their part
// - DR message policy: up and down size are recipient number * plaintext size
// - cipher message policy : up is <plaintext size + authentication tag size>(cipher message size) + recipient number * random seed size
// down is recipient number * (random seed size + <plaintext size + authentication tag size>(the cipher message))
// Note: We are not taking in consideration the fact that being multipart, the message gets an extra multipart boundary when using cipher message mode
if ( 2*recipients.size()*plaintext.size() <=
(plaintext.size() + lime::settings::DRMessageAuthTagSize + (2*lime::settings::DRrandomSeedSize + plaintext.size() + lime::settings::DRMessageAuthTagSize)*recipients.size()) ) {
payloadDirectEncryption = true;
} else {
payloadDirectEncryption = false;
}
break;
break;
case lime::EncryptionPolicy::optimizeUploadSize:
default: // to make compiler happy but it shall not be necessary
// Default encryption policy : go for the optimal upload size. All other parts being equal, size of output data is
// - DR message policy: recipients number * plaintext size (plaintext is present encrypted in each recipient message)
// - cipher message policy: plaintext size + authentication tag size (the cipher message) + recipients number * random seed size (each DR message holds the random seed as encrypted data)
// Note: We are not taking in consideration the fact that being multipart, the message gets an extra multipart boundary when using cipher message mode
if ( recipients.size()*plaintext.size() <= (plaintext.size() + lime::settings::DRMessageAuthTagSize + (lime::settings::DRrandomSeedSize*recipients.size())) ) {
payloadDirectEncryption = true;
} else {
......
......@@ -168,14 +168,14 @@ namespace lime {
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) {};
encryptionPolicy(lime::EncryptionPolicy::optimizeUploadSize), OPkServerLowLimit(0), OPkBatchSize(OPkInitialBatchSize) {};
/** 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} {};
encryptionPolicy(lime::EncryptionPolicy::optimizeUploadSize), OPkServerLowLimit{OPkServerLowLimit}, OPkBatchSize{OPkBatchSize} {};
/** created at encrypt(getPeerBundle)
*/
......
......@@ -41,8 +41,13 @@ int wait_for_timeout=4000;
// default value for initial OPk batch size, keep it small so not too many OPks generated
uint16_t OPkInitialBatchSize=3;
// messages with calibrated length to test the optimize encryption policies
// with a short one, any optimize policy shall go for the DRmessage encryption
std::string shortMessage{"Short Message"};
std::string longMessage{"This message is long enough to automatically switch to cipher Message mode when at least two recipients are involved. This message is long enough to automatically switch to cipher Message mode when at least two recipients are involved."};
// with a long one(>80 <176) optimizeUploadSzie policy shall go for the cipherMessage encryption, but the optimizeGlobalBandwith stick to DRmessage (with 2 recipients)
std::string longMessage{"This message is long enough to automatically switch to cipher Message mode when at least two recipients are involved."};
// with a very long one(>176) all optimize policies shall go for the cipherMessage encryption(with 2 recipients)
std::string veryLongMessage{"This message is long enough to automatically switch to cipher Message mode when at least two recipients are involved. This message is long enough to automatically switch to cipher Message mode when at least two recipients are involved."};
std::vector<std::string> messages_pattern = {
{"Frankly, my dear, I don't give a damn."},
......
......@@ -34,6 +34,7 @@ namespace lime_tester {
extern std::string shortMessage;
extern std::string longMessage;
extern std::string veryLongMessage;
extern std::vector<std::string> messages_pattern;
......
......@@ -89,7 +89,7 @@ static void dr_skippedMessages_basic_test(const uint8_t period=1, const uint8_t
recipients[i].emplace_back("bob",alice);
std::vector<uint8_t> plaintext{lime_tester::messages_pattern[i].begin(), lime_tester::messages_pattern[i].end()};
std::vector<uint8_t> cipherMessage{};
encryptMessage(recipients[i], plaintext, "bob", "alice", cipher[i], lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients[i], plaintext, "bob", "alice", cipher[i], lime::EncryptionPolicy::optimizeUploadSize);
bctbx_debug("alice encrypt %d", int(i));
messageSender[i] = 1;
......@@ -101,7 +101,7 @@ static void dr_skippedMessages_basic_test(const uint8_t period=1, const uint8_t
recipients[i].emplace_back("alice",bob);
std::vector<uint8_t> plaintext{lime_tester::messages_pattern[i].begin(), lime_tester::messages_pattern[i].end()};
std::vector<uint8_t> cipherMessage{};
encryptMessage(recipients[i], plaintext, "alice", "bob", cipher[i], lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients[i], plaintext, "alice", "bob", cipher[i], lime::EncryptionPolicy::optimizeUploadSize);
bctbx_debug("bob encrypt %d", int(i));
messageSender[i] = 2;
......@@ -237,7 +237,7 @@ static void dr_long_exchange_test(uint8_t period=1, std::string db_filename="dr_
recipients.emplace_back("bob",alice);
std::vector<uint8_t> plaintext{lime_tester::messages_pattern[i].begin(), lime_tester::messages_pattern[i].end()};
std::vector<uint8_t> cipherMessage{};
encryptMessage(recipients, plaintext, "bob", "alice", cipherMessage, lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients, plaintext, "bob", "alice", cipherMessage, lime::EncryptionPolicy::optimizeUploadSize);
// bob decrypt it
std::vector<shared_ptr<DR<Curve>>> recipientDRSessions{};
......@@ -261,7 +261,7 @@ static void dr_long_exchange_test(uint8_t period=1, std::string db_filename="dr_
recipients.emplace_back("alice",bob);
std::vector<uint8_t> plaintext{lime_tester::messages_pattern[i].begin(), lime_tester::messages_pattern[i].end()};
std::vector<uint8_t> cipherMessage{};
encryptMessage(recipients, plaintext, "alice", "bob", cipherMessage, lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients, plaintext, "alice", "bob", cipherMessage, lime::EncryptionPolicy::optimizeUploadSize);
// alice decrypt it
std::vector<shared_ptr<DR<Curve>>> recipientDRSessions{};
......@@ -401,7 +401,7 @@ static void dr_simple_exchange(std::shared_ptr<DR<Curve>> &DRsessionAlice, std::
lime_tester::messages_pattern[0], lime_tester::messages_pattern[1], // default: use messages_pattern 0 and 1
false, // do not check
lime::EncryptionPolicy::DRMessage, lime::EncryptionPolicy::DRMessage, //useless as we are not checking anything
lime::EncryptionPolicy::optimizeSize, lime::EncryptionPolicy::optimizeSize); // set to default
lime::EncryptionPolicy::optimizeUploadSize, lime::EncryptionPolicy::optimizeUploadSize); // set to default
}
/* alice send a message to bob, and he replies */
......@@ -520,7 +520,7 @@ static void dr_multidevice_basic_test(std::string db_filename) {
dr_multidevice_exchange<Curve>(db_filename,
lime_tester::messages_pattern[0],
false, // do not check
lime::EncryptionPolicy::optimizeSize, lime::EncryptionPolicy::optimizeSize); // default setting
lime::EncryptionPolicy::optimizeUploadSize, lime::EncryptionPolicy::optimizeUploadSize); // default setting
}
static void dr_multidevice_basic(void) {
#ifdef EC25519_ENABLED
......@@ -556,7 +556,7 @@ static void dr_skip_too_much_test(std::string db_filename) {
std::vector<uint8_t> plaintextAlice{lime_tester::messages_pattern[1].begin(), lime_tester::messages_pattern[1].end()};
for (auto i=0; i<lime::settings::maxMessageSkip+2; i++) { // we can skip maxMessageSkip, so encrypt +2 and we will skip +1
// alice encrypt a message, just discard it, it's not the point to decrypt it
encryptMessage(recipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeUploadSize);
}
// now decrypt the last encrypted message, it shall fail: too much skiped messages
......@@ -581,7 +581,7 @@ static void dr_skip_too_much_test(std::string db_filename) {
recipients.clear();
recipients.emplace_back("bob",alice);
plaintextAlice.assign(lime_tester::messages_pattern[1].begin(), lime_tester::messages_pattern[1].end());
encryptMessage(recipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeUploadSize);
// bob decrypt it - Bob perform a DH Ratchet and than have receiving chain n, sending chain n+1
recipientDRSessions.clear();
......@@ -598,7 +598,7 @@ static void dr_skip_too_much_test(std::string db_filename) {
recipients.clear();
recipients.emplace_back("alice",bob);
std::vector<uint8_t> plaintextBob{lime_tester::messages_pattern[2].begin(), lime_tester::messages_pattern[2].end()};
encryptMessage(recipients, plaintextBob, "alice", "bob", bobCipher, lime::EncryptionPolicy::optimizeSize);
encryptMessage(recipients, plaintextBob, "alice", "bob", bobCipher, lime::EncryptionPolicy::optimizeUploadSize);
// alice did not get bob reply, and encrypt maxMessageSkip/2 messages, with sending chain n (receiving chain is still n too))
aliceCipher.clear();
......@@ -607,7 +607,7 @@ static void dr_skip_too_much_test(std::string db_filename) {
plaintextAlice.assign(lime_tester::messages_pattern[2].begin(), lime_tester::messages_pattern[2].end());
for (auto i=0; i<lime::settings::maxMessageSkip/2; i++) {
// alice encrypt a message, just discard it, it's not the point to decrypt it
encryptMessage(lostRecipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeSize);
encryptMessage(lostRecipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeUploadSize);
}
// alice now decrypt bob's message performing a DH ratchet, after that she has sending chain n+1, receiving chain n+1
......@@ -627,7 +627,7 @@ static void dr_skip_too_much_test(std::string db_filename) {
plaintextAlice.assign(lime_tester::messages_pattern[2].begin(), lime_tester::messages_pattern[2].end());
for (auto i=0; i<lime::settings::maxMessageSkip/2+3; i++) {
// alice encrypt a message, just discard it, it's not the point to decrypt it
encryptMessage(lostRecipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeSize);
encryptMessage(lostRecipients, plaintextAlice, "bob", "alice", aliceCipher, lime::EncryptionPolicy::optimizeUploadSize);
}
// now decrypt the last encrypted message, it shall fail: bob is on receiving chain n and missed maxMessageSkip/2 on it + maxMessageSkip/2+3 in receiving chain n+1
......@@ -669,13 +669,13 @@ static void dr_encryptionPolicy_basic_test(std::string db_filename) {
dr_simple_exchange(alice, bob, localStorageAlice, localStorageBob, aliceFilename, bobFilename, lime_tester::shortMessage, lime_tester::shortMessage,
true,
lime::EncryptionPolicy::DRMessage, lime::EncryptionPolicy::DRMessage, // we expect direct message encryption when we have only one recipient
lime::EncryptionPolicy::optimizeSize, lime::EncryptionPolicy::optimizeSize); // and force optimizeSize
lime::EncryptionPolicy::optimizeUploadSize, lime::EncryptionPolicy::optimizeUploadSize); // and force optimizeSize
/* long message, force optimizeSize policy -> direct encryption(we have only one recipient)*/
dr_simple_exchange(alice, bob, localStorageAlice, localStorageBob, aliceFilename, bobFilename, lime_tester::longMessage, lime_tester::longMessage,
true,
lime::EncryptionPolicy::DRMessage, lime::EncryptionPolicy::DRMessage, // we expect direct message encryption as we have only one recipient even if the message is long
lime::EncryptionPolicy::optimizeSize, lime::EncryptionPolicy::optimizeSize); // and force optimizeSize
lime::EncryptionPolicy::optimizeUploadSize, lime::EncryptionPolicy::optimizeUploadSize); // and force optimizeSize
/* short message, force cipher Message policy -> cipher Message encryption */
dr_simple_exchange(alice, bob, localStorageAlice, localStorageBob, aliceFilename, bobFilename, lime_tester::shortMessage, lime_tester::shortMessage,
......@@ -724,14 +724,14 @@ static void dr_encryptionPolicy_multidevice_test(std::string db_filename) {
lime_tester::shortMessage,
true,
lime::EncryptionPolicy::DRMessage, // check we have direct encryotion
lime::EncryptionPolicy::optimizeSize); // do nothing about payload encryption policy: use default
lime::EncryptionPolicy::optimizeUploadSize); // do nothing about payload encryption policy: use default
/* long message, forced optimizeSize policy(which shall be the default anyway) -> cipher message encryption(we have more thant one recipient) */
dr_multidevice_exchange<Curve>(db_filename,
lime_tester::longMessage,
true,
lime::EncryptionPolicy::cipherMessage,// check we have cipher message encryption
lime::EncryptionPolicy::optimizeSize); // do nothing about payload encryption policy: use default
lime::EncryptionPolicy::optimizeUploadSize); // do nothing about payload encryption policy: use default
/* short message, forced DRMessage policy -> direct encryption(even if we have more thant one recipient) */
dr_multidevice_exchange<Curve>(db_filename,
......
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