Java Code Examples for org.whispersystems.libsignal.UntrustedIdentityException

The following examples show how to use org.whispersystems.libsignal.UntrustedIdentityException. These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source Project: bcm-android   Author: bcmapp   File: SignalServiceCipher.java    License: GNU General Public License v3.0 6 votes vote down vote up
public OutgoingPushMessage encrypt(SignalProtocolAddress destination, byte[] unpaddedMessage, PushPurpose pushPurpose)
    throws UntrustedIdentityException
{
  SessionCipher        sessionCipher        = new SessionCipher(signalProtocolStore, destination);
  PushTransportDetails transportDetails     = new PushTransportDetails(sessionCipher.getSessionVersion());
  CiphertextMessage    message              = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
  int                  remoteRegistrationId = sessionCipher.getRemoteRegistrationId();
  String               body                 = Base64.encodeBytes(message.serialize());

  int type;

  switch (message.getType()) {
    case CiphertextMessage.PREKEY_TYPE:  type = Type.PREKEY_BUNDLE_VALUE; break;
    case CiphertextMessage.WHISPER_TYPE: type = Type.CIPHERTEXT_VALUE;    break;
    default: throw new AssertionError("Bad type: " + message.getType());
  }

  return new OutgoingPushMessage(type, destination.getDeviceId(), remoteRegistrationId, body, pushPurpose);
}
 
Example #2
Source Project: Silence   Author: SilenceIM   File: SessionBuilder.java    License: GNU General Public License v3.0 6 votes vote down vote up
/**
 * Build a new session from a {@link org.whispersystems.libsignal.protocol.KeyExchangeMessage}
 * received from a remote client.
 *
 * @param message The received KeyExchangeMessage.
 * @return The KeyExchangeMessage to respond with, or null if no response is necessary.
 * @throws InvalidKeyException if the received KeyExchangeMessage is badly formatted.
 */
public KeyExchangeMessage process(KeyExchangeMessage message)
    throws InvalidKeyException, UntrustedIdentityException, StaleKeyExchangeException
{
  synchronized (SessionCipher.SESSION_LOCK) {
    if (!identityKeyStore.isTrustedIdentity(remoteAddress, message.getIdentityKey(), IdentityKeyStore.Direction.SENDING)) {
      throw new UntrustedIdentityException(remoteAddress.getName(), message.getIdentityKey());
    }

    KeyExchangeMessage responseMessage = null;

    if (message.isInitiate()) responseMessage = processInitiate(message);
    else                      processResponse(message);

    return responseMessage;
  }
}
 
Example #3
Source Project: Silence   Author: SilenceIM   File: SmsCipher.java    License: GNU General Public License v3.0 6 votes vote down vote up
public IncomingTextMessage decrypt(Context context, IncomingTextMessage message)
    throws LegacyMessageException, InvalidMessageException, DuplicateMessageException,
           NoSessionException, UntrustedIdentityException
{
  try {
    byte[]        decoded       = transportDetails.getDecodedMessage(message.getMessageBody().getBytes());
    SignalMessage signalMessage = new SignalMessage(decoded);
    SessionCipher sessionCipher = new SessionCipher(signalProtocolStore, new SignalProtocolAddress(message.getSender(), 1));
    byte[]        padded        = sessionCipher.decrypt(signalMessage);
    byte[]        plaintext     = transportDetails.getStrippedPaddingMessageBody(padded);

    if (message.isEndSession() && "TERMINATE".equals(new String(plaintext))) {
      signalProtocolStore.deleteSession(new SignalProtocolAddress(message.getSender(), 1));
    }

    return message.withMessageBody(new String(plaintext));
  } catch (IOException | IllegalArgumentException | NullPointerException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #4
Source Project: Silence   Author: SilenceIM   File: SmsCipher.java    License: GNU General Public License v3.0 6 votes vote down vote up
public IncomingEncryptedMessage decrypt(Context context, IncomingPreKeyBundleMessage message)
    throws InvalidVersionException, InvalidMessageException, DuplicateMessageException,
           UntrustedIdentityException, LegacyMessageException
{
  try {
    byte[]              decoded       = transportDetails.getDecodedMessage(message.getMessageBody().getBytes());
    PreKeySignalMessage preKeyMessage = new PreKeySignalMessage(decoded);
    SessionCipher       sessionCipher = new SessionCipher(signalProtocolStore, new SignalProtocolAddress(message.getSender(), 1));
    byte[]              padded        = sessionCipher.decrypt(preKeyMessage);
    byte[]              plaintext     = transportDetails.getStrippedPaddingMessageBody(padded);

    return new IncomingEncryptedMessage(message, new String(plaintext));
  } catch (IOException | InvalidKeyException | InvalidKeyIdException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #5
Source Project: Silence   Author: SilenceIM   File: SmsCipher.java    License: GNU General Public License v3.0 6 votes vote down vote up
public OutgoingTextMessage encrypt(OutgoingTextMessage message)
  throws NoSessionException, UntrustedIdentityException
{
  byte[] paddedBody      = transportDetails.getPaddedMessageBody(message.getMessageBody().getBytes());
  String recipientNumber = message.getRecipients().getPrimaryRecipient().getNumber();

  if (!signalProtocolStore.containsSession(new SignalProtocolAddress(recipientNumber, 1))) {
    throw new NoSessionException("No session for: " + recipientNumber);
  }

  SessionCipher     cipher            = new SessionCipher(signalProtocolStore, new SignalProtocolAddress(recipientNumber, 1));
  CiphertextMessage ciphertextMessage = cipher.encrypt(paddedBody);
  String            encodedCiphertext = new String(transportDetails.getEncodedMessage(ciphertextMessage.serialize()));

  if (ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE) {
    return new OutgoingPrekeyBundleMessage(message, encodedCiphertext);
  } else {
    return message.withBody(encodedCiphertext);
  }
}
 
Example #6
Source Project: Silence   Author: SilenceIM   File: SmsCipher.java    License: GNU General Public License v3.0 6 votes vote down vote up
public OutgoingKeyExchangeMessage process(Context context, IncomingKeyExchangeMessage message)
    throws UntrustedIdentityException, StaleKeyExchangeException,
           InvalidVersionException, LegacyMessageException, InvalidMessageException
{
  try {
    Recipients            recipients            = RecipientFactory.getRecipientsFromString(context, message.getSender(), false);
    SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(message.getSender(), 1);
    KeyExchangeMessage    exchangeMessage       = new KeyExchangeMessage(transportDetails.getDecodedMessage(message.getMessageBody().getBytes()));
    SessionBuilder        sessionBuilder        = new SessionBuilder(signalProtocolStore, signalProtocolAddress);

    KeyExchangeMessage response        = sessionBuilder.process(exchangeMessage);

    if (response != null) {
      byte[] serializedResponse = transportDetails.getEncodedMessage(response.serialize());
      return new OutgoingKeyExchangeMessage(recipients, new String(serializedResponse), message.getSubscriptionId());
    } else {
      return null;
    }
  } catch (IOException | InvalidKeyException e) {
    throw new InvalidMessageException(e);
  }
}
 
Example #7
Source Project: Silence   Author: SilenceIM   File: SmsSendJob.java    License: GNU General Public License v3.0 6 votes vote down vote up
@Override
public void onSend(MasterSecret masterSecret) throws NoSuchMessageException {
  EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
  SmsMessageRecord      record   = database.getMessage(masterSecret, messageId);

  try {
    Log.w(TAG, "Sending message: " + messageId);

    deliver(masterSecret, record);
  } catch (UndeliverableMessageException ude) {
    Log.w(TAG, ude);
    DatabaseFactory.getSmsDatabase(context).markAsSentFailed(record.getId());
    MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
  } catch (UntrustedIdentityException uid) {
    Log.w(TAG, uid);
    DatabaseFactory.getSmsDatabase(context).markAsNoSession(record.getId());
    MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
  }
}
 
Example #8
Source Project: bcm-android   Author: bcmapp   File: SignalServiceCipher.java    License: GNU General Public License v3.0 5 votes vote down vote up
private byte[] decrypt(SignalServiceProtos.Envelope envelope, byte[] ciphertext)
    throws InvalidVersionException, InvalidMessageException, InvalidKeyException,
           DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException,
           LegacyMessageException, NoSessionException
{
  SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSource(), envelope.getSourceDevice());
  SessionCipher         sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);

  byte[] paddedMessage;

  if (envelope.getType() == Type.PREKEY_BUNDLE) {
    paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
      //纠正remote register id
      SessionRecord sessionRecord = signalProtocolStore.loadSession(sourceAddress);
      if (sessionRecord.getSessionState().getRemoteRegistrationId() == 0) {
          sessionRecord.getSessionState().setRemoteRegistrationId(envelope.getSourceRegistration());
          signalProtocolStore.storeSession(sourceAddress, sessionRecord);
      }

  } else if (envelope.getType() == Type.CIPHERTEXT) {
    paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
  } else {
    throw new InvalidMessageException("Unknown type: " + envelope.getType());
  }

  PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
  return transportDetails.getStrippedPaddingMessageBody(paddedMessage);
}
 
Example #9
Source Project: Pix-Art-Messenger   Author: kriztan   File: XmppAxolotlSession.java    License: GNU General Public License v3.0 5 votes vote down vote up
@Nullable
public AxolotlKey processSending(@NonNull byte[] outgoingMessage, boolean ignoreSessionTrust) {
    FingerprintStatus status = getTrust();
    if (ignoreSessionTrust || status.isTrustedAndActive()) {
        try {
            CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
            return new AxolotlKey(getRemoteAddress().getDeviceId(), ciphertextMessage.serialize(), ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE);
        } catch (UntrustedIdentityException e) {
            return null;
        }
    } else {
        return null;
    }
}
 
Example #10
Source Project: Silence   Author: SilenceIM   File: SessionBuilder.java    License: GNU General Public License v3.0 5 votes vote down vote up
/**
 * Build a new session from a received {@link PreKeySignalMessage}.
 *
 * After a session is constructed in this way, the embedded {@link SignalMessage}
 * can be decrypted.
 *
 * @param message The received {@link PreKeySignalMessage}.
 * @throws org.whispersystems.libsignal.InvalidKeyIdException when there is no local
 *                                                             {@link org.whispersystems.libsignal.state.PreKeyRecord}
 *                                                             that corresponds to the PreKey ID in
 *                                                             the message.
 * @throws org.whispersystems.libsignal.InvalidKeyException when the message is formatted incorrectly.
 * @throws org.whispersystems.libsignal.UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
 */
/*package*/ Optional<Integer> process(SessionRecord sessionRecord, PreKeySignalMessage message)
    throws InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
{
  IdentityKey theirIdentityKey = message.getIdentityKey();

  if (!identityKeyStore.isTrustedIdentity(remoteAddress, theirIdentityKey, IdentityKeyStore.Direction.RECEIVING)) {
    throw new UntrustedIdentityException(remoteAddress.getName(), theirIdentityKey);
  }

  Optional<Integer> unsignedPreKeyId = processV3(sessionRecord, message);

  identityKeyStore.saveIdentity(remoteAddress, theirIdentityKey);
  return unsignedPreKeyId;
}
 
Example #11
Source Project: Silence   Author: SilenceIM   File: SessionBuilder.java    License: GNU General Public License v3.0 5 votes vote down vote up
private Optional<Integer> processV3(SessionRecord sessionRecord, PreKeySignalMessage message)
    throws UntrustedIdentityException, InvalidKeyIdException, InvalidKeyException
{

  if (sessionRecord.hasSessionState(message.getMessageVersion(), message.getBaseKey().serialize())) {
    Log.w(TAG, "We've already setup a session for this V3 message, letting bundled message fall through...");
    return Optional.absent();
  }

  ECKeyPair ourSignedPreKey = signedPreKeyStore.loadSignedPreKey(message.getSignedPreKeyId()).getKeyPair();

  BobSignalProtocolParameters.Builder parameters = BobSignalProtocolParameters.newBuilder();

  parameters.setTheirBaseKey(message.getBaseKey())
            .setTheirIdentityKey(message.getIdentityKey())
            .setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
            .setOurSignedPreKey(ourSignedPreKey)
            .setOurRatchetKey(ourSignedPreKey);

  if (message.getPreKeyId().isPresent()) {
    parameters.setOurOneTimePreKey(Optional.of(preKeyStore.loadPreKey(message.getPreKeyId().get()).getKeyPair()));
  } else {
    parameters.setOurOneTimePreKey(Optional.<ECKeyPair>absent());
  }

  if (!sessionRecord.isFresh()) sessionRecord.archiveCurrentState();

  RatchetingSession.initializeSession(sessionRecord.getSessionState(), parameters.create());

  sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
  sessionRecord.getSessionState().setRemoteRegistrationId(message.getRegistrationId());
  sessionRecord.getSessionState().setAliceBaseKey(message.getBaseKey().serialize());

  if (message.getPreKeyId().isPresent() && message.getPreKeyId().get() != Medium.MAX_VALUE) {
    return message.getPreKeyId();
  } else {
    return Optional.absent();
  }
}
 
Example #12
Source Project: Silence   Author: SilenceIM   File: MmsCipher.java    License: GNU General Public License v3.0 5 votes vote down vote up
public SendReq encrypt(Context context, SendReq message)
    throws NoSessionException, RecipientFormattingException, UndeliverableMessageException,
           UntrustedIdentityException
{
  EncodedStringValue[] encodedRecipient = message.getTo();
  String               recipientString  = encodedRecipient[0].getString();
  byte[]               pduBytes         = new PduComposer(context, message).make();

  if (pduBytes == null) {
    throw new UndeliverableMessageException("PDU composition failed, null payload");
  }

  if (!axolotlStore.containsSession(new SignalProtocolAddress(recipientString, 1))) {
    throw new NoSessionException("No session for: " + recipientString);
  }

  SessionCipher     cipher            = new SessionCipher(axolotlStore, new SignalProtocolAddress(recipientString, 1));
  CiphertextMessage ciphertextMessage = cipher.encrypt(pduBytes);
  byte[]            encryptedPduBytes = textTransport.getEncodedMessage(ciphertextMessage.serialize());

  PduBody body         = new PduBody();
  PduPart part         = new PduPart();

  part.setContentId((System.currentTimeMillis()+"").getBytes());
  part.setContentType(ContentType.TEXT_PLAIN.getBytes());
  part.setName((System.currentTimeMillis()+"").getBytes());
  part.setData(encryptedPduBytes);
  body.addPart(part);
  message.setSubject(new EncodedStringValue(WirePrefix.calculateEncryptedMmsSubject()));
  message.setBody(body);

  return message;
}
 
Example #13
Source Project: Silence   Author: SilenceIM   File: SmsSendJob.java    License: GNU General Public License v3.0 5 votes vote down vote up
private OutgoingTextMessage getAsymmetricEncrypt(MasterSecret masterSecret,
                                                 OutgoingTextMessage message)
    throws UndeliverableMessageException, UntrustedIdentityException

{
  try {
    return new SmsCipher(new SilenceSignalProtocolStore(context, masterSecret, message.getSubscriptionId())).encrypt(message);
  } catch (NoSessionException e) {
    throw new UndeliverableMessageException(e);
  }
}
 
Example #14
Source Project: Silence   Author: SilenceIM   File: SmsDecryptJob.java    License: GNU General Public License v3.0 5 votes vote down vote up
private void handleSecureMessage(MasterSecret masterSecret, long messageId, long threadId,
                                 IncomingTextMessage message)
    throws NoSessionException, DuplicateMessageException,
           InvalidMessageException, LegacyMessageException,
           UntrustedIdentityException
{
  EncryptingSmsDatabase database  = DatabaseFactory.getEncryptingSmsDatabase(context);
  SmsCipher             cipher    = new SmsCipher(new SilenceSignalProtocolStore(context, masterSecret, message.getSubscriptionId()));
  IncomingTextMessage   plaintext = cipher.decrypt(context, message);

  database.updateMessageBody(masterSecret, messageId, plaintext.getMessageBody());

  if (message.isEndSession()) SecurityEvent.broadcastSecurityUpdateEvent(context, threadId);
}
 
Example #15
Source Project: Smack   Author: igniterealtime   File: SignalOmemoRatchet.java    License: Apache License 2.0 5 votes vote down vote up
@Override
public CiphertextTuple doubleRatchetEncrypt(OmemoDevice recipient, byte[] messageKey) {
    CiphertextMessage ciphertextMessage;
    try {
        ciphertextMessage = getCipher(recipient).encrypt(messageKey);
    } catch (UntrustedIdentityException e) {
        throw new AssertionError("Signals trust management MUST be disabled.");
    }

    int type = ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE ?
            OmemoElement.TYPE_OMEMO_PREKEY_MESSAGE : OmemoElement.TYPE_OMEMO_MESSAGE;

    return new CiphertextTuple(ciphertextMessage.serialize(), type);
}
 
Example #16
Source Project: Conversations   Author: iNPUTmice   File: XmppAxolotlSession.java    License: GNU General Public License v3.0 5 votes vote down vote up
@Nullable
public AxolotlKey processSending(@NonNull byte[] outgoingMessage, boolean ignoreSessionTrust) {
	FingerprintStatus status = getTrust();
	if (ignoreSessionTrust || status.isTrustedAndActive()) {
		try {
			CiphertextMessage ciphertextMessage = cipher.encrypt(outgoingMessage);
			return new AxolotlKey(getRemoteAddress().getDeviceId(), ciphertextMessage.serialize(),ciphertextMessage.getType() == CiphertextMessage.PREKEY_TYPE);
		} catch (UntrustedIdentityException e) {
			return null;
		}
	} else {
		return null;
	}
}
 
Example #17
Source Project: Silence   Author: SilenceIM   File: SessionBuilder.java    License: GNU General Public License v3.0 4 votes vote down vote up
/**
 * Build a new session from a {@link org.whispersystems.libsignal.state.PreKeyBundle} retrieved from
 * a server.
 *
 * @param preKey A PreKey for the destination recipient, retrieved from a server.
 * @throws InvalidKeyException when the {@link org.whispersystems.libsignal.state.PreKeyBundle} is
 *                             badly formatted.
 * @throws org.whispersystems.libsignal.UntrustedIdentityException when the sender's
 *                                                                  {@link IdentityKey} is not
 *                                                                  trusted.
 */
public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException {
  synchronized (SessionCipher.SESSION_LOCK) {
    if (!identityKeyStore.isTrustedIdentity(remoteAddress, preKey.getIdentityKey(), IdentityKeyStore.Direction.SENDING)) {
      throw new UntrustedIdentityException(remoteAddress.getName(), preKey.getIdentityKey());
    }

    if (preKey.getSignedPreKey() != null &&
        !Curve.verifySignature(preKey.getIdentityKey().getPublicKey(),
                               preKey.getSignedPreKey().serialize(),
                               preKey.getSignedPreKeySignature()))
    {
      throw new InvalidKeyException("Invalid signature on device key!");
    }

    if (preKey.getSignedPreKey() == null) {
      throw new InvalidKeyException("No signed prekey!");
    }

    SessionRecord         sessionRecord        = sessionStore.loadSession(remoteAddress);
    ECKeyPair             ourBaseKey           = Curve.generateKeyPair();
    ECPublicKey           theirSignedPreKey    = preKey.getSignedPreKey();
    Optional<ECPublicKey> theirOneTimePreKey   = Optional.fromNullable(preKey.getPreKey());
    Optional<Integer>     theirOneTimePreKeyId = theirOneTimePreKey.isPresent() ? Optional.of(preKey.getPreKeyId()) :
                                                                                  Optional.<Integer>absent();

    AliceSignalProtocolParameters.Builder parameters = AliceSignalProtocolParameters.newBuilder();

    parameters.setOurBaseKey(ourBaseKey)
              .setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
              .setTheirIdentityKey(preKey.getIdentityKey())
              .setTheirSignedPreKey(theirSignedPreKey)
              .setTheirRatchetKey(theirSignedPreKey)
              .setTheirOneTimePreKey(theirOneTimePreKey);

    if (!sessionRecord.isFresh()) sessionRecord.archiveCurrentState();

    RatchetingSession.initializeSession(sessionRecord.getSessionState(), parameters.create());

    sessionRecord.getSessionState().setUnacknowledgedPreKeyMessage(theirOneTimePreKeyId, preKey.getSignedPreKeyId(), ourBaseKey.getPublicKey());
    sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
    sessionRecord.getSessionState().setRemoteRegistrationId(preKey.getRegistrationId());
    sessionRecord.getSessionState().setAliceBaseKey(ourBaseKey.getPublicKey().serialize());

    identityKeyStore.saveIdentity(remoteAddress, preKey.getIdentityKey());
    sessionStore.storeSession(remoteAddress, sessionRecord);
  }
}
 
Example #18
Source Project: Silence   Author: SilenceIM   File: SmsSendJob.java    License: GNU General Public License v3.0 4 votes vote down vote up
private void deliver(MasterSecret masterSecret, SmsMessageRecord message)
    throws UndeliverableMessageException, UntrustedIdentityException
{
  String recipient = message.getIndividualRecipient().getNumber();
  ArrayList<String> messages;

  // See issue #1516 for bug report, and discussion on commits related to #4833 for problems
  // related to the original fix to #1516. This still may not be a correct fix if networks allow
  // SMS/MMS sending to alphanumeric recipients other than email addresses, but should also
  // help to fix issue #3099.
  if (!NumberUtil.isValidEmail(recipient)) {
    recipient = PhoneNumberUtils.stripSeparators(PhoneNumberUtils.convertKeypadLettersToDigits(recipient));
  }

  if (!NumberUtil.isValidSmsOrEmail(recipient)) {
    throw new UndeliverableMessageException("Not a valid SMS destination! " + recipient);
  }

  if (message.isSecure() || message.isKeyExchange() || message.isEndSession()) {
    MultipartSmsMessageHandler multipartMessageHandler = new MultipartSmsMessageHandler();
    OutgoingTextMessage        transportMessage        = OutgoingTextMessage.from(message);

    if (!message.isKeyExchange()) {
      transportMessage = getAsymmetricEncrypt(masterSecret, transportMessage);
    }

    messages = SmsManager.getDefault().divideMessage(multipartMessageHandler.getEncodedMessage(transportMessage));
  } else {
    messages = SmsManager.getDefault().divideMessage(message.getBody().getBody());
  }

  ArrayList<PendingIntent> sentIntents      = constructSentIntents(message.getId(), message.getType(), messages, message.isSecure());
  ArrayList<PendingIntent> deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages);

  int deviceSubscriptionId = DualSimUtil.getSubscriptionIdFromAppSubscriptionId(context, message.getSubscriptionId());

  // NOTE 11/04/14 -- There's apparently a bug where for some unknown recipients
  // and messages, this will throw an NPE.  We have no idea why, so we're just
  // catching it and marking the message as a failure.  That way at least it doesn't
  // repeatedly crash every time you start the app.
  try {
    getSmsManagerFor(deviceSubscriptionId).sendMultipartTextMessage(recipient, null, messages, sentIntents, deliveredIntents);
  } catch (NullPointerException npe) {
    Log.w(TAG, npe);
    Log.w(TAG, "Recipient: " + recipient);
    Log.w(TAG, "Message Parts: " + messages.size());
    throw new UndeliverableMessageException(npe);
  } catch (IllegalArgumentException iae) {
    Log.w(TAG, iae);
    throw new UndeliverableMessageException(iae);
  } catch (SecurityException se) {
    Log.w(TAG, se);
    throw new UndeliverableMessageException(se);
  } 
}