public OutgoingPushMessage encrypt(AxolotlAddress destination, byte[] unpaddedMessage, bool legacy)
        {
            SessionCipher sessionCipher = new SessionCipher(axolotlStore, destination);
            PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
            CiphertextMessage message = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
            uint remoteRegistrationId = sessionCipher.getRemoteRegistrationId();
            String body = Base64.encodeBytes(message.serialize());

            uint type;

            switch (message.getType())
            {
                case CiphertextMessage.PREKEY_TYPE: type = (uint)Envelope.Types.Type.PREKEY_BUNDLE; break; // todo check
                case CiphertextMessage.WHISPER_TYPE: type = (uint)Envelope.Types.Type.CIPHERTEXT; break; // todo check
                default: throw new Exception("Bad type: " + message.getType());
            }

            return new OutgoingPushMessage(type, destination.DeviceId, remoteRegistrationId, legacy ? body : null, legacy ? null : body);
        }
        private byte[] decrypt(TextSecureEnvelope envelope, byte[] ciphertext)

        {
            AxolotlAddress sourceAddress = new AxolotlAddress(envelope.getSource(), envelope.getSourceDevice());
            SessionCipher sessionCipher = new SessionCipher(axolotlStore, sourceAddress);

            byte[] paddedMessage;

            if (envelope.isPreKeyWhisperMessage())
            {
                paddedMessage = sessionCipher.decrypt(new PreKeyWhisperMessage(ciphertext));
            }
            else if (envelope.isWhisperMessage())
            {
                paddedMessage = sessionCipher.decrypt(new WhisperMessage(ciphertext));
            }
            else
            {
                throw new InvalidMessageException("Unknown type: " + envelope.getType());
            }

            PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
            return transportDetails.getStrippedPaddingMessageBody(paddedMessage);
        }