diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.h +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.h @@ -48,6 +48,7 @@ void initializeOutboundForSendingSession( const std::string &targetUserId, const OlmBuffer &idKeys, + const OlmBuffer &preKeys, const OlmBuffer &oneTimeKeys, size_t keyIndex = 0); bool hasSessionFor(const std::string &targetUserId); diff --git a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp --- a/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp +++ b/native/cpp/CommonCpp/CryptoTools/CryptoModule.cpp @@ -137,6 +137,7 @@ void CryptoModule::initializeOutboundForSendingSession( const std::string &targetUserId, const OlmBuffer &idKeys, + const OlmBuffer &preKeys, const OlmBuffer &oneTimeKeys, size_t keyIndex) { if (this->hasSessionFor(targetUserId)) { @@ -148,6 +149,7 @@ this->account, this->keys.identityKeys.data(), idKeys, + preKeys, oneTimeKeys, keyIndex); this->sessions.insert(make_pair(targetUserId, std::move(newSession))); diff --git a/native/cpp/CommonCpp/CryptoTools/Session.h b/native/cpp/CommonCpp/CryptoTools/Session.h --- a/native/cpp/CommonCpp/CryptoTools/Session.h +++ b/native/cpp/CommonCpp/CryptoTools/Session.h @@ -24,6 +24,7 @@ OlmAccount *account, std::uint8_t *ownerIdentityKeys, const OlmBuffer &idKeys, + const OlmBuffer &preKeys, const OlmBuffer &oneTimeKeys, size_t keyIndex = 0); static std::unique_ptr createSessionAsResponder( diff --git a/native/cpp/CommonCpp/CryptoTools/Session.cpp b/native/cpp/CommonCpp/CryptoTools/Session.cpp --- a/native/cpp/CommonCpp/CryptoTools/Session.cpp +++ b/native/cpp/CommonCpp/CryptoTools/Session.cpp @@ -10,6 +10,7 @@ OlmAccount *account, std::uint8_t *ownerIdentityKeys, const OlmBuffer &idKeys, + const OlmBuffer &preKeys, const OlmBuffer &oneTimeKeys, size_t keyIndex) { std::unique_ptr session(new Session(account, ownerIdentityKeys)); @@ -28,6 +29,8 @@ session->ownerUserAccount, idKeys.data() + ID_KEYS_PREFIX_OFFSET, KEYSIZE, + preKeys.data() + PRE_KEY_PREFIX_OFFSET, + KEYSIZE, oneTimeKeys.data() + ONE_TIME_KEYS_PREFIX_OFFSET + (KEYSIZE + ONE_TIME_KEYS_MIDDLE_OFFSET) * keyIndex, KEYSIZE, diff --git a/native/cpp/CommonCpp/CryptoTools/Tools.h b/native/cpp/CommonCpp/CryptoTools/Tools.h --- a/native/cpp/CommonCpp/CryptoTools/Tools.h +++ b/native/cpp/CommonCpp/CryptoTools/Tools.h @@ -8,6 +8,7 @@ #define KEYSIZE 43 #define ID_KEYS_PREFIX_OFFSET 15 +#define PRE_KEY_PREFIX_OFFSET 25 #define ONE_TIME_KEYS_PREFIX_OFFSET 25 #define ONE_TIME_KEYS_MIDDLE_OFFSET 12 diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj --- a/native/ios/Comm.xcodeproj/project.pbxproj +++ b/native/ios/Comm.xcodeproj/project.pbxproj @@ -13,7 +13,6 @@ 1F537ACC7B60DC049C0ECFA7 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */; }; 71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; }; 711B408425DA97F9005F8F06 /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F26E81B24440D87004049C6 /* dummy.swift */; }; - 713EE41126C66B80003D7C48 /* CryptoTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 713EE41026C66B80003D7C48 /* CryptoTest.mm */; }; 71762A75270D8AAE00F565ED /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; }; 718DE99E2653D41C00365824 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; }; 71BE844A2636A944002849D2 /* CommCoreModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BE843C2636A944002849D2 /* CommCoreModule.cpp */; }; @@ -117,7 +116,6 @@ 711CF80E25DC096000A00FBD /* libFolly.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libFolly.a; sourceTree = BUILT_PRODUCTS_DIR; }; 713EE40626C6676B003D7C48 /* CommTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CommTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 713EE40A26C6676B003D7C48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 713EE41026C66B80003D7C48 /* CryptoTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CryptoTest.mm; sourceTree = ""; }; 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformSpecificTools.mm; path = Comm/PlatformSpecificTools.mm; sourceTree = ""; }; 718DE99C2653D41C00365824 /* WorkerThread.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WorkerThread.cpp; sourceTree = ""; }; 718DE99D2653D41C00365824 /* WorkerThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WorkerThread.h; sourceTree = ""; }; @@ -303,7 +301,6 @@ 713EE40726C6676B003D7C48 /* CommTests */ = { isa = PBXGroup; children = ( - 713EE41026C66B80003D7C48 /* CryptoTest.mm */, 713EE40A26C6676B003D7C48 /* Info.plist */, ); path = CommTests; @@ -1000,7 +997,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 713EE41126C66B80003D7C48 /* CryptoTest.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/native/ios/CommTests/CryptoTest.mm b/native/ios/CommTests/CryptoTest.mm deleted file mode 100644 --- a/native/ios/CommTests/CryptoTest.mm +++ /dev/null @@ -1,314 +0,0 @@ -#import "../../cpp/CommonCpp/CryptoTools/CryptoModule.h" -#import "../../cpp/CommonCpp/CryptoTools/Tools.h" -#import "../../cpp/CommonCpp/Tools/Logger.h" -#import - -#import - -#import - -using namespace comm::crypto; - -@interface CryptoTest : XCTestCase - -@end - -@implementation CryptoTest - -struct ModuleWithKeys { - std::shared_ptr module; - Keys keys; -}; - -enum class RepickleOption { - NONE = 0, - SENDER = 1, - RECEIVER = 2, - BOTH = 3, -}; - -size_t currentId = 1000; - -- (void)setUp { - // Put setup code here. This method is called before the invocation of each - // test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each - // test method in the class. -} - -void sendMessage(ModuleWithKeys &moduleAData, ModuleWithKeys &moduleBData) { - if (!moduleAData.module->hasSessionFor(moduleBData.module->id)) { - moduleAData.module->initializeOutboundForSendingSession( - moduleBData.module->id, - moduleBData.keys.identityKeys, - moduleBData.keys.oneTimeKeys); - } - std::string message{Tools::generateRandomString(50)}; - EncryptedData encryptedData = - moduleAData.module->encrypt(moduleBData.module->id, message); - comm::Logger::log("encrypted: " + message); - - if (!moduleBData.module->hasSessionFor(moduleAData.module->id)) { - moduleBData.module->initializeInboundForReceivingSession( - moduleAData.module->id, - encryptedData.message, - moduleAData.keys.identityKeys); - } - - std::string decrypted = moduleBData.module->decrypt( - moduleAData.module->id, encryptedData, moduleAData.keys.identityKeys); - comm::Logger::log("decrypted: " + decrypted); - - XCTAssert( - memcmp(message.data(), decrypted.data(), message.size()) == 0, - @"message decrypted properly"); -} - -void repickle(std::shared_ptr module) { - std::string pickleKey{Tools::generateRandomString(20)}; - Persist pickled = module->storeAsB64(pickleKey); - std::string userId = module->id; - module.reset(new CryptoModule(userId)); - module->restoreFromB64(pickleKey, pickled); -}; - -ModuleWithKeys initializeModuleWithKeys(size_t id) { - std::shared_ptr module( - new CryptoModule(std::to_string(1000 + id))); - - std::string idKeys = module->getIdentityKeys(); - std::string otKeys = module->getOneTimeKeys(50); - Keys keys = CryptoModule::keysFromStrings(idKeys, otKeys); - - return {module, keys}; -} - -void sendAlternatingMessages( - ModuleWithKeys &firstSenderData, - ModuleWithKeys &firstReceiverData, - size_t numberOfMessages) { - for (size_t i = 0; i < numberOfMessages; ++i) { - if (i % 2 == 0) { - sendMessage(firstSenderData, firstReceiverData); - } else { - sendMessage(firstReceiverData, firstSenderData); - } - } -} - -void sendMessagesOneWay( - ModuleWithKeys &senderData, - ModuleWithKeys &receiverData, - size_t numberOfMessages) { - for (size_t i = 0; i < numberOfMessages; ++i) { - sendMessage(senderData, receiverData); - } -} - -void performRepickle( - ModuleWithKeys &a, - ModuleWithKeys &b, - RepickleOption repickleOption, - std::function sendCallback) { - for (size_t i = 0; i < 5; ++i) { - switch (repickleOption) { - case RepickleOption::SENDER: { - repickle(a.module); - break; - } - case RepickleOption::RECEIVER: { - repickle(b.module); - break; - } - case RepickleOption::BOTH: { - repickle(a.module); - repickle(b.module); - break; - } - } - sendCallback(a, b); - } -} - -void sendMessagesWrapperTwoUsers( - RepickleOption repickleOption, - std::function sendCallback) { - ModuleWithKeys moduleA = initializeModuleWithKeys(++currentId); - ModuleWithKeys moduleB = initializeModuleWithKeys(++currentId); - - performRepickle(moduleA, moduleB, repickleOption, sendCallback); -} - -void sendMessagesWrapperThreeUsers( - RepickleOption repickleOption, - std::function sendCallback) { - ModuleWithKeys moduleA = initializeModuleWithKeys(++currentId); - ModuleWithKeys moduleB = initializeModuleWithKeys(++currentId); - ModuleWithKeys moduleC = initializeModuleWithKeys(++currentId); - - performRepickle(moduleA, moduleB, repickleOption, sendCallback); - performRepickle(moduleA, moduleC, repickleOption, sendCallback); - performRepickle(moduleB, moduleC, repickleOption, sendCallback); -} - -// for 2.1 -auto callback1 = [](ModuleWithKeys &a, ModuleWithKeys &b) { - sendAlternatingMessages(a, b, 50); -}; - -// for 2.2 -auto callback2 = [](ModuleWithKeys &a, ModuleWithKeys &b) { - sendMessagesOneWay(a, b, 10); - sendAlternatingMessages(b, a, 50); -}; - -// for 2.3 -auto callback3 = [](ModuleWithKeys &a, ModuleWithKeys &b) { - sendMessagesOneWay(a, b, 10); - sendMessagesOneWay(b, a, 10); - sendAlternatingMessages(a, b, 50); -}; - -void testMessagesWrapper( - RepickleOption repickleOption, - std::function callback) { - try { - sendMessagesWrapperTwoUsers(repickleOption, callback); - sendMessagesWrapperThreeUsers(repickleOption, callback); - } catch (std::runtime_error &e) { - comm::Logger::log("test message error: " + std::string(e.what())); - XCTAssert(false); - } -} - -- (void)testMessagesAlternateNoReprickle { - testMessagesWrapper(RepickleOption::NONE, callback1); -} - -- (void)testMessagesAlternateRepickleA { - testMessagesWrapper(RepickleOption::SENDER, callback1); -} - -- (void)testMessagesAlternateRepickleB { - testMessagesWrapper(RepickleOption::RECEIVER, callback1); -} - -- (void)testMessagesAlternateRepickleBoth { - testMessagesWrapper(RepickleOption::BOTH, callback1); -} - -- (void)testMessagesNThenAlternateNoReprickle { - testMessagesWrapper(RepickleOption::NONE, callback2); -} - -- (void)testMessagesNThenAlternateRepickleA { - testMessagesWrapper(RepickleOption::SENDER, callback2); -} - -- (void)testMessagesNThenAlternateRepickleB { - testMessagesWrapper(RepickleOption::RECEIVER, callback2); -} - -- (void)testMessagesNThenAlternateRepickleBoth { - testMessagesWrapper(RepickleOption::BOTH, callback2); -} - -- (void)testMessagesNThenNThenAlternateNoReprickle { - testMessagesWrapper(RepickleOption::NONE, callback3); -} - -- (void)testMessagesNThenNThenAlternateRepickleA { - testMessagesWrapper(RepickleOption::SENDER, callback3); -} - -- (void)testMessagesNThenNThenAlternateRepickleB { - testMessagesWrapper(RepickleOption::RECEIVER, callback3); -} - -- (void)testMessagesNThenNThenAlternateRepickleBoth { - testMessagesWrapper(RepickleOption::BOTH, callback3); -} - -- (void)testTwoUsersCreatingOutboundSessions { - try { - for (size_t wrappingI = 0; wrappingI < 2; ++wrappingI) { - std::shared_ptr moduleA( - new CryptoModule(std::to_string(1000 + (wrappingI * 2)))); - std::string aIdKeys = moduleA->getIdentityKeys(); - std::string aOtKeys = moduleA->getOneTimeKeys(50); - Keys aKeys = CryptoModule::keysFromStrings(aIdKeys, aOtKeys); - - std::shared_ptr moduleB( - new CryptoModule(std::to_string(1001 + (wrappingI * 2)))); - std::string bIdKeys = moduleB->getIdentityKeys(); - std::string bOtKeys = moduleB->getOneTimeKeys(50); - Keys bKeys = CryptoModule::keysFromStrings(bIdKeys, bOtKeys); - - std::string message1{Tools::generateRandomString(50)}; - std::string message2{Tools::generateRandomString(50)}; - - if (!moduleA->hasSessionFor(moduleB->id)) { - moduleA->initializeOutboundForSendingSession( - moduleB->id, bKeys.identityKeys, bKeys.oneTimeKeys); - } - EncryptedData encryptedData1 = moduleA->encrypt(moduleB->id, message1); - - if (!moduleB->hasSessionFor(moduleA->id)) { - moduleB->initializeOutboundForSendingSession( - moduleA->id, aKeys.identityKeys, aKeys.oneTimeKeys); - } - EncryptedData encryptedData2 = moduleB->encrypt(moduleA->id, message2); - - XCTAssert( - moduleA->hasSessionFor(moduleB->id) && - moduleB->hasSessionFor(moduleA->id), - @"sessions created successfully"); - - // they both have outbound sessions so one of them has to remove their - // outbound session and start an inbound session - bool matches = moduleB->matchesInboundSession( - moduleA->id, encryptedData1, aKeys.identityKeys); - if (!matches) { - moduleB->initializeInboundForReceivingSession( - moduleA->id, encryptedData1.message, aKeys.identityKeys, true); - } - - std::string decrypted1 = - moduleB->decrypt(moduleA->id, encryptedData1, aKeys.identityKeys); - // user who reinitialized the session has to encrypt it again - // it's very important to decrypt first, otherwise it's not going to work - // because the `session`'s `received_message` won't be changed and - // `encrypt` will try to send a prekey message but it shouldn't - EncryptedData encryptedData3 = moduleB->encrypt(moduleA->id, message2); - - std::string decrypted2 = - moduleA->decrypt(moduleB->id, encryptedData3, bKeys.identityKeys); - - XCTAssert( - memcmp(message1.data(), decrypted1.data(), message1.size()) == 0, - @"A -> B message decrypted successfully"); - XCTAssert( - memcmp(message2.data(), decrypted2.data(), message2.size()) == 0, - @"B -> A message decrypted successfully"); - - ModuleWithKeys moduleAData = {moduleA, aKeys}; - ModuleWithKeys moduleBData = {moduleB, bKeys}; - - for (size_t i = 0; i < 20; ++i) { - if (wrappingI % 2 == 0) { - sendMessage(moduleAData, moduleBData); - } else { - sendMessage(moduleBData, moduleAData); - } - } - } - } catch (std::runtime_error &e) { - comm::Logger::log("testSessionsIssue error: " + std::string(e.what())); - XCTAssert(false); - } -} - -@end diff --git a/native/package.json b/native/package.json --- a/native/package.json +++ b/native/package.json @@ -86,7 +86,7 @@ "lodash": "^4.17.21", "lottie-react-native": "^5.1.4", "md5": "^2.2.1", - "olm": "git+https://gitlab.matrix.org/matrix-org/olm.git#v3.2.14", + "olm": "git+https://github.com/CommE2E/olm.git#v0.0.4", "react": "18.1.0", "react-native": "^0.70.8", "react-native-background-upload": "^6.6.0", diff --git a/yarn.lock b/yarn.lock --- a/yarn.lock +++ b/yarn.lock @@ -17833,9 +17833,9 @@ resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== -"olm@git+https://gitlab.matrix.org/matrix-org/olm.git#v3.2.14": +"olm@git+https://github.com/CommE2E/olm.git#v0.0.4": version "0.0.0" - resolved "git+https://gitlab.matrix.org/matrix-org/olm.git#5efd38c990b1238236f4e573fba8835dc400982a" + resolved "git+https://github.com/CommE2E/olm.git#9ff2863a394399684e272c0665eb8629ef430714" on-finished@2.4.1: version "2.4.1"