public static void initializeSession(SessionState sessionState,
                                             uint sessionVersion,
                                             SymmetricAxolotlParameters parameters)
        {
            if (isAlice(parameters.getOurBaseKey().getPublicKey(), parameters.getTheirBaseKey()))
            {
                AliceAxolotlParameters.Builder aliceParameters = AliceAxolotlParameters.newBuilder();

                aliceParameters.setOurBaseKey(parameters.getOurBaseKey())
                               .setOurIdentityKey(parameters.getOurIdentityKey())
                               .setTheirRatchetKey(parameters.getTheirRatchetKey())
                               .setTheirIdentityKey(parameters.getTheirIdentityKey())
                               .setTheirSignedPreKey(parameters.getTheirBaseKey())
                               .setTheirOneTimePreKey(May<ECPublicKey>.NoValue);

                RatchetingSession.initializeSession(sessionState, sessionVersion, aliceParameters.create());
            }
            else
            {
                BobAxolotlParameters.Builder bobParameters = BobAxolotlParameters.newBuilder();

                bobParameters.setOurIdentityKey(parameters.getOurIdentityKey())
                             .setOurRatchetKey(parameters.getOurRatchetKey())
                             .setOurSignedPreKey(parameters.getOurBaseKey())
                             .setOurOneTimePreKey(May<ECKeyPair>.NoValue)
                             .setTheirBaseKey(parameters.getTheirBaseKey())
                             .setTheirIdentityKey(parameters.getTheirIdentityKey());

                RatchetingSession.initializeSession(sessionState, sessionVersion, bobParameters.create());
            }
        }
        public SessionRecord(byte[] serialized)
        {
            RecordStructure record = RecordStructure.ParseFrom(serialized);
            this.sessionState = new SessionState(record.CurrentSession);
            this.fresh = false;

            foreach (SessionStructure previousStructure in record.PreviousSessionsList)
            {
                previousStates.AddLast(new SessionState(previousStructure)); // add -> AddLast (java)
            }
        }
        public static void initializeSession(SessionState sessionState,
                                             uint sessionVersion,
                                             AliceAxolotlParameters parameters)

        {
            try
            {
                sessionState.setSessionVersion(sessionVersion);
                sessionState.setRemoteIdentityKey(parameters.getTheirIdentityKey());
                sessionState.setLocalIdentityKey(parameters.getOurIdentityKey().getPublicKey());

                ECKeyPair sendingRatchetKey = Curve.generateKeyPair();
                MemoryStream secrets = new MemoryStream();

                if (sessionVersion >= 3)
                {
                    byte[] discontinuityBytes = getDiscontinuityBytes();
                    secrets.Write(discontinuityBytes, 0, discontinuityBytes.Length);
                }

                byte[] agree1 = Curve.calculateAgreement(parameters.getTheirSignedPreKey(),
                                                       parameters.getOurIdentityKey().getPrivateKey());
                byte[] agree2 = Curve.calculateAgreement(parameters.getTheirIdentityKey().getPublicKey(),
                                                        parameters.getOurBaseKey().getPrivateKey());
                byte[] agree3 = Curve.calculateAgreement(parameters.getTheirSignedPreKey(),
                                                       parameters.getOurBaseKey().getPrivateKey());

                secrets.Write(agree1, 0, agree1.Length);
                secrets.Write(agree2, 0, agree2.Length);
                secrets.Write(agree3, 0, agree3.Length);


                if (sessionVersion >= 3 && parameters.getTheirOneTimePreKey().HasValue)
                {
                    byte[] agree4 = Curve.calculateAgreement(parameters.getTheirOneTimePreKey().ForceGetValue(),
                                                           parameters.getOurBaseKey().getPrivateKey());
                    secrets.Write(agree4, 0, agree4.Length);
                }

                DerivedKeys derivedKeys = calculateDerivedKeys(sessionVersion, secrets.ToArray());
                Pair<RootKey, ChainKey> sendingChain = derivedKeys.getRootKey().createChain(parameters.getTheirRatchetKey(), sendingRatchetKey);

                sessionState.addReceiverChain(parameters.getTheirRatchetKey(), derivedKeys.getChainKey());
                sessionState.setSenderChain(sendingRatchetKey, sendingChain.second());
                sessionState.setRootKey(sendingChain.first());
            }
            catch (IOException e)
            {
                throw new Exception(e.Message);
            }
        }
		private MessageKeys getOrCreateMessageKeys(SessionState sessionState,
												   ECPublicKey theirEphemeral,
												   ChainKey chainKey, uint counter)

		{
			if (chainKey.getIndex() > counter)
			{
				if (sessionState.hasMessageKeys(theirEphemeral, counter))
				{
					return sessionState.removeMessageKeys(theirEphemeral, counter);
				}
				else
				{
					throw new DuplicateMessageException($"Received message with old counter: {chainKey.getIndex()}  , {counter}");
				}
			}

			//Avoiding a uint overflow
			uint chainKeyIndex = chainKey.getIndex();
			if ((counter > chainKeyIndex) && (counter - chainKeyIndex > 2000))
			{
				throw new InvalidMessageException("Over 2000 messages into the future!");
			}

			while (chainKey.getIndex() < counter)
			{
				MessageKeys messageKeys = chainKey.getMessageKeys();
				sessionState.setMessageKeys(theirEphemeral, messageKeys);
				chainKey = chainKey.getNextChainKey();
			}

			sessionState.setReceiverChainKey(theirEphemeral, chainKey.getNextChainKey());
			return chainKey.getMessageKeys();
		}
		private ChainKey getOrCreateChainKey(SessionState sessionState, ECPublicKey theirEphemeral)

		{
			try
			{
				if (sessionState.hasReceiverChain(theirEphemeral))
				{
					return sessionState.getReceiverChainKey(theirEphemeral);
				}
				else
				{
					RootKey rootKey = sessionState.getRootKey();
					ECKeyPair ourEphemeral = sessionState.getSenderRatchetKeyPair();
					Pair<RootKey, ChainKey> receiverChain = rootKey.createChain(theirEphemeral, ourEphemeral);
					ECKeyPair ourNewEphemeral = Curve.generateKeyPair();
					Pair<RootKey, ChainKey> senderChain = receiverChain.first().createChain(theirEphemeral, ourNewEphemeral);

					sessionState.setRootKey(senderChain.first());
					sessionState.addReceiverChain(theirEphemeral, receiverChain.second());
					sessionState.setPreviousCounter(Math.Max(sessionState.getSenderChainKey().getIndex() - 1, 0));
					sessionState.setSenderChain(ourNewEphemeral, senderChain.second());

					return receiverChain.second();
				}
			}
			catch (InvalidKeyException e)
			{
				throw new InvalidMessageException(e);
			}
		}
		private byte[] decrypt(SessionState sessionState, WhisperMessage ciphertextMessage)
		{
			if (!sessionState.hasSenderChain())
			{
				throw new InvalidMessageException("Uninitialized session!");
			}

			if (ciphertextMessage.getMessageVersion() != sessionState.getSessionVersion())
			{
				throw new InvalidMessageException($"Message version {ciphertextMessage.getMessageVersion()}, but session version {sessionState.getSessionVersion()}");
			}

			uint messageVersion = ciphertextMessage.getMessageVersion();
			ECPublicKey theirEphemeral = ciphertextMessage.getSenderRatchetKey();
			uint counter = ciphertextMessage.getCounter();
			ChainKey chainKey = getOrCreateChainKey(sessionState, theirEphemeral);
			MessageKeys messageKeys = getOrCreateMessageKeys(sessionState, theirEphemeral,
																	  chainKey, counter);

		/*	ciphertextMessage.verifyMac(messageVersion,
											sessionState.getRemoteIdentityKey(),
											sessionState.getLocalIdentityKey(),
											messageKeys.getMacKey());*/

			byte[] plaintext = getPlaintext(messageVersion, messageKeys, ciphertextMessage.getBody());

			sessionState.clearUnacknowledgedPreKeyMessage();

			return plaintext;
		}
		private byte[] decrypt(SessionRecord sessionRecord, WhisperMessage ciphertext)
		{
			lock (SESSION_LOCK)
			{
				IEnumerator<SessionState> previousStates = sessionRecord.getPreviousSessionStates().GetEnumerator(); //iterator
				LinkedList<Exception> exceptions = new LinkedList<Exception>();

				try
				{
					SessionState sessionState = new SessionState(sessionRecord.getSessionState());
					byte[] plaintext = decrypt(sessionState, ciphertext);

					sessionRecord.setState(sessionState);
					return plaintext;
				}
				catch (InvalidMessageException e)
				{
					exceptions.AddLast(e); // add (java default behavioir addlast)
				}

				while (previousStates.MoveNext()) //hasNext();
				{
					try
					{
						SessionState promotedState = new SessionState(previousStates.Current); //.next()
						byte[] plaintext = decrypt(promotedState, ciphertext);

						sessionRecord.getPreviousSessionStates().Remove(previousStates.Current); // previousStates.remove()
						sessionRecord.promoteState(promotedState);

						return plaintext;
					}
					catch (InvalidMessageException e)
					{
						exceptions.AddLast(e);
					}
				}

				throw new InvalidMessageException("No valid sessions.", exceptions);
			}
		}
 public SessionRecord(SessionState sessionState)
 {
     this.sessionState = sessionState;
     this.fresh = false;
 }
 public void setState(SessionState sessionState)
 {
     this.sessionState = sessionState;
 }
        public void promoteState(SessionState promotedState)
        {
            this.previousStates.AddFirst(sessionState);
            this.sessionState = promotedState;

            if (previousStates.Count > ARCHIVED_STATES_MAX_LENGTH)
            {
                previousStates.RemoveLast();
            }
        }
		public SessionState(SessionState copy)
		{
			this.sessionStructure = copy.sessionStructure.ToBuilder().Build();
		}
        public void testRatchetingSessionAsAlice()
        {
            byte[] bobPublic =
            {
                0x05, 0x2c, 0xb4, 0x97, 0x76,
                0xb8, 0x77, 0x02, 0x05, 0x74,
                0x5a, 0x3a, 0x6e, 0x24, 0xf5,
                0x79, 0xcd, 0xb4, 0xba, 0x7a,
                0x89, 0x04, 0x10, 0x05, 0x92,
                0x8e, 0xbb, 0xad, 0xc9, 0xc0,
                0x5a, 0xd4, 0x58
            };

            byte[] bobIdentityPublic =
            {
                0x05, 0xf1, 0xf4, 0x38, 0x74,
                0xf6, 0x96, 0x69, 0x56, 0xc2,
                0xdd, 0x47, 0x3f, 0x8f, 0xa1,
                0x5a, 0xde, 0xb7, 0x1d, 0x1c,
                0xb9, 0x91, 0xb2, 0x34, 0x16,
                0x92, 0x32, 0x4c, 0xef, 0xb1,
                0xc5, 0xe6, 0x26
            };

            byte[] aliceBasePublic =
            {
                0x05, 0x47, 0x2d, 0x1f, 0xb1,
                0xa9, 0x86, 0x2c, 0x3a, 0xf6,
                0xbe, 0xac, 0xa8, 0x92, 0x02,
                0x77, 0xe2, 0xb2, 0x6f, 0x4a,
                0x79, 0x21, 0x3e, 0xc7, 0xc9,
                0x06, 0xae, 0xb3, 0x5e, 0x03,
                0xcf, 0x89, 0x50
            };

            byte[] aliceBasePrivate =
            {
                0x11, 0xae, 0x7c, 0x64, 0xd1,
                0xe6, 0x1c, 0xd5, 0x96, 0xb7,
                0x6a, 0x0d, 0xb5, 0x01, 0x26,
                0x73, 0x39, 0x1c, 0xae, 0x66,
                0xed, 0xbf, 0xcf, 0x07, 0x3b,
                0x4d, 0xa8, 0x05, 0x16, 0xa4,
                0x74, 0x49
            };

            byte[] aliceEphemeralPublic =
            {
                0x05, 0x6c, 0x3e, 0x0d, 0x1f,
                0x52, 0x02, 0x83, 0xef, 0xcc,
                0x55, 0xfc, 0xa5, 0xe6, 0x70,
                0x75, 0xb9, 0x04, 0x00, 0x7f,
                0x18, 0x81, 0xd1, 0x51, 0xaf,
                0x76, 0xdf, 0x18, 0xc5, 0x1d,
                0x29, 0xd3, 0x4b
            };

            byte[] aliceEphemeralPrivate =
            {
                0xd1, 0xba, 0x38, 0xce, 0xa9,
                0x17, 0x43, 0xd3, 0x39, 0x39,
                0xc3, 0x3c, 0x84, 0x98, 0x65,
                0x09, 0x28, 0x01, 0x61, 0xb8,
                0xb6, 0x0f, 0xc7, 0x87, 0x0c,
                0x59, 0x9c, 0x1d, 0x46, 0x20,
                0x12, 0x48
            };

            byte[] aliceIdentityPublic =
            {
                0x05, 0xb4, 0xa8, 0x45, 0x56,
                0x60, 0xad, 0xa6, 0x5b, 0x40,
                0x10, 0x07, 0xf6, 0x15, 0xe6,
                0x54, 0x04, 0x17, 0x46, 0x43,
                0x2e, 0x33, 0x39, 0xc6, 0x87,
                0x51, 0x49, 0xbc, 0xee, 0xfc,
                0xb4, 0x2b, 0x4a
            };

            byte[] aliceIdentityPrivate =
            {
                0x90, 0x40, 0xf0, 0xd4, 0xe0,
                0x9c, 0xf3, 0x8f, 0x6d, 0xc7,
                0xc1, 0x37, 0x79, 0xc9, 0x08,
                0xc0, 0x15, 0xa1, 0xda, 0x4f,
                0xa7, 0x87, 0x37, 0xa0, 0x80,
                0xeb, 0x0a, 0x6f, 0x4f, 0x5f,
                0x8f, 0x58
            };

            byte[] receiverChain =
            {
                0xd2, 0x2f, 0xd5, 0x6d, 0x3f,
                0xec, 0x81, 0x9c, 0xf4, 0xc3,
                0xd5, 0x0c, 0x56, 0xed, 0xfb,
                0x1c, 0x28, 0x0a, 0x1b, 0x31,
                0x96, 0x45, 0x37, 0xf1, 0xd1,
                0x61, 0xe1, 0xc9, 0x31, 0x48,
                0xe3, 0x6b
            };

            IdentityKey bobIdentityKey = new IdentityKey(bobIdentityPublic, 0);
            ECPublicKey bobEphemeralPublicKey = Curve.decodePoint(bobPublic, 0);
            ECPublicKey bobBasePublicKey = bobEphemeralPublicKey;
            ECPublicKey aliceBasePublicKey = Curve.decodePoint(aliceBasePublic, 0);
            ECPrivateKey aliceBasePrivateKey = Curve.decodePrivatePoint(aliceBasePrivate);
            ECKeyPair aliceBaseKey = new ECKeyPair(aliceBasePublicKey, aliceBasePrivateKey);
            ECPublicKey aliceEphemeralPublicKey = Curve.decodePoint(aliceEphemeralPublic, 0);
            ECPrivateKey aliceEphemeralPrivateKey = Curve.decodePrivatePoint(aliceEphemeralPrivate);
            ECKeyPair aliceEphemeralKey = new ECKeyPair(aliceEphemeralPublicKey, aliceEphemeralPrivateKey);
            IdentityKey aliceIdentityPublicKey = new IdentityKey(aliceIdentityPublic, 0);
            ECPrivateKey aliceIdentityPrivateKey = Curve.decodePrivatePoint(aliceIdentityPrivate);
            IdentityKeyPair aliceIdentityKey = new IdentityKeyPair(aliceIdentityPublicKey, aliceIdentityPrivateKey);

            SessionState session = new SessionState();

            AliceAxolotlParameters parameters = AliceAxolotlParameters.newBuilder()
                .setOurBaseKey(aliceBaseKey)
                .setOurIdentityKey(aliceIdentityKey)
                .setTheirIdentityKey(bobIdentityKey)
                .setTheirSignedPreKey(bobBasePublicKey)
                .setTheirRatchetKey(bobEphemeralPublicKey)
                .setTheirOneTimePreKey(May<ECPublicKey>.NoValue)
                .create();

            RatchetingSession.initializeSession(session, 2, parameters);

            Assert.AreEqual(session.getLocalIdentityKey(), aliceIdentityKey.getPublicKey());
            Assert.AreEqual(session.getRemoteIdentityKey(), bobIdentityKey);
            CollectionAssert.AreEqual(session.getReceiverChainKey(bobEphemeralPublicKey).getKey(), receiverChain);
        }
Exemple #13
0
 public SessionState(SessionState copy)
 {
     this.sessionStructure = copy.sessionStructure.ToBuilder().Build();
 }