public void Test_OmemoKeyExchangeMessage() { Random rand = new Random(); byte[] hmac = new byte[16]; rand.NextBytes(hmac); byte[] sessionKey = new byte[32]; rand.NextBytes(sessionKey); IdentityKeyPairModel identityKey = KeyHelper.GenerateIdentityKeyPair(); SignedPreKeyModel signedPreKey = KeyHelper.GenerateSignedPreKey(0, identityKey.privKey); OmemoSessionModel refOmemoSession = new OmemoSessionModel(new Bundle() { identityKey = identityKey.pubKey, preKeys = KeyHelper.GeneratePreKeys(0, 10), preKeySignature = signedPreKey.signature, signedPreKey = signedPreKey.preKey.pubKey, signedPreKeyId = signedPreKey.preKey.keyId }, 0, KeyHelper.GenerateIdentityKeyPair()) { ek = KeyHelper.GenerateKeyPair().pubKey }; OmemoMessage refOmemoMessage = new OmemoMessage(refOmemoSession); OmemoAuthenticatedMessage refOmemoAuthenticatedMessage = new OmemoAuthenticatedMessage(new byte[16], refOmemoMessage.ToByteArray()); OmemoKeyExchangeMessage refOmemoKeyExchangeMessage = new OmemoKeyExchangeMessage((uint)rand.Next(), (uint)rand.Next(), KeyHelper.GenerateKeyPair().pubKey, KeyHelper.GenerateKeyPair().pubKey, refOmemoAuthenticatedMessage); byte[] data = refOmemoKeyExchangeMessage.ToByteArray(); Assert.IsTrue(data.Length > 0); OmemoKeyExchangeMessage omemoKeyExchangeMessage = new OmemoKeyExchangeMessage(data); Assert.IsTrue(omemoKeyExchangeMessage.Equals(refOmemoKeyExchangeMessage)); }
public void Test_OmemoBundleInformation() { IdentityKeyPairModel bobIdentKey = KeyHelper.GenerateIdentityKeyPair(); List <PreKeyModel> bobPreKeys = KeyHelper.GeneratePreKeys(0, 100); SignedPreKeyModel bobSignedPreKey = KeyHelper.GenerateSignedPreKey(0, bobIdentKey.privKey); Bundle bobBundle = new Bundle() { identityKey = bobIdentKey.pubKey, preKeys = bobPreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList(), preKeySignature = bobSignedPreKey.signature, signedPreKey = bobSignedPreKey.preKey.pubKey, signedPreKeyId = bobSignedPreKey.preKey.keyId }; string bundleInfo = GetBobsBundleInfoMsg(bobBundle); MessageParser2 parser = new MessageParser2(); List <AbstractMessage> messages = parser.parseMessages(ref bundleInfo); // Check if message parsed successfully: Assert.IsTrue(messages.Count == 1); Assert.IsInstanceOfType(messages[0], typeof(OmemoBundleInformationResultMessage)); OmemoBundleInformationResultMessage bundleInfoMsg = messages[0] as OmemoBundleInformationResultMessage; // Check if keys match: Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.identityKey.Equals(bobIdentKey.pubKey)); Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.preKeys.SequenceEqual(bobPreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList())); Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.preKeySignature.SequenceEqual(bobSignedPreKey.signature)); Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.signedPreKey.Equals(bobSignedPreKey.preKey.pubKey)); Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.signedPreKeyId == bobSignedPreKey.preKey.keyId); }
public void Test_PreKeyGeneration() { for (uint count = 0; count < 250; count++) { List <PreKeyModel> keys = KeyHelper.GeneratePreKeys(1, count); Assert.AreEqual(keys.Count, (int)count); } // Rollover: for (uint count = 0; count < 10; count++) { List <PreKeyModel> keys = KeyHelper.GeneratePreKeys(0x7FFFFFFF, count); Assert.AreEqual(keys.Count, (int)count); } for (uint count = 0; count < 10; count++) { List <PreKeyModel> keys = KeyHelper.GeneratePreKeys(0x7FFFFFFF - count, 100); Assert.AreEqual(keys.Count, 100); } // Key IDs are unique: List <uint> ids = new List <uint>(); List <PreKeyModel> keys2 = KeyHelper.GeneratePreKeys(0x7FFFFFFF - 100, 1000); for (int i = 0; i < keys2.Count; i++) { Assert.IsFalse(ids.Contains(keys2[i].keyId)); ids.Add(keys2[i].keyId); } }
public void Test_Omemo_Send_Receive_Send() { // Generate Alices keys: IdentityKeyPairModel aliceIdentKey = KeyHelper.GenerateIdentityKeyPair(); List <PreKeyModel> alicePreKeys = KeyHelper.GeneratePreKeys(0, 1); SignedPreKeyModel aliceSignedPreKey = KeyHelper.GenerateSignedPreKey(0, aliceIdentKey.privKey); Bundle aliceBundle = new Bundle() { identityKey = aliceIdentKey.pubKey, preKeys = alicePreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList(), preKeySignature = aliceSignedPreKey.signature, signedPreKey = aliceSignedPreKey.preKey.pubKey, signedPreKeyId = aliceSignedPreKey.preKey.keyId }; InMemmoryOmemoStorage aliceStorage = new InMemmoryOmemoStorage(); DoubleRachet aliceRachet = new DoubleRachet(aliceIdentKey); // Generate Bobs keys: IdentityKeyPairModel bobIdentKey = KeyHelper.GenerateIdentityKeyPair(); List <PreKeyModel> bobPreKeys = KeyHelper.GeneratePreKeys(0, 1); SignedPreKeyModel bobSignedPreKey = KeyHelper.GenerateSignedPreKey(0, bobIdentKey.privKey); Bundle bobBundle = new Bundle() { identityKey = bobIdentKey.pubKey, preKeys = bobPreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList(), preKeySignature = bobSignedPreKey.signature, signedPreKey = bobSignedPreKey.preKey.pubKey, signedPreKeyId = bobSignedPreKey.preKey.keyId }; InMemmoryOmemoStorage bobStorage = new InMemmoryOmemoStorage(); DoubleRachet bobRachet = new DoubleRachet(bobIdentKey); //-----------------OMEOMO Session Building:----------------- MessageParser2 parser = new MessageParser2(); string deviceListMsg = GetBobsDeviceListMsg(); List <AbstractMessage> messages = parser.parseMessages(ref deviceListMsg); Assert.IsTrue(messages.Count == 1); Assert.IsTrue(messages[0] is OmemoDeviceListResultMessage); OmemoDeviceListResultMessage devList = messages[0] as OmemoDeviceListResultMessage; uint selectedBobDeviceId = devList.DEVICES.getRandomDeviceId(); Assert.IsTrue(selectedBobDeviceId == BOB_ADDRESS.DEVICE_ID); // Alice builds a session to Bob: string bundleInfoMsg = GetBobsBundleInfoMsg(bobBundle); messages = parser.parseMessages(ref bundleInfoMsg); Assert.IsTrue(messages.Count == 1); Assert.IsTrue(messages[0] is OmemoBundleInformationResultMessage); OmemoBundleInformationResultMessage bundleInfo = messages[0] as OmemoBundleInformationResultMessage; Assert.IsTrue(bundleInfo.BUNDLE_INFO.deviceId == BOB_ADDRESS.DEVICE_ID); aliceStorage.StoreFingerprint(new OmemoFingerprint(bobBundle.identityKey, BOB_ADDRESS)); // Encrypt Message 1: string msg1 = "Hello OMEMO"; OmemoEncryptedMessage omemoEncryptedMessage = new OmemoEncryptedMessage(ALICE_ADDRESS.BARE_JID, BOB_ADDRESS.BARE_JID, msg1, MessageMessage.TYPE_CHAT, false); List <OmemoDeviceGroup> bobDevices = new List <OmemoDeviceGroup>(); OmemoDeviceGroup bobDeviceGroup = new OmemoDeviceGroup(BOB_ADDRESS.BARE_JID); bobDeviceGroup.SESSIONS[BOB_ADDRESS.DEVICE_ID] = new OmemoSessionModel(bobBundle, 0, aliceIdentKey); bobDevices.Add(bobDeviceGroup); omemoEncryptedMessage.encrypt(ALICE_ADDRESS.DEVICE_ID, aliceIdentKey, aliceStorage, bobDevices); Assert.IsTrue(omemoEncryptedMessage.ENCRYPTED); Assert.IsNotNull(aliceStorage.LoadFingerprint(BOB_ADDRESS)); Assert.IsNotNull(aliceStorage.LoadSession(BOB_ADDRESS)); // Decrypt Message 1: // Throws an exception in case something goes wrong: OmemoDecryptionContext decryptCtx1 = new OmemoDecryptionContext(BOB_ADDRESS, bobIdentKey, bobSignedPreKey, bobPreKeys, false, bobStorage); omemoEncryptedMessage.decrypt(decryptCtx1); Assert.AreEqual(msg1, omemoEncryptedMessage.MESSAGE); Assert.IsFalse(omemoEncryptedMessage.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsFalse(omemoEncryptedMessage.ENCRYPTED); Assert.IsNotNull(bobStorage.LoadFingerprint(ALICE_ADDRESS)); Assert.IsNotNull(bobStorage.LoadSession(ALICE_ADDRESS)); // Encrypt Message 2: string msg2 = "Hello OMEMO 2"; OmemoEncryptedMessage omemoEncryptedMessage2 = new OmemoEncryptedMessage(BOB_ADDRESS.BARE_JID, ALICE_ADDRESS.BARE_JID, msg2, MessageMessage.TYPE_CHAT, false); List <OmemoDeviceGroup> aliceDevices = new List <OmemoDeviceGroup>(); OmemoDeviceGroup aliceDeviceGroup = new OmemoDeviceGroup(ALICE_ADDRESS.BARE_JID); aliceDeviceGroup.SESSIONS[ALICE_ADDRESS.DEVICE_ID] = bobStorage.LoadSession(ALICE_ADDRESS); aliceDevices.Add(aliceDeviceGroup); omemoEncryptedMessage2.encrypt(BOB_ADDRESS.DEVICE_ID, bobIdentKey, bobStorage, aliceDevices); Assert.IsTrue(omemoEncryptedMessage2.ENCRYPTED); // Decrypt Message 2: // Throws an exception in case something goes wrong: OmemoDecryptionContext decryptCtx2 = new OmemoDecryptionContext(ALICE_ADDRESS, aliceIdentKey, aliceSignedPreKey, alicePreKeys, false, aliceStorage); omemoEncryptedMessage2.decrypt(decryptCtx2); Assert.AreEqual(msg2, omemoEncryptedMessage2.MESSAGE); Assert.IsFalse(omemoEncryptedMessage2.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsFalse(omemoEncryptedMessage2.ENCRYPTED); // Encrypt Message 3: string msg3 = "Hello OMEMO 3"; OmemoEncryptedMessage omemoEncryptedMessage3 = new OmemoEncryptedMessage(ALICE_ADDRESS.BARE_JID, BOB_ADDRESS.BARE_JID, msg3, MessageMessage.TYPE_CHAT, false); bobDeviceGroup.SESSIONS[BOB_ADDRESS.DEVICE_ID] = aliceStorage.LoadSession(BOB_ADDRESS); omemoEncryptedMessage3.encrypt(ALICE_ADDRESS.DEVICE_ID, aliceIdentKey, aliceStorage, bobDevices); Assert.IsFalse(omemoEncryptedMessage3.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsTrue(omemoEncryptedMessage3.ENCRYPTED); Assert.IsNotNull(aliceStorage.LoadFingerprint(BOB_ADDRESS)); Assert.IsNotNull(aliceStorage.LoadSession(BOB_ADDRESS)); // Decrypt Message 3: // Throws an exception in case something goes wrong: OmemoDecryptionContext decryptCtx3 = new OmemoDecryptionContext(BOB_ADDRESS, bobIdentKey, bobSignedPreKey, bobPreKeys, false, bobStorage); omemoEncryptedMessage3.decrypt(decryptCtx3); Assert.AreEqual(msg3, omemoEncryptedMessage3.MESSAGE); Assert.IsFalse(omemoEncryptedMessage3.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsFalse(omemoEncryptedMessage3.ENCRYPTED); Assert.IsNotNull(bobStorage.LoadFingerprint(ALICE_ADDRESS)); Assert.IsNotNull(bobStorage.LoadSession(ALICE_ADDRESS)); }
static void Main(string[] args) { // 1. Sender setup // At install time, a libsignal client needs to generate its identity keys, registration id, and prekeys. var senderIdentityKeyPair = KeyHelper.GenerateIdentityKeyPair(); var senderRegistrationId = KeyHelper.GenerateRegistrationId(false); var senderPreKeys = KeyHelper.GeneratePreKeys(0, 100); var senderSignedPreKey = KeyHelper.GenerateSignedPreKey(senderIdentityKeyPair, KeyHelper.GenerateSenderKeyId()); var senderAddress = new SignalProtocolAddress("sender", 1); // TODO: Store identityKeyPair somewhere durable and safe. // TODO: Store registrationId somewhere durable and safe. // Store preKeys in PreKeyStore. var senderPreKeyStore = new InMemoryPreKeyStore(); foreach (var senderPreKey in senderPreKeys) { senderPreKeyStore.StorePreKey(senderPreKey.GetId(), senderPreKey); } // Store signed prekey in SignedPreKeyStore. var senderSignedPreKeyStore = new InMemorySignedPreKeyStore(); senderSignedPreKeyStore.StoreSignedPreKey(senderSignedPreKey.GetId(), senderSignedPreKey); var senderSessionStore = new InMemorySessionStore(); var senderIdentityStore = new InMemoryIdentityKeyStore(senderIdentityKeyPair, senderRegistrationId); var senderProtocolStore = new InMemorySignalProtocolStore(senderIdentityKeyPair, senderRegistrationId); var senderPreKeyBundle = new PreKeyBundle( senderProtocolStore.GetLocalRegistrationId(), senderAddress.DeviceId, senderPreKeys[0].GetId(), senderPreKeys[0].GetKeyPair().GetPublicKey(), senderSignedPreKey.GetId(), senderSignedPreKey.GetKeyPair().GetPublicKey(), senderSignedPreKey.GetSignature(), senderProtocolStore.GetIdentityKeyPair().GetPublicKey() ); senderProtocolStore.StorePreKey(senderPreKeys[0].GetId(), new PreKeyRecord(senderPreKeyBundle.GetPreKeyId(), senderPreKeys[0].GetKeyPair())); senderProtocolStore.StoreSignedPreKey(senderSignedPreKey.GetId(), new SignedPreKeyRecord(22, (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), senderSignedPreKey.GetKeyPair(), senderSignedPreKey.GetSignature())); // 2. Destination setup var destinationIdentityKeyPair = KeyHelper.GenerateIdentityKeyPair(); var destinationRegistrationId = KeyHelper.GenerateRegistrationId(false); var destinationPreKeys = KeyHelper.GeneratePreKeys(0, 100); var destinationSignedPreKey = KeyHelper.GenerateSignedPreKey(destinationIdentityKeyPair, KeyHelper.GenerateSenderKeyId()); var destinationAddress = new SignalProtocolAddress("destination", 1); // TODO: Store identityKeyPair somewhere durable and safe. // TODO: Store registrationId somewhere durable and safe. var destinationPreKeyStore = new InMemoryPreKeyStore(); foreach (var destinationPreKey in destinationPreKeys) { destinationPreKeyStore.StorePreKey(destinationPreKey.GetId(), destinationPreKey); } // Store signed prekey in SignedPreKeyStore. var destinationSignedPreKeyStore = new InMemorySignedPreKeyStore(); destinationSignedPreKeyStore.StoreSignedPreKey(destinationSignedPreKey.GetId(), destinationSignedPreKey); var destinationSessionStore = new InMemorySessionStore(); var destinationIdentityStore = new InMemoryIdentityKeyStore(destinationIdentityKeyPair, destinationRegistrationId); var destinationProtocolStore = new InMemorySignalProtocolStore(destinationIdentityKeyPair, destinationRegistrationId); var destinationPreKeyBundle = new PreKeyBundle( destinationProtocolStore.GetLocalRegistrationId(), destinationAddress.DeviceId, destinationPreKeys[0].GetId(), destinationPreKeys[0].GetKeyPair().GetPublicKey(), destinationSignedPreKey.GetId(), destinationSignedPreKey.GetKeyPair().GetPublicKey(), destinationSignedPreKey.GetSignature(), destinationProtocolStore.GetIdentityKeyPair().GetPublicKey() ); destinationProtocolStore.StorePreKey(destinationPreKeys[0].GetId(), new PreKeyRecord(destinationPreKeyBundle.GetPreKeyId(), destinationPreKeys[0].GetKeyPair())); destinationProtocolStore.StoreSignedPreKey(destinationSignedPreKey.GetId(), new SignedPreKeyRecord(22, (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), destinationSignedPreKey.GetKeyPair(), destinationSignedPreKey.GetSignature())); // Instantiate a SessionBuilder for a remote recipientId + deviceId tuple. var senderToDestinationSessionBuilder = new SessionBuilder(senderProtocolStore, destinationAddress); var destinationToSenderSessionBuilder = new SessionBuilder(destinationProtocolStore, senderAddress); // Build a session with a PreKey retrieved from the server. senderToDestinationSessionBuilder.Process(destinationPreKeyBundle); destinationToSenderSessionBuilder.Process(senderPreKeyBundle); SessionCipher senderToDestinationSessionCipher = new SessionCipher(senderProtocolStore, destinationAddress); while (true) { Console.Write("Enter the text to encrypt: "); var text = Console.ReadLine(); if (string.IsNullOrWhiteSpace(text) || text.Equals("quit", StringComparison.OrdinalIgnoreCase)) { break; } CiphertextMessage message = senderToDestinationSessionCipher.Encrypt(Encoding.UTF8.GetBytes(text)); var encryptedMessage = message.Serialize(); Console.WriteLine("Encrypted message: {0}", Convert.ToBase64String(encryptedMessage)); SessionCipher destinationToSenderSessionCipher = new SessionCipher(destinationProtocolStore, senderAddress); PreKeySignalMessage incomingMessage = new PreKeySignalMessage(encryptedMessage); var decryptedMessage = destinationToSenderSessionCipher.Decrypt(incomingMessage); Console.WriteLine("Decrypted message: {0}", Encoding.UTF8.GetString(decryptedMessage)); } }