/// <summary>
        /// Decrypt a SenderKey group message.
        /// </summary>
        /// <param name="senderKeyMessageBytes">The received ciphertext.</param>
        /// <param name="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.</param>
        /// <returns>Plaintext</returns>
        /// <exception cref="LegacyMessageException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        /// <exception cref="DuplicateMessageException"></exception>
        /// <exception cref="NoSessionException"></exception>
        public byte[] decrypt(byte[] senderKeyMessageBytes, DecryptionCallback callback)
        {
            lock (LOCK)
            {
                try
                {
                    SenderKeyRecord record = senderKeyStore.loadSenderKey(senderKeyId);

                    if (record.isEmpty())
                    {
                        throw new NoSessionException("No sender key for: " + senderKeyId);
                    }

                    SenderKeyMessage senderKeyMessage = new SenderKeyMessage(senderKeyMessageBytes);
                    SenderKeyState   senderKeyState   = record.getSenderKeyState(senderKeyMessage.getKeyId());

                    senderKeyMessage.verifySignature(senderKeyState.getSigningKeyPublic());

                    SenderMessageKey senderKey = getSenderKey(senderKeyState, senderKeyMessage.getIteration());

                    byte[] plaintext = getPlainText(senderKey.getIv(), senderKey.getCipherKey(), senderKeyMessage.getCipherText());

                    callback.handlePlaintext(plaintext);

                    senderKeyStore.storeSenderKey(senderKeyId, record);

                    return(plaintext);
                }
                catch (Exception e) when(e is InvalidKeyException || e is InvalidKeyIdException)
                {
                    throw new InvalidMessageException(e);
                }
            }
        }
Example #2
0
        /**
         * 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);
            }
        }
Example #3
0
        /**
         * Decrypt a message.
         *
         * @param  ciphertext The {@link PreKeyWhisperMessage} 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 InvalidKeyIdException when there is no local {@link org.whispersystems.libaxolotl.state.PreKeyRecord}
         *                               that corresponds to the PreKey ID in the message.
         * @throws InvalidKeyException when the message is formatted incorrectly.
         * @throws UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
         */
        public byte[] decrypt(PreKeyWhisperMessage ciphertext, DecryptionCallback callback)

        {
            lock (SESSION_LOCK)
            {
                SessionRecord sessionRecord    = sessionStore.loadSession(remoteAddress);
                May <uint>    unsignedPreKeyId = sessionBuilder.process(sessionRecord, ciphertext);
                byte[]        plaintext        = decrypt(sessionRecord, ciphertext.getWhisperMessage());

                callback.handlePlaintext(plaintext);

                sessionStore.storeSession(remoteAddress, sessionRecord);

                if (unsignedPreKeyId.HasValue)
                {
                    preKeyStore.removePreKey(unsignedPreKeyId.ForceGetValue());
                }

                return(plaintext);
            }
        }
        /**
         * Decrypt a message.
         *
         * @param  ciphertext The {@link PreKeySignalMessage} 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 InvalidKeyIdException when there is no local {@link org.whispersystems.libsignal.state.PreKeyRecord}
         *                               that corresponds to the PreKey ID in the message.
         * @throws InvalidKeyException when the message is formatted incorrectly.
         * @throws UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
         */
        public byte[] decrypt(PreKeySignalMessage ciphertext, DecryptionCallback callback)
        {
            lock (SESSION_LOCK)
            {
                SessionRecord sessionRecord    = sessionStore.LoadSession(remoteAddress);
                May <uint>    unsignedPreKeyId = sessionBuilder.process(sessionRecord, ciphertext);
                byte[]        plaintext        = decrypt(sessionRecord, ciphertext.getSignalMessage());

                identityKeyStore.SaveIdentity(remoteAddress, sessionRecord.getSessionState().getRemoteIdentityKey());

                callback.handlePlaintext(plaintext);

                sessionStore.StoreSession(remoteAddress, sessionRecord);

                if (unsignedPreKeyId.HasValue)
                {
                    preKeyStore.RemovePreKey(unsignedPreKeyId.ForceGetValue());
                }

                return(plaintext);
            }
        }
