public void TestBadMessageBundle() { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); EcKeyPair bobPreKeyPair = Curve.GenerateKeyPair(); EcKeyPair bobSignedPreKeyPair = Curve.GenerateKeyPair(); byte[] bobSignedPreKeySignature = Curve.CalculateSignature(bobStore.GetIdentityKeyPair().GetPrivateKey(), bobSignedPreKeyPair.GetPublicKey().Serialize()); PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1, 31337, bobPreKeyPair.GetPublicKey(), 22, bobSignedPreKeyPair.GetPublicKey(), bobSignedPreKeySignature, bobStore.GetIdentityKeyPair().GetPublicKey()); bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.GetPreKeyId(), bobPreKeyPair)); bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.CurrentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); aliceSessionBuilder.Process(bobPreKey); String originalMessage = "L'homme est condamné à être libre"; SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); CiphertextMessage outgoingMessageOne = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(CiphertextMessage.PrekeyType, outgoingMessageOne.GetMessageType()); byte[] goodMessage = outgoingMessageOne.Serialize(); byte[] badMessage = new byte[goodMessage.Length]; Array.Copy(goodMessage, 0, badMessage, 0, badMessage.Length); badMessage[badMessage.Length - 10] ^= 0x01; PreKeySignalMessage incomingMessage = new PreKeySignalMessage(badMessage); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); byte[] plaintext = new byte[0]; try { plaintext = bobSessionCipher.Decrypt(incomingMessage); throw new Exception("Decrypt should have failed!"); } catch (InvalidMessageException) { // good. } Assert.IsTrue(bobStore.ContainsPreKey(31337)); plaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(goodMessage)); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); Assert.IsFalse(bobStore.ContainsPreKey(31337)); }
public void TestBasicSimultaneousInitiate() { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); PreKeyBundle alicePreKeyBundle = CreateAlicePreKeyBundle(aliceStore); PreKeyBundle bobPreKeyBundle = CreateBobPreKeyBundle(bobStore); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, AliceAddress); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); aliceSessionBuilder.Process(bobPreKeyBundle); bobSessionBuilder.Process(alicePreKeyBundle); CiphertextMessage messageForBob = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("hey there")); CiphertextMessage messageForAlice = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("sample message")); Assert.AreEqual(CiphertextMessage.PrekeyType, messageForBob.GetMessageType()); Assert.AreEqual(CiphertextMessage.PrekeyType, messageForAlice.GetMessageType()); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); byte[] alicePlaintext = aliceSessionCipher.Decrypt(new PreKeySignalMessage(messageForAlice.Serialize())); byte[] bobPlaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(messageForBob.Serialize())); Assert.AreEqual("sample message", Encoding.UTF8.GetString(alicePlaintext)); Assert.AreEqual("hey there", Encoding.UTF8.GetString(bobPlaintext)); Assert.AreEqual((uint)3, aliceStore.LoadSession(BobAddress).GetSessionState().GetSessionVersion()); Assert.AreEqual((uint)3, bobStore.LoadSession(AliceAddress).GetSessionState().GetSessionVersion()); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); CiphertextMessage aliceResponse = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("second message")); Assert.AreEqual(CiphertextMessage.WhisperType, aliceResponse.GetMessageType()); byte[] responsePlaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceResponse.Serialize())); Assert.AreEqual("second message", Encoding.UTF8.GetString(responsePlaintext)); Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore)); CiphertextMessage finalMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("third message")); Assert.AreEqual(CiphertextMessage.WhisperType, finalMessage.GetMessageType()); byte[] finalPlaintext = aliceSessionCipher.Decrypt(new SignalMessage(finalMessage.Serialize())); Assert.AreEqual("third message", Encoding.UTF8.GetString(finalPlaintext)); Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore)); }
public void TestRepeatBundleMessageV3() { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); EcKeyPair bobPreKeyPair = Curve.GenerateKeyPair(); EcKeyPair bobSignedPreKeyPair = Curve.GenerateKeyPair(); byte[] bobSignedPreKeySignature = Curve.CalculateSignature(bobStore.GetIdentityKeyPair().GetPrivateKey(), bobSignedPreKeyPair.GetPublicKey().Serialize()); PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1, 31337, bobPreKeyPair.GetPublicKey(), 22, bobSignedPreKeyPair.GetPublicKey(), bobSignedPreKeySignature, bobStore.GetIdentityKeyPair().GetPublicKey()); bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.GetPreKeyId(), bobPreKeyPair)); bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.CurrentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); aliceSessionBuilder.Process(bobPreKey); String originalMessage = "L'homme est condamné à être libre"; SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); CiphertextMessage outgoingMessageOne = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); CiphertextMessage outgoingMessageTwo = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(CiphertextMessage.PrekeyType, outgoingMessageOne.GetMessageType()); Assert.AreEqual(CiphertextMessage.PrekeyType, outgoingMessageTwo.GetMessageType()); PreKeySignalMessage incomingMessage = new PreKeySignalMessage(outgoingMessageOne.Serialize()); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); byte[] plaintext = bobSessionCipher.Decrypt(incomingMessage); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); CiphertextMessage bobOutgoingMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); byte[] alicePlaintext = aliceSessionCipher.Decrypt(new SignalMessage(bobOutgoingMessage.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext)); // The test PreKeySignalMessage incomingMessageTwo = new PreKeySignalMessage(outgoingMessageTwo.Serialize()); plaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(incomingMessageTwo.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); bobOutgoingMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); alicePlaintext = aliceSessionCipher.Decrypt(new SignalMessage(bobOutgoingMessage.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext)); }
public void TestMessageKeyLimits() { SessionRecord aliceSessionRecord = new SessionRecord(); SessionRecord bobSessionRecord = new SessionRecord(); InitializeSessionsV3(aliceSessionRecord.GetSessionState(), bobSessionRecord.GetSessionState()); ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); aliceStore.StoreSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord); bobStore.StoreSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord); SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1)); SessionCipher bobCipher = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1)); List <CiphertextMessage> inflight = new List <CiphertextMessage>(); for (int i = 0; i < 2010; i++) { inflight.Add(aliceCipher.Encrypt(Encoding.UTF8.GetBytes("you've never been so hungry, you've never been so cold"))); } bobCipher.Decrypt(new SignalMessage(inflight[1000].Serialize())); bobCipher.Decrypt(new SignalMessage(inflight[inflight.Count - 1].Serialize())); try { bobCipher.Decrypt(new SignalMessage(inflight[0].Serialize())); throw new Exception("Should have failed!"); } catch (DuplicateMessageException) { // good } }
public void TestOptionalOneTimePreKey() { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); EcKeyPair bobPreKeyPair = Curve.GenerateKeyPair(); EcKeyPair bobSignedPreKeyPair = Curve.GenerateKeyPair(); byte[] bobSignedPreKeySignature = Curve.CalculateSignature(bobStore.GetIdentityKeyPair().GetPrivateKey(), bobSignedPreKeyPair.GetPublicKey().Serialize()); PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1, 0, null, 22, bobSignedPreKeyPair.GetPublicKey(), bobSignedPreKeySignature, bobStore.GetIdentityKeyPair().GetPublicKey()); aliceSessionBuilder.Process(bobPreKey); Assert.IsTrue(aliceStore.ContainsSession(BobAddress)); Assert.AreEqual((uint)3, aliceStore.LoadSession(BobAddress).GetSessionState().GetSessionVersion()); String originalMessage = "L'homme est condamné à être libre"; SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); CiphertextMessage outgoingMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(outgoingMessage.GetMessageType(), CiphertextMessage.PrekeyType); PreKeySignalMessage incomingMessage = new PreKeySignalMessage(outgoingMessage.Serialize()); Assert.IsFalse(incomingMessage.GetPreKeyId().HasValue); bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.GetPreKeyId(), bobPreKeyPair)); bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.CurrentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); byte[] plaintext = bobSessionCipher.Decrypt(incomingMessage); Assert.IsTrue(bobStore.ContainsSession(AliceAddress)); Assert.AreEqual((uint)3, bobStore.LoadSession(AliceAddress).GetSessionState().GetSessionVersion()); Assert.IsNotNull(bobStore.LoadSession(AliceAddress).GetSessionState().GetAliceBaseKey()); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); }
private void RunInteraction(SessionRecord aliceSessionRecord, SessionRecord bobSessionRecord) { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); aliceStore.StoreSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord); bobStore.StoreSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord); SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1)); SessionCipher bobCipher = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1)); byte[] alicePlaintext = Encoding.UTF8.GetBytes("This is a plaintext message."); CiphertextMessage message = aliceCipher.Encrypt(alicePlaintext); byte[] bobPlaintext = bobCipher.Decrypt(new SignalMessage(message.Serialize())); CollectionAssert.AreEqual(alicePlaintext, bobPlaintext); byte[] bobReply = Encoding.UTF8.GetBytes("This is a message from Bob."); CiphertextMessage reply = bobCipher.Encrypt(bobReply); byte[] receivedReply = aliceCipher.Decrypt(new SignalMessage(reply.Serialize())); CollectionAssert.AreEqual(bobReply, receivedReply); List <CiphertextMessage> aliceCiphertextMessages = new List <CiphertextMessage>(); List <byte[]> alicePlaintextMessages = new List <byte[]>(); for (int i = 0; i < 50; i++) { alicePlaintextMessages.Add(Encoding.UTF8.GetBytes("смерть за смерть " + i)); aliceCiphertextMessages.Add(aliceCipher.Encrypt(Encoding.UTF8.GetBytes("смерть за смерть " + i))); } ulong seed = DateUtil.CurrentTimeMillis(); HelperMethods.Shuffle(aliceCiphertextMessages, new Random((int)seed)); HelperMethods.Shuffle(alicePlaintextMessages, new Random((int)seed)); for (int i = 0; i < aliceCiphertextMessages.Count / 2; i++) { byte[] receivedPlaintext = bobCipher.Decrypt(new SignalMessage(aliceCiphertextMessages[i].Serialize())); Assert.IsTrue(ByteUtil.IsEqual(receivedPlaintext, alicePlaintextMessages[i])); } List <CiphertextMessage> bobCiphertextMessages = new List <CiphertextMessage>(); List <byte[]> bobPlaintextMessages = new List <byte[]>(); for (int i = 0; i < 20; i++) { bobPlaintextMessages.Add(Encoding.UTF8.GetBytes("смерть за смерть " + i)); bobCiphertextMessages.Add(bobCipher.Encrypt(Encoding.UTF8.GetBytes("смерть за смерть " + i))); } seed = DateUtil.CurrentTimeMillis(); HelperMethods.Shuffle(bobCiphertextMessages, new Random((int)seed)); HelperMethods.Shuffle(bobPlaintextMessages, new Random((int)seed)); for (int i = 0; i < bobCiphertextMessages.Count / 2; i++) { byte[] receivedPlaintext = aliceCipher.Decrypt(new SignalMessage(bobCiphertextMessages[i].Serialize())); CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]); } for (int i = aliceCiphertextMessages.Count / 2; i < aliceCiphertextMessages.Count; i++) { byte[] receivedPlaintext = bobCipher.Decrypt(new SignalMessage(aliceCiphertextMessages[i].Serialize())); CollectionAssert.AreEqual(receivedPlaintext, alicePlaintextMessages[i]); } for (int i = bobCiphertextMessages.Count / 2; i < bobCiphertextMessages.Count; i++) { byte[] receivedPlaintext = aliceCipher.Decrypt(new SignalMessage(bobCiphertextMessages[i].Serialize())); CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]); } }
public void TestRepeatedSimultaneousInitiateLostMessageRepeatedMessages() { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, AliceAddress); SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); // PreKeyBundle aliceLostPreKeyBundle = createAlicePreKeyBundle(aliceStore); PreKeyBundle bobLostPreKeyBundle = CreateBobPreKeyBundle(bobStore); aliceSessionBuilder.Process(bobLostPreKeyBundle); // bobSessionBuilder.process(aliceLostPreKeyBundle); CiphertextMessage lostMessageForBob = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("hey there")); // CiphertextMessage lostMessageForAlice = bobSessionCipher.encrypt("sample message".getBytes()); for (int i = 0; i < 15; i++) { PreKeyBundle alicePreKeyBundle = CreateAlicePreKeyBundle(aliceStore); PreKeyBundle bobPreKeyBundle = CreateBobPreKeyBundle(bobStore); aliceSessionBuilder.Process(bobPreKeyBundle); bobSessionBuilder.Process(alicePreKeyBundle); CiphertextMessage messageForBob = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("hey there")); CiphertextMessage messageForAlice = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("sample message")); Assert.AreEqual <uint>(messageForBob.GetMessageType(), CiphertextMessage.PrekeyType); Assert.AreEqual <uint>(messageForAlice.GetMessageType(), CiphertextMessage.PrekeyType); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); byte[] alicePlaintext = aliceSessionCipher.Decrypt(new PreKeySignalMessage(messageForAlice.Serialize())); byte[] bobPlaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(messageForBob.Serialize())); Assert.IsTrue(Encoding.UTF8.GetString(alicePlaintext).Equals("sample message")); Assert.IsTrue(Encoding.UTF8.GetString(bobPlaintext).Equals("hey there")); Assert.IsTrue(aliceStore.LoadSession(BobAddress).GetSessionState().GetSessionVersion() == 3); Assert.IsTrue(bobStore.LoadSession(AliceAddress).GetSessionState().GetSessionVersion() == 3); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); } for (int i = 0; i < 50; i++) { CiphertextMessage messageForBobRepeat = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("hey there")); CiphertextMessage messageForAliceRepeat = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("sample message")); Assert.AreEqual <uint>(messageForBobRepeat.GetMessageType(), CiphertextMessage.WhisperType); Assert.AreEqual <uint>(messageForAliceRepeat.GetMessageType(), CiphertextMessage.WhisperType); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); byte[] alicePlaintextRepeat = aliceSessionCipher.Decrypt(new SignalMessage(messageForAliceRepeat.Serialize())); byte[] bobPlaintextRepeat = bobSessionCipher.Decrypt(new SignalMessage(messageForBobRepeat.Serialize())); Assert.IsTrue(Encoding.UTF8.GetString(alicePlaintextRepeat).Equals("sample message")); Assert.IsTrue(Encoding.UTF8.GetString(bobPlaintextRepeat).Equals("hey there")); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); } CiphertextMessage aliceResponse = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("second message")); Assert.AreEqual <uint>(aliceResponse.GetMessageType(), CiphertextMessage.WhisperType); byte[] responsePlaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceResponse.Serialize())); Assert.IsTrue(Encoding.UTF8.GetString(responsePlaintext).Equals("second message")); Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore)); CiphertextMessage finalMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("third message")); Assert.AreEqual <uint>(finalMessage.GetMessageType(), CiphertextMessage.WhisperType); byte[] finalPlaintext = aliceSessionCipher.Decrypt(new SignalMessage(finalMessage.Serialize())); Assert.IsTrue(Encoding.UTF8.GetString(finalPlaintext).Equals("third message")); Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore)); byte[] lostMessagePlaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(lostMessageForBob.Serialize())); Assert.IsTrue(Encoding.UTF8.GetString(lostMessagePlaintext).Equals("hey there")); Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore)); CiphertextMessage blastFromThePast = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("unexpected!")); byte[] blastFromThePastPlaintext = aliceSessionCipher.Decrypt(new SignalMessage(blastFromThePast.Serialize())); Assert.IsTrue(Encoding.UTF8.GetString(blastFromThePastPlaintext).Equals("unexpected!")); Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore)); }
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)); } }
public void TestBasicPreKeyV3() { ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore(); SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); ISignalProtocolStore bobStore = new TestInMemorySignalProtocolStore(); EcKeyPair bobPreKeyPair = Curve.GenerateKeyPair(); EcKeyPair bobSignedPreKeyPair = Curve.GenerateKeyPair(); byte[] bobSignedPreKeySignature = Curve.CalculateSignature(bobStore.GetIdentityKeyPair().GetPrivateKey(), bobSignedPreKeyPair.GetPublicKey().Serialize()); PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1, 31337, bobPreKeyPair.GetPublicKey(), 22, bobSignedPreKeyPair.GetPublicKey(), bobSignedPreKeySignature, bobStore.GetIdentityKeyPair().GetPublicKey()); aliceSessionBuilder.Process(bobPreKey); Assert.IsTrue(aliceStore.ContainsSession(BobAddress)); Assert.AreEqual((uint)3, aliceStore.LoadSession(BobAddress).GetSessionState().GetSessionVersion()); String originalMessage = "L'homme est condamné à être libre"; SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); CiphertextMessage outgoingMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(CiphertextMessage.PrekeyType, outgoingMessage.GetMessageType()); PreKeySignalMessage incomingMessage = new PreKeySignalMessage(outgoingMessage.Serialize()); bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.GetPreKeyId(), bobPreKeyPair)); bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.CurrentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); byte[] plaintext = bobSessionCipher.Decrypt(incomingMessage, new BobDecryptionCallback(bobStore, originalMessage)); Assert.IsTrue(bobStore.ContainsSession(AliceAddress)); Assert.AreEqual((uint)3, bobStore.LoadSession(AliceAddress).GetSessionState().GetSessionVersion()); Assert.IsNotNull(bobStore.LoadSession(AliceAddress).GetSessionState().GetAliceBaseKey()); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); CiphertextMessage bobOutgoingMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(CiphertextMessage.WhisperType, bobOutgoingMessage.GetMessageType()); byte[] alicePlaintext = aliceSessionCipher.Decrypt(new SignalMessage(bobOutgoingMessage.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext)); RunInteraction(aliceStore, bobStore); aliceStore = new TestInMemorySignalProtocolStore(); aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress); aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); bobPreKeyPair = Curve.GenerateKeyPair(); bobSignedPreKeyPair = Curve.GenerateKeyPair(); bobSignedPreKeySignature = Curve.CalculateSignature(bobStore.GetIdentityKeyPair().GetPrivateKey(), bobSignedPreKeyPair.GetPublicKey().Serialize()); bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1, 31338, bobPreKeyPair.GetPublicKey(), 23, bobSignedPreKeyPair.GetPublicKey(), bobSignedPreKeySignature, bobStore.GetIdentityKeyPair().GetPublicKey()); bobStore.StorePreKey(31338, new PreKeyRecord(bobPreKey.GetPreKeyId(), bobPreKeyPair)); bobStore.StoreSignedPreKey(23, new SignedPreKeyRecord(23, DateUtil.CurrentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature)); aliceSessionBuilder.Process(bobPreKey); outgoingMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); try { plaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(outgoingMessage.Serialize())); throw new Exception("shouldn't be trusted!"); } catch (UntrustedIdentityException) { bobStore.SaveIdentity(AliceAddress, new PreKeySignalMessage(outgoingMessage.Serialize()).GetIdentityKey()); } plaintext = bobSessionCipher.Decrypt(new PreKeySignalMessage(outgoingMessage.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1, 31337, Curve.GenerateKeyPair().GetPublicKey(), 23, bobSignedPreKeyPair.GetPublicKey(), bobSignedPreKeySignature, aliceStore.GetIdentityKeyPair().GetPublicKey()); try { aliceSessionBuilder.Process(bobPreKey); throw new Exception("shoulnd't be trusted!"); } catch (UntrustedIdentityException) { // good } }
private void RunInteraction(ISignalProtocolStore aliceStore, ISignalProtocolStore bobStore) { SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress); SessionCipher bobSessionCipher = new SessionCipher(bobStore, AliceAddress); String originalMessage = "smert ze smert"; CiphertextMessage aliceMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(CiphertextMessage.WhisperType, aliceMessage.GetMessageType()); byte[] plaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceMessage.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); CiphertextMessage bobMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes(originalMessage)); Assert.AreEqual(CiphertextMessage.WhisperType, bobMessage.GetMessageType()); plaintext = aliceSessionCipher.Decrypt(new SignalMessage(bobMessage.Serialize())); Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext)); for (int i = 0; i < 10; i++) { String loopingMessage = ("What do we mean by saying that existence precedes essence? " + "We mean that man first of all exists, encounters himself, " + "surges up in the world--and defines himself aftward. " + i); CiphertextMessage aliceLoopingMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(loopingMessage)); byte[] loopingPlaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceLoopingMessage.Serialize())); Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext)); } for (int i = 0; i < 10; i++) { String loopingMessage = ("What do we mean by saying that existence precedes essence? " + "We mean that man first of all exists, encounters himself, " + "surges up in the world--and defines himself aftward. " + i); CiphertextMessage bobLoopingMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes(loopingMessage)); byte[] loopingPlaintext = aliceSessionCipher.Decrypt(new SignalMessage(bobLoopingMessage.Serialize())); Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext)); } HashSet <Pair <String, CiphertextMessage> > aliceOutOfOrderMessages = new HashSet <Pair <String, CiphertextMessage> >(); for (int i = 0; i < 10; i++) { String loopingMessage = ("What do we mean by saying that existence precedes essence? " + "We mean that man first of all exists, encounters himself, " + "surges up in the world--and defines himself aftward. " + i); CiphertextMessage aliceLoopingMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(loopingMessage)); aliceOutOfOrderMessages.Add(new Pair <String, CiphertextMessage>(loopingMessage, aliceLoopingMessage)); } for (int i = 0; i < 10; i++) { String loopingMessage = ("What do we mean by saying that existence precedes essence? " + "We mean that man first of all exists, encounters himself, " + "surges up in the world--and defines himself aftward. " + i); CiphertextMessage aliceLoopingMessage = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes(loopingMessage)); byte[] loopingPlaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceLoopingMessage.Serialize())); Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext)); } for (int i = 0; i < 10; i++) { String loopingMessage = ("You can only desire based on what you know: " + i); CiphertextMessage bobLoopingMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes(loopingMessage)); byte[] loopingPlaintext = aliceSessionCipher.Decrypt(new SignalMessage(bobLoopingMessage.Serialize())); Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext)); } foreach (Pair <String, CiphertextMessage> aliceOutOfOrderMessage in aliceOutOfOrderMessages) { byte[] outOfOrderPlaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceOutOfOrderMessage.Second().Serialize())); Assert.AreEqual(aliceOutOfOrderMessage.First(), Encoding.UTF8.GetString(outOfOrderPlaintext)); } }