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;
import org.whispersystems.textsecure.crypto.MessageCipher;
import org.whispersystems.textsecure.crypto.IdentityKey;
import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.whispersystems.textsecure.crypto.MessageCipher;
import org.whispersystems.textsecure.crypto.PublicKey;
import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.Conversions;
import java.io.IOException;
/**
* Class responsible for parsing and constructing PreKeyBundle messages.
*
@ -53,27 +50,25 @@ public class PreKeyBundleMessage {
private final PublicKey publicKey;
private final byte[] bundledMessage;
public PreKeyBundleMessage(String message) throws InvalidKeyException, InvalidVersionException {
try {
this.messageBytes = Base64.decodeWithoutPadding(message);
this.messageVersion = Conversions.highBitsToInt(this.messageBytes[VERSION_OFFSET]);
public PreKeyBundleMessage(byte[] messageBytes)
throws InvalidKeyException, InvalidVersionException
{
this.messageBytes = messageBytes;
this.messageVersion = Conversions.highBitsToInt(this.messageBytes[VERSION_OFFSET]);
if (messageVersion > MessageCipher.SUPPORTED_VERSION)
throw new InvalidVersionException("Key exchange with version: " + messageVersion +
" but we only support: " + MessageCipher.SUPPORTED_VERSION);
if (messageVersion > MessageCipher.SUPPORTED_VERSION)
throw new InvalidVersionException("Key exchange with version: " + messageVersion +
" but we only support: " + MessageCipher.SUPPORTED_VERSION);
this.supportedVersion = Conversions.lowBitsToInt(messageBytes[VERSION_OFFSET]);
this.publicKey = new PublicKey(messageBytes, PUBLIC_KEY_OFFSET);
this.identityKey = new IdentityKey(messageBytes, IDENTITY_KEY_OFFSET);
this.preKeyId = Conversions.byteArrayToMedium(messageBytes, PREKEY_ID_OFFSET);
this.bundledMessage = new byte[messageBytes.length - IDENTITY_KEY_LENGTH];
this.supportedVersion = Conversions.lowBitsToInt(messageBytes[VERSION_OFFSET]);
this.publicKey = new PublicKey(messageBytes, PUBLIC_KEY_OFFSET);
this.identityKey = new IdentityKey(messageBytes, IDENTITY_KEY_OFFSET);
this.preKeyId = Conversions.byteArrayToMedium(messageBytes, PREKEY_ID_OFFSET);
this.bundledMessage = new byte[messageBytes.length - IDENTITY_KEY_LENGTH];
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);
} catch (IOException e) {
throw new InvalidKeyException(e);
}
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);
}
public PreKeyBundleMessage(IdentityKey identityKey, byte[] bundledMessage) {
@ -116,8 +111,8 @@ public class PreKeyBundleMessage {
return publicKey;
}
public String getBundledMessage() {
return Base64.encodeBytesWithoutPadding(bundledMessage);
public byte[] getBundledMessage() {
return bundledMessage;
}
public int getPreKeyId() {

View File

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

View File

@ -68,7 +68,13 @@ public abstract class Record {
}
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 {

View File

@ -8,6 +8,7 @@ import com.google.android.gcm.GCMBaseIntentService;
import org.thoughtcrime.securesms.service.RegistrationService;
import org.thoughtcrime.securesms.service.SendReceiveService;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.whispersystems.textsecure.push.IncomingEncryptedPushMessage;
@ -76,7 +77,8 @@ public class GcmIntentService extends GCMBaseIntentService {
private void handleIncomingTextMessage(Context context, IncomingPushMessage message) {
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);
receivedIntent.setAction(SendReceiveService.RECEIVE_SMS_ACTION);

View File

@ -46,9 +46,9 @@ public class IncomingMediaMessage {
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();
text.setData(message.getMessageText().getBytes());
text.setData(message.getBody());
text.setContentType("text/plain".getBytes(CharacterSets.MIMENAME_ISO_8859_1));
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.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.MultipartSmsMessageHandler;
import org.thoughtcrime.securesms.sms.SmsTransportDetails;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.crypto.InvalidKeyException;
import org.whispersystems.textsecure.crypto.InvalidVersionException;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
import org.whispersystems.textsecure.push.OutgoingPushMessage;
import org.whispersystems.textsecure.push.PushMessage;
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import java.io.IOException;
import java.util.List;
public class SmsReceiver {
@ -120,14 +121,16 @@ public class SmsReceiver {
Log.w("SmsReceiver", "Processing prekey message...");
try {
Recipient recipient = new Recipient(null, message.getSender(), null, null);
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient);
PreKeyBundleMessage preKeyExchange = new PreKeyBundleMessage(message.getMessageBody());
Recipient recipient = new Recipient(null, message.getSender(), null, null);
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient);
SmsTransportDetails transportDetails = new SmsTransportDetails();
PreKeyBundleMessage preKeyExchange = new PreKeyBundleMessage(transportDetails.getDecodedMessage(message.getMessageBody().getBytes()));
if (processor.isTrusted(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);
Intent intent = new Intent(KeyExchangeProcessor.SECURITY_UPDATE_EVENT);
@ -136,6 +139,8 @@ public class SmsReceiver {
context.sendBroadcast(intent, KeyCachingService.KEY_PERMISSION);
return messageAndThreadId;
} else {
/// XXX
}
} catch (InvalidKeyException e) {
Log.w("SmsReceiver", e);
@ -146,6 +151,9 @@ public class SmsReceiver {
} catch (InvalidKeyIdException e) {
Log.w("SmsReceiver", e);
message.setStale(true);
} catch (IOException e) {
Log.w("SmsReceive", e);
message.setCorrupted(true);
}
return storeStandardMessage(masterSecret, message);

View File

@ -40,8 +40,8 @@ public class IncomingTextMessage implements Parcelable {
this.sentTimestampMillis = message.getTimestampMillis();
}
public IncomingTextMessage(IncomingPushMessage message) {
this.message = message.getMessageText();
public IncomingTextMessage(IncomingPushMessage message, String encodedBody) {
this.message = encodedBody;
this.sender = message.getSource();
this.protocol = 31337;
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.mms.PartParser;
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.Util;
import org.whispersystems.textsecure.crypto.IdentityKey;

View File

@ -4,10 +4,9 @@ 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.thoughtcrime.securesms.sms.OutgoingPrekeyBundleMessage;import org.whispersystems.textsecure.push.RawTransportDetails;
import org.whispersystems.textsecure.crypto.IdentityKeyPair;
import org.whispersystems.textsecure.crypto.KeyUtil;
import org.whispersystems.textsecure.crypto.MasterSecret;