Example #5
0
        /**
         * Decrypt a SenderKey group message.
         *
         * @param senderKeyMessageBytes The received ciphertext.
         * @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 Plaintext
         * @throws LegacyMessageException
         * @throws InvalidMessageException
         * @throws DuplicateMessageException
         */
        public byte[] decrypt(byte[] senderKeyMessageBytes, DecryptionCallback callback)
        {
            lock (LOCK)
            {
                try
                {
                    SenderKeyRecord record = senderKeyStore.loadSenderKey(senderKeyId);

                    if (record.isEmpty())
                    {
                        throw new NoSessionException("No sender key for: " + senderKeyId);
                    }

                    SenderKeyMessage senderKeyMessage = new SenderKeyMessage(senderKeyMessageBytes);
                    SenderKeyState senderKeyState = record.getSenderKeyState(senderKeyMessage.getKeyId());

                    senderKeyMessage.verifySignature(senderKeyState.getSigningKeyPublic());

                    SenderMessageKey senderKey = getSenderKey(senderKeyState, senderKeyMessage.getIteration());

                    byte[] plaintext = getPlainText(senderKey.getIv(), senderKey.getCipherKey(), senderKeyMessage.getCipherText());

                    callback.handlePlaintext(plaintext);

                    senderKeyStore.storeSenderKey(senderKeyId, record);

                    return plaintext;
                }
                catch (InvalidKeyException e)
                {
                    throw new InvalidMessageException(e);
                }
                catch (InvalidKeyIdException e)
                {
                    throw new InvalidMessageException(e);
                }
            }
        }
        /**
         * Decrypt a message.
         *
         * @param  ciphertext The {@link SignalMessage} 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(SignalMessage 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);

                if (!identityKeyStore.IsTrustedIdentity(remoteAddress, sessionRecord.getSessionState().getRemoteIdentityKey(), Direction.RECEIVING))
                {
                    throw new UntrustedIdentityException(remoteAddress.Name, sessionRecord.getSessionState().getRemoteIdentityKey());
                }

                callback.handlePlaintext(plaintext);

                sessionStore.StoreSession(remoteAddress, sessionRecord);

                return(plaintext);
            }
        }
Example #7
0
        /**
         * Decrypt a SenderKey group message.
         *
         * @param senderKeyMessageBytes The received ciphertext.
         * @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 Plaintext
         * @throws LegacyMessageException
         * @throws InvalidMessageException
         * @throws DuplicateMessageException
         */

        public byte[] Decrypt(byte[] senderKeyMessageBytes, DecryptionCallback callback)
        {
            lock (LOCK)
            {
                try
                {
                    SenderKeyRecord record = senderKeyStore.LoadSenderKey(senderKeyId);

                    if (record.IsEmpty())
                    {
                        throw new NoSessionException("No Sender Key For: " + senderKeyId);
                    }

                    SenderKeyMessage senderKeyMessage = new SenderKeyMessage(senderKeyMessageBytes);
                    SenderKeyState   senderKeyState   = record.GetSenderKeyState(senderKeyMessage.GetKeyId());
                    senderKeyMessage.VerifySignature(senderKeyState.GetSigningKeyPublic());

                    SenderMessageKey senderKey = GetSenderKey(senderKeyState, senderKeyMessage.GetIteration());
                    byte[]           plaintext = GetPlainText(senderKey.GetIv(), senderKey.GetCipherKey(), senderKeyMessage.GetCipherText());

                    callback.HandlePlaintext(plaintext);

                    senderKeyStore.StoreSenderKey(senderKeyId, record);

                    return(plaintext);
                }
                catch (InvalidKeyException e)
                {
                    throw new InvalidMessageException(e);
                }
                catch (InvalidKeyIdException e)
                {
                    throw new InvalidMessageException(e);
                }
            }
        }
		/**
         * 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 PreKeyWhisperMessage} 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 InvalidKeyIdException when there is no local {@link org.whispersystems.libaxolotl.state.PreKeyRecord}
         *                               that corresponds to the PreKey ID in the message.
         * @throws InvalidKeyException when the message is formatted incorrectly.
         * @throws UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
         */
		public byte[] decrypt(PreKeyWhisperMessage ciphertext, DecryptionCallback callback)

		{
			lock (SESSION_LOCK)
			{
				SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress);
				May<uint> unsignedPreKeyId = sessionBuilder.process(sessionRecord, ciphertext);
				byte[] plaintext = decrypt(sessionRecord, ciphertext.getWhisperMessage());

				callback.handlePlaintext(plaintext);

				sessionStore.StoreSession(remoteAddress, sessionRecord);

				if (unsignedPreKeyId.HasValue)
				{
					preKeyStore.RemovePreKey(unsignedPreKeyId.ForceGetValue());
				}

				return plaintext;
			}
		}