mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-25 22:59:25 +00:00
Added SMS transport support for PreKeyBundle messages.
1) Added SMS transport support. 2) Keep track of whether a PreKeyBundle message has gotten a response, and send them as subsequent messages until one has been received.
This commit is contained in:
@@ -2,26 +2,27 @@ package org.thoughtcrime.securesms.transport;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.PartParser;
|
||||
import org.thoughtcrime.securesms.mms.TextTransport;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.sms.RawTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.KeyUtil;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.MessageCipher;
|
||||
import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
|
||||
import org.whispersystems.textsecure.push.PreKeyEntity;
|
||||
import org.whispersystems.textsecure.push.PushAttachmentData;
|
||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||
import org.whispersystems.textsecure.push.PushTransportDetails;
|
||||
import org.whispersystems.textsecure.push.RateLimitException;
|
||||
import org.whispersystems.textsecure.storage.SessionRecord;
|
||||
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -53,20 +54,14 @@ public class PushTransport extends BaseTransport {
|
||||
String password = TextSecurePreferences.getPushServerPassword(context);
|
||||
PushServiceSocket socket = new PushServiceSocket(context, localNumber, password);
|
||||
|
||||
Recipient recipient = message.getIndividualRecipient();
|
||||
String plaintext = message.getBody().getBody();
|
||||
String recipientCanonicalNumber = PhoneNumberFormatter.formatNumber(recipient.getNumber(),
|
||||
localNumber);
|
||||
Recipient recipient = message.getIndividualRecipient();
|
||||
String plaintext = message.getBody().getBody();
|
||||
String recipientCanonicalNumber = PhoneNumberFormatter.formatNumber(recipient.getNumber(),
|
||||
localNumber);
|
||||
|
||||
if (SessionRecord.hasSession(context, recipient)) {
|
||||
byte[] cipherText = getEncryptedMessageForExistingSession(recipient, plaintext);
|
||||
socket.sendMessage(recipientCanonicalNumber, new String(cipherText), TYPE_MESSAGE_CIPHERTEXT);
|
||||
} else {
|
||||
byte[] cipherText = getEncryptedMessageForNewSession(socket, recipient,
|
||||
recipientCanonicalNumber,
|
||||
plaintext);
|
||||
socket.sendMessage(recipientCanonicalNumber, new String(cipherText), TYPE_MESSAGE_PREKEY_BUNDLE);
|
||||
}
|
||||
Pair<Integer, String> typeAndCiphertext = getEncryptedMessage(socket, recipient, recipientCanonicalNumber, plaintext);
|
||||
|
||||
socket.sendMessage(recipientCanonicalNumber, typeAndCiphertext.second, typeAndCiphertext.first);
|
||||
|
||||
context.sendBroadcast(constructSentIntent(context, message.getId(), message.getType()));
|
||||
} catch (RateLimitException e) {
|
||||
@@ -108,8 +103,42 @@ public class PushTransport extends BaseTransport {
|
||||
return attachments;
|
||||
}
|
||||
|
||||
private byte[] getEncryptedMessageForNewSession(PushServiceSocket socket, Recipient recipient,
|
||||
String canonicalRecipientNumber, String plaintext)
|
||||
private Pair<Integer, String> getEncryptedMessage(PushServiceSocket socket, Recipient recipient,
|
||||
String canonicalRecipientNumber, String plaintext)
|
||||
throws IOException
|
||||
{
|
||||
if (KeyUtil.isNonPrekeySessionFor(context, masterSecret, recipient)) {
|
||||
Log.w("PushTransport", "Sending standard ciphertext message...");
|
||||
String ciphertext = getEncryptedMessageForExistingSession(recipient, plaintext);
|
||||
return new Pair<Integer, String>(TYPE_MESSAGE_CIPHERTEXT, ciphertext);
|
||||
} else if (KeyUtil.isSessionFor(context, recipient)) {
|
||||
Log.w("PushTransport", "Sending prekeybundle ciphertext message for existing session...");
|
||||
String ciphertext = getEncryptedPrekeyBundleMessageForExistingSession(recipient, plaintext);
|
||||
return new Pair<Integer, String>(TYPE_MESSAGE_PREKEY_BUNDLE, ciphertext);
|
||||
} else {
|
||||
Log.w("PushTransport", "Sending prekeybundle ciphertext message for new session...");
|
||||
String ciphertext = getEncryptedPrekeyBundleMessageForNewSession(socket, recipient, canonicalRecipientNumber, plaintext);
|
||||
return new Pair<Integer, String>(TYPE_MESSAGE_PREKEY_BUNDLE, ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
private String getEncryptedPrekeyBundleMessageForExistingSession(Recipient recipient,
|
||||
String plaintext)
|
||||
{
|
||||
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
||||
IdentityKey identityKey = identityKeyPair.getPublicKey();
|
||||
|
||||
MessageCipher message = new MessageCipher(context, masterSecret, identityKeyPair, new RawTransportDetails());
|
||||
byte[] bundledMessage = message.encrypt(recipient, plaintext.getBytes());
|
||||
|
||||
PreKeyBundleMessage preKeyBundleMessage = new PreKeyBundleMessage(identityKey, bundledMessage);
|
||||
return preKeyBundleMessage.serialize();
|
||||
}
|
||||
|
||||
private String getEncryptedPrekeyBundleMessageForNewSession(PushServiceSocket socket,
|
||||
Recipient recipient,
|
||||
String canonicalRecipientNumber,
|
||||
String plaintext)
|
||||
throws IOException
|
||||
{
|
||||
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
||||
@@ -123,15 +152,17 @@ public class PushTransport extends BaseTransport {
|
||||
byte[] bundledMessage = message.encrypt(recipient, plaintext.getBytes());
|
||||
|
||||
PreKeyBundleMessage preKeyBundleMessage = new PreKeyBundleMessage(identityKey, bundledMessage);
|
||||
return preKeyBundleMessage.serialize().getBytes();
|
||||
return preKeyBundleMessage.serialize();
|
||||
}
|
||||
|
||||
private byte[] getEncryptedMessageForExistingSession(Recipient recipient, String plaintext)
|
||||
private String getEncryptedMessageForExistingSession(Recipient recipient, String plaintext)
|
||||
throws IOException
|
||||
{
|
||||
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
||||
MessageCipher message = new MessageCipher(context, masterSecret, identityKeyPair, new TextTransport());
|
||||
return message.encrypt(recipient, plaintext.getBytes());
|
||||
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
||||
MessageCipher messageCipher = new MessageCipher(context, masterSecret, identityKeyPair,
|
||||
new PushTransportDetails());
|
||||
|
||||
return new String(messageCipher.encrypt(recipient, plaintext.getBytes()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.telephony.SmsManager;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingPrekeyBundleMessage;import org.thoughtcrime.securesms.sms.RawTransportDetails;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.KeyUtil;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.MessageCipher;
|
||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
@@ -17,6 +20,7 @@ import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -43,9 +47,7 @@ public class SmsTransport extends BaseTransport {
|
||||
OutgoingTextMessage transportMessage = OutgoingTextMessage.from(message);
|
||||
|
||||
if (message.isSecure()) {
|
||||
String encryptedMessage = getAsymmetricEncrypt(masterSecret, message.getBody().getBody(),
|
||||
message.getIndividualRecipient());
|
||||
transportMessage = transportMessage.withBody(encryptedMessage);
|
||||
transportMessage = getAsymmetricEncrypt(masterSecret, transportMessage);
|
||||
}
|
||||
|
||||
ArrayList<String> messages = multipartMessageHandler.divideMessage(transportMessage);
|
||||
@@ -139,9 +141,26 @@ public class SmsTransport extends BaseTransport {
|
||||
return deliveredIntents;
|
||||
}
|
||||
|
||||
private String getAsymmetricEncrypt(MasterSecret masterSecret, String body, Recipient recipient) {
|
||||
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
||||
MessageCipher message = new MessageCipher(context, masterSecret, identityKey, new SmsTransportDetails());
|
||||
return new String(message.encrypt(recipient, body.getBytes()));
|
||||
private OutgoingTextMessage getAsymmetricEncrypt(MasterSecret masterSecret,
|
||||
OutgoingTextMessage message)
|
||||
{
|
||||
Recipient recipient = message.getRecipients().getPrimaryRecipient();
|
||||
String body = message.getMessageBody();
|
||||
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context, masterSecret);
|
||||
|
||||
if (KeyUtil.isNonPrekeySessionFor(context, masterSecret, recipient)) {
|
||||
Log.w("SmsTransport", "Delivering standard ciphertext...");
|
||||
MessageCipher messageCipher = new MessageCipher(context, masterSecret, identityKey, new SmsTransportDetails());
|
||||
byte[] ciphertext = messageCipher.encrypt(recipient, body.getBytes());
|
||||
|
||||
return message.withBody(new String(ciphertext));
|
||||
} else {
|
||||
Log.w("SmsTransport", "Delivering prekeybundle ciphertext...");
|
||||
MessageCipher messageCipher = new MessageCipher(context, masterSecret, identityKey, new RawTransportDetails());
|
||||
byte[] bundledMessage = messageCipher.encrypt(recipient, body.getBytes());
|
||||
PreKeyBundleMessage preKeyBundleMessage = new PreKeyBundleMessage(identityKey.getPublicKey(), bundledMessage);
|
||||
|
||||
return new OutgoingPrekeyBundleMessage(message, preKeyBundleMessage.serialize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/**
|
||||
* Copyright (C) 2013 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.transport;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
Reference in New Issue
Block a user