public PreKeyWhisperMessage(uint messageVersion, uint registrationId, May<uint> preKeyId,
                                    uint signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey,
                                    WhisperMessage message)
        {
            this.version = messageVersion;
            this.registrationId = registrationId;
            this.preKeyId = preKeyId;
            this.signedPreKeyId = signedPreKeyId;
            this.baseKey = baseKey;
            this.identityKey = identityKey;
            this.message = message;

            WhisperProtos.PreKeyWhisperMessage.Builder builder =
                WhisperProtos.PreKeyWhisperMessage.CreateBuilder()
                                                  .SetSignedPreKeyId(signedPreKeyId)
                                                  .SetBaseKey(ByteString.CopyFrom(baseKey.serialize()))
                                                  .SetIdentityKey(ByteString.CopyFrom(identityKey.serialize()))
                                                  .SetMessage(ByteString.CopyFrom(message.serialize()))
                                                  .SetRegistrationId(registrationId);

            if (preKeyId.HasValue) // .isPresent()
            {
                builder.SetPreKeyId(preKeyId.ForceGetValue()); // get()
            }

            byte[] versionBytes = { ByteUtil.intsToByteHighAndLow((int)this.version, (int)CURRENT_VERSION) };
            byte[] messageBytes = builder.Build().ToByteArray();

            this.serialized = ByteUtil.combine(versionBytes, messageBytes);
        }
Example #2
0
        public PreKeyWhisperMessage(uint messageVersion, uint registrationId, May <uint> preKeyId,
                                    uint signedPreKeyId, ECPublicKey baseKey, IdentityKey identityKey,
                                    WhisperMessage message)
        {
            this.version        = messageVersion;
            this.registrationId = registrationId;
            this.preKeyId       = preKeyId;
            this.signedPreKeyId = signedPreKeyId;
            this.baseKey        = baseKey;
            this.identityKey    = identityKey;
            this.message        = message;

            WhisperProtos.PreKeyWhisperMessage.Builder builder =
                WhisperProtos.PreKeyWhisperMessage.CreateBuilder()
                .SetSignedPreKeyId(signedPreKeyId)
                .SetBaseKey(ByteString.CopyFrom(baseKey.serialize()))
                .SetIdentityKey(ByteString.CopyFrom(identityKey.serialize()))
                .SetMessage(ByteString.CopyFrom(message.serialize()))
                .SetRegistrationId(registrationId);

            if (preKeyId.HasValue)                             // .isPresent()
            {
                builder.SetPreKeyId(preKeyId.ForceGetValue()); // get()
            }

            byte[] versionBytes = { ByteUtil.intsToByteHighAndLow((int)this.version, (int)CURRENT_VERSION) };
            byte[] messageBytes = builder.Build().ToByteArray();

            this.serialized = ByteUtil.combine(versionBytes, messageBytes);
        }
        public PreKeyWhisperMessage(byte[] serialized)
        {
            try
            {
                this.version = (uint)ByteUtil.highBitsToInt(serialized[0]);

                if (this.version > CiphertextMessage.CURRENT_VERSION)
                {
                    throw new InvalidVersionException("Unknown version: " + this.version);
                }

                WhisperProtos.PreKeyWhisperMessage preKeyWhisperMessage
                    = WhisperProtos.PreKeyWhisperMessage.ParseFrom(ByteString.CopyFrom(serialized, 1,
                                                                                       serialized.Length - 1));

                if ((version == 2 && !preKeyWhisperMessage.HasPreKeyId) ||
                    (version == 3 && !preKeyWhisperMessage.HasSignedPreKeyId) ||
                    !preKeyWhisperMessage.HasBaseKey ||
                    !preKeyWhisperMessage.HasIdentityKey ||
                    !preKeyWhisperMessage.HasMessage)
                {
                    throw new InvalidMessageException("Incomplete message.");
                }

                this.serialized = serialized;
                this.registrationId = preKeyWhisperMessage.RegistrationId;
                this.preKeyId = preKeyWhisperMessage.HasPreKeyId ? new May<uint>(preKeyWhisperMessage.PreKeyId) : May<uint>.NoValue;
                this.signedPreKeyId = preKeyWhisperMessage.HasSignedPreKeyId ? preKeyWhisperMessage.SignedPreKeyId : uint.MaxValue; // -1
                this.baseKey = Curve.decodePoint(preKeyWhisperMessage.BaseKey.ToByteArray(), 0);
                this.identityKey = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.IdentityKey.ToByteArray(), 0));
                this.message = new WhisperMessage(preKeyWhisperMessage.Message.ToByteArray());
            }
            catch (Exception e)
            {
                //(InvalidProtocolBufferException | InvalidKeyException | LegacyMessage
                throw new InvalidMessageException(e.Message);
            }
        }
Example #4
0
        public PreKeyWhisperMessage(byte[] serialized)
        {
            try
            {
                this.version = (uint)ByteUtil.highBitsToInt(serialized[0]);

                if (this.version > CiphertextMessage.CURRENT_VERSION)
                {
                    throw new InvalidVersionException("Unknown version: " + this.version);
                }

                WhisperProtos.PreKeyWhisperMessage preKeyWhisperMessage
                    = WhisperProtos.PreKeyWhisperMessage.ParseFrom(ByteString.CopyFrom(serialized, 1,
                                                                                       serialized.Length - 1));

                if ((version == 2 && !preKeyWhisperMessage.HasPreKeyId) ||
                    (version == 3 && !preKeyWhisperMessage.HasSignedPreKeyId) ||
                    !preKeyWhisperMessage.HasBaseKey ||
                    !preKeyWhisperMessage.HasIdentityKey ||
                    !preKeyWhisperMessage.HasMessage)
                {
                    throw new InvalidMessageException("Incomplete message.");
                }

                this.serialized     = serialized;
                this.registrationId = preKeyWhisperMessage.RegistrationId;
                this.preKeyId       = preKeyWhisperMessage.HasPreKeyId ? new May <uint>(preKeyWhisperMessage.PreKeyId) : May <uint> .NoValue;
                this.signedPreKeyId = preKeyWhisperMessage.HasSignedPreKeyId ? preKeyWhisperMessage.SignedPreKeyId : uint.MaxValue; // -1
                this.baseKey        = Curve.decodePoint(preKeyWhisperMessage.BaseKey.ToByteArray(), 0);
                this.identityKey    = new IdentityKey(Curve.decodePoint(preKeyWhisperMessage.IdentityKey.ToByteArray(), 0));
                this.message        = new WhisperMessage(preKeyWhisperMessage.Message.ToByteArray());
            }
            catch (Exception e)
            {
                //(InvalidProtocolBufferException | InvalidKeyException | LegacyMessage
                throw new InvalidMessageException(e.Message);
            }
        }
		/**
         * Encrypt a message.
         *
         * @param  paddedMessage The plaintext message bytes, optionally padded to a constant multiple.
         * @return A ciphertext message encrypted to the recipient+device tuple.
         */
		public CiphertextMessage encrypt(byte[] paddedMessage)
		{
			lock (SESSION_LOCK)
			{
				SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress);
				SessionState sessionState = sessionRecord.getSessionState();
				ChainKey chainKey = sessionState.getSenderChainKey();
				MessageKeys messageKeys = chainKey.getMessageKeys();
				ECPublicKey senderEphemeral = sessionState.getSenderRatchetKey();
				uint previousCounter = sessionState.getPreviousCounter();
				uint sessionVersion = sessionState.getSessionVersion();

				byte[] ciphertextBody = getCiphertext(sessionVersion, messageKeys, paddedMessage);
				CiphertextMessage ciphertextMessage = new WhisperMessage(sessionVersion, messageKeys.getMacKey(),
																		 senderEphemeral, chainKey.getIndex(),
																		 previousCounter, ciphertextBody,
																		 sessionState.getLocalIdentityKey(),
																		 sessionState.getRemoteIdentityKey());

				if (sessionState.hasUnacknowledgedPreKeyMessage())
				{
					SessionState.UnacknowledgedPreKeyMessageItems items = sessionState.getUnacknowledgedPreKeyMessageItems();
					uint localRegistrationId = sessionState.GetLocalRegistrationId();

					ciphertextMessage = new PreKeyWhisperMessage(sessionVersion, localRegistrationId, items.getPreKeyId(),
																 items.getSignedPreKeyId(), items.getBaseKey(),
																 sessionState.getLocalIdentityKey(),
																 (WhisperMessage)ciphertextMessage);
				}

				sessionState.setSenderChainKey(chainKey.getNextChainKey());
				sessionStore.StoreSession(remoteAddress, sessionRecord);
				return ciphertextMessage;
			}
		}
		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);
			}
		}
		/**
         * Decrypt a message.
         *
         * @param  ciphertext The {@link WhisperMessage} to decrypt.
         * @param  callback   A callback that is triggered after decryption is complete,
         *                    but before the updated session state has been committed to the session
         *                    DB.  This allows some implementations to store the committed plaintext
         *                    to a DB first, in case they are concerned with a crash happening between
         *                    the time the session state is updated but before they're able to store
         *                    the plaintext to disk.
         *
         * @return The plaintext.
         * @throws InvalidMessageException if the input is not valid ciphertext.
         * @throws DuplicateMessageException if the input is a message that has already been received.
         * @throws LegacyMessageException if the input is a message formatted by a protocol version that
         *                                is no longer supported.
         * @throws NoSessionException if there is no established session for this contact.
         */
		public byte[] decrypt(WhisperMessage ciphertext, DecryptionCallback callback)

		{
			lock (SESSION_LOCK)
			{

				if (!sessionStore.ContainsSession(remoteAddress))
				{
					throw new NoSessionException($"No session for: {remoteAddress}");
				}

				SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress);
				byte[] plaintext = decrypt(sessionRecord, ciphertext);

				callback.handlePlaintext(plaintext);

				sessionStore.StoreSession(remoteAddress, sessionRecord);

				return plaintext;
			}
		}
		/**
         * Decrypt a message.
         *
         * @param  ciphertext The {@link WhisperMessage} to decrypt.
         *
         * @return The plaintext.
         * @throws InvalidMessageException if the input is not valid ciphertext.
         * @throws DuplicateMessageException if the input is a message that has already been received.
         * @throws LegacyMessageException if the input is a message formatted by a protocol version that
         *                                is no longer supported.
         * @throws NoSessionException if there is no established session for this contact.
         */
		public byte[] decrypt(WhisperMessage ciphertext)

		{
			return decrypt(ciphertext, new NullDecryptionCallback());
		}