Make encoding/decoding more explicit.

This commit is contained in:
Moxie Marlinspike 2013-08-31 09:28:49 -07:00
parent 0cc5837d7f
commit cddba2738f
10 changed files with 52 additions and 47 deletions

View File

@ -16,16 +16,13 @@
*/ */
package org.whispersystems.textsecure.crypto.protocol; package org.whispersystems.textsecure.crypto.protocol;
import org.whispersystems.textsecure.crypto.MessageCipher;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.textsecure.crypto.IdentityKey;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.whispersystems.textsecure.crypto.MessageCipher;
import org.whispersystems.textsecure.crypto.PublicKey; import org.whispersystems.textsecure.crypto.PublicKey;
import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Conversions; import org.whispersystems.textsecure.util.Conversions;
import java.io.IOException;
/** /**
* Class responsible for parsing and constructing PreKeyBundle messages. * Class responsible for parsing and constructing PreKeyBundle messages.
* *
@ -53,9 +50,10 @@ public class PreKeyBundleMessage {
private final PublicKey publicKey; private final PublicKey publicKey;
private final byte[] bundledMessage; private final byte[] bundledMessage;
public PreKeyBundleMessage(String message) throws InvalidKeyException, InvalidVersionException { public PreKeyBundleMessage(byte[] messageBytes)
try { throws InvalidKeyException, InvalidVersionException
this.messageBytes = Base64.decodeWithoutPadding(message); {
this.messageBytes = messageBytes;
this.messageVersion = Conversions.highBitsToInt(this.messageBytes[VERSION_OFFSET]); this.messageVersion = Conversions.highBitsToInt(this.messageBytes[VERSION_OFFSET]);
if (messageVersion > MessageCipher.SUPPORTED_VERSION) if (messageVersion > MessageCipher.SUPPORTED_VERSION)
@ -71,9 +69,6 @@ public class PreKeyBundleMessage {
this.bundledMessage[VERSION_OFFSET] = this.messageBytes[VERSION_OFFSET]; this.bundledMessage[VERSION_OFFSET] = this.messageBytes[VERSION_OFFSET];
System.arraycopy(messageBytes, IDENTITY_KEY_OFFSET+IDENTITY_KEY_LENGTH, bundledMessage, VERSION_OFFSET+VERSION_LENGTH, bundledMessage.length-VERSION_LENGTH); System.arraycopy(messageBytes, IDENTITY_KEY_OFFSET+IDENTITY_KEY_LENGTH, bundledMessage, VERSION_OFFSET+VERSION_LENGTH, bundledMessage.length-VERSION_LENGTH);
} catch (IOException e) {
throw new InvalidKeyException(e);
}
} }
public PreKeyBundleMessage(IdentityKey identityKey, byte[] bundledMessage) { public PreKeyBundleMessage(IdentityKey identityKey, byte[] bundledMessage) {
@ -116,8 +111,8 @@ public class PreKeyBundleMessage {
return publicKey; return publicKey;
} }
public String getBundledMessage() { public byte[] getBundledMessage() {
return Base64.encodeBytesWithoutPadding(bundledMessage); return bundledMessage;
} }
public int getPreKeyId() { public int getPreKeyId() {

View File

@ -50,6 +50,7 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
this.destinations = new LinkedList<String>(); this.destinations = new LinkedList<String>();
this.attachments = new LinkedList<PushAttachmentPointer>(); this.attachments = new LinkedList<PushAttachmentPointer>();
this.type = in.readInt();
this.source = in.readString(); this.source = in.readString();
in.readStringList(destinations); in.readStringList(destinations);
this.message = new byte[in.readInt()]; this.message = new byte[in.readInt()];
@ -70,15 +71,8 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
return attachments; return attachments;
} }
public String getMessageText() { public byte[] getBody() {
if (type == TYPE_MESSAGE_CIPHERTEXT || return message;
type == TYPE_MESSAGE_KEY_EXCHANGE ||
type == TYPE_MESSAGE_PREKEY_BUNDLE)
{
return Base64.encodeBytesWithoutPadding(message);
}
return new String(message);
} }
public List<String> getDestinations() { public List<String> getDestinations() {
@ -96,6 +90,7 @@ public class IncomingPushMessage implements PushMessage, Parcelable {
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(type);
dest.writeString(source); dest.writeString(source);
dest.writeStringList(destinations); dest.writeStringList(destinations);
dest.writeInt(message.length); dest.writeInt(message.length);

View File

@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.sms; package org.whispersystems.textsecure.push;
import org.whispersystems.textsecure.crypto.TransportDetails; import org.whispersystems.textsecure.crypto.TransportDetails;

View File

@ -68,7 +68,13 @@ public abstract class Record {
} }
private static File getAddressFile(Context context, String directory, String address) { private static File getAddressFile(Context context, String directory, String address) {
return new File(context.getFilesDir().getAbsolutePath() + File.separatorChar + directory, address); File parent = new File(context.getFilesDir(), directory);
if (!parent.exists()) {
parent.mkdirs();
}
return new File(parent, address);
} }
protected byte[] readBlob(FileInputStream in) throws IOException { protected byte[] readBlob(FileInputStream in) throws IOException {

View File

@ -8,6 +8,7 @@ import com.google.android.gcm.GCMBaseIntentService;
import org.thoughtcrime.securesms.service.RegistrationService; import org.thoughtcrime.securesms.service.RegistrationService;
import org.thoughtcrime.securesms.service.SendReceiveService; import org.thoughtcrime.securesms.service.SendReceiveService;
import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.whispersystems.textsecure.push.IncomingEncryptedPushMessage; import org.whispersystems.textsecure.push.IncomingEncryptedPushMessage;
@ -76,7 +77,8 @@ public class GcmIntentService extends GCMBaseIntentService {
private void handleIncomingTextMessage(Context context, IncomingPushMessage message) { private void handleIncomingTextMessage(Context context, IncomingPushMessage message) {
ArrayList<IncomingTextMessage> messages = new ArrayList<IncomingTextMessage>(); ArrayList<IncomingTextMessage> messages = new ArrayList<IncomingTextMessage>();
messages.add(new IncomingTextMessage(message)); String encodedBody = new String(new SmsTransportDetails().getEncodedMessage(message.getBody()));
messages.add(new IncomingTextMessage(message, encodedBody));
Intent receivedIntent = new Intent(context, SendReceiveService.class); Intent receivedIntent = new Intent(context, SendReceiveService.class);
receivedIntent.setAction(SendReceiveService.RECEIVE_SMS_ACTION); receivedIntent.setAction(SendReceiveService.RECEIVE_SMS_ACTION);

View File

@ -46,9 +46,9 @@ public class IncomingMediaMessage {
this.headers.setLongInteger(message.getTimestampMillis() / 1000, PduHeaders.DATE); this.headers.setLongInteger(message.getTimestampMillis() / 1000, PduHeaders.DATE);
if (message.getMessageText() != null && message.getMessageText().length() > 0) { if (message.getBody() != null && message.getBody().length > 0) {
PduPart text = new PduPart(); PduPart text = new PduPart();
text.setData(message.getMessageText().getBytes()); text.setData(message.getBody());
text.setContentType("text/plain".getBytes(CharacterSets.MIMENAME_ISO_8859_1)); text.setContentType("text/plain".getBytes(CharacterSets.MIMENAME_ISO_8859_1));
body.addPart(text); body.addPart(text);
} }

View File

@ -36,15 +36,16 @@ import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage;
import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage; import org.thoughtcrime.securesms.sms.IncomingPreKeyBundleMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler; import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler;
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.InvalidKeyException; import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidVersionException; import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage; import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
import org.whispersystems.textsecure.push.OutgoingPushMessage;
import org.whispersystems.textsecure.push.PushMessage; import org.whispersystems.textsecure.push.PushMessage;
import org.whispersystems.textsecure.storage.InvalidKeyIdException; import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import java.io.IOException;
import java.util.List; import java.util.List;
public class SmsReceiver { public class SmsReceiver {
@ -122,12 +123,14 @@ public class SmsReceiver {
try { try {
Recipient recipient = new Recipient(null, message.getSender(), null, null); Recipient recipient = new Recipient(null, message.getSender(), null, null);
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient); KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient);
PreKeyBundleMessage preKeyExchange = new PreKeyBundleMessage(message.getMessageBody()); SmsTransportDetails transportDetails = new SmsTransportDetails();
PreKeyBundleMessage preKeyExchange = new PreKeyBundleMessage(transportDetails.getDecodedMessage(message.getMessageBody().getBytes()));
if (processor.isTrusted(preKeyExchange)) { if (processor.isTrusted(preKeyExchange)) {
processor.processKeyExchangeMessage(preKeyExchange); processor.processKeyExchangeMessage(preKeyExchange);
IncomingEncryptedMessage bundledMessage = new IncomingEncryptedMessage(message, preKeyExchange.getBundledMessage()); String bundledMessageBody = new String(transportDetails.getEncodedMessage(preKeyExchange.getBundledMessage()));
IncomingEncryptedMessage bundledMessage = new IncomingEncryptedMessage(message, bundledMessageBody);
Pair<Long, Long> messageAndThreadId = storeSecureMessage(masterSecret, bundledMessage); Pair<Long, Long> messageAndThreadId = storeSecureMessage(masterSecret, bundledMessage);
Intent intent = new Intent(KeyExchangeProcessor.SECURITY_UPDATE_EVENT); Intent intent = new Intent(KeyExchangeProcessor.SECURITY_UPDATE_EVENT);
@ -136,6 +139,8 @@ public class SmsReceiver {
context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION); context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION);
return messageAndThreadId; return messageAndThreadId;
} else {
/// XXX
} }
} catch (InvalidKeyException e) { } catch (InvalidKeyException e) {
Log.w("SmsReceiver", e); Log.w("SmsReceiver", e);
@ -146,6 +151,9 @@ public class SmsReceiver {
} catch (InvalidKeyIdException e) { } catch (InvalidKeyIdException e) {
Log.w("SmsReceiver", e); Log.w("SmsReceiver", e);
message.setStale(true); message.setStale(true);
} catch (IOException e) {
Log.w("SmsReceive", e);
message.setCorrupted(true);
} }
return storeStandardMessage(masterSecret, message); return storeStandardMessage(masterSecret, message);

View File

@ -40,8 +40,8 @@ public class IncomingTextMessage implements Parcelable {
this.sentTimestampMillis = message.getTimestampMillis(); this.sentTimestampMillis = message.getTimestampMillis();
} }
public IncomingTextMessage(IncomingPushMessage message) { public IncomingTextMessage(IncomingPushMessage message, String encodedBody) {
this.message = message.getMessageText(); this.message = encodedBody;
this.sender = message.getSource(); this.sender = message.getSource();
this.protocol = 31337; this.protocol = 31337;
this.serviceCenterAddress = "GCM"; this.serviceCenterAddress = "GCM";

View File

@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.crypto.KeyExchangeProcessor;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord; import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.mms.PartParser; import org.thoughtcrime.securesms.mms.PartParser;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.RawTransportDetails; import org.whispersystems.textsecure.push.RawTransportDetails;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.textsecure.crypto.IdentityKey; import org.whispersystems.textsecure.crypto.IdentityKey;

View File

@ -4,10 +4,9 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.telephony.SmsManager; import android.telephony.SmsManager;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil; import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.sms.OutgoingPrekeyBundleMessage;import org.thoughtcrime.securesms.sms.RawTransportDetails; import org.thoughtcrime.securesms.sms.OutgoingPrekeyBundleMessage;import org.whispersystems.textsecure.push.RawTransportDetails;
import org.whispersystems.textsecure.crypto.IdentityKeyPair; import org.whispersystems.textsecure.crypto.IdentityKeyPair;
import org.whispersystems.textsecure.crypto.KeyUtil; import org.whispersystems.textsecure.crypto.KeyUtil;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;