Fix for 'bad encrypted message' errors.

1) There was a regression in the outgoing multipart transport
   logic, such that the same 'identifier' byte would be used
   for all messages (0).  This now works correctly.

2) Added some additional heuristics on the receiving side.
   Now mutlipart containers are only valid for 1hr, and are
   considered invalid if the container size is different from
   the multipart message size.
This commit is contained in:
Moxie Marlinspike 2013-07-22 15:04:31 -07:00
parent 4281df7a28
commit 7d07d56fc3
3 changed files with 59 additions and 21 deletions

View File

@ -0,0 +1,32 @@
package org.thoughtcrime.securesms.sms;
import java.util.HashMap;
public class MultipartSmsIdentifier {
private static final MultipartSmsIdentifier instance = new MultipartSmsIdentifier();
public static MultipartSmsIdentifier getInstance() {
return instance;
}
private final HashMap<String, Integer> idMap = new HashMap<String, Integer>();
public synchronized byte getIdForRecipient(String recipient) {
Integer currentId;
if (idMap.containsKey(recipient)) {
currentId = idMap.get(recipient);
idMap.remove(recipient);
} else {
currentId = 0;
}
byte id = currentId.byteValue();
idMap.put(recipient, (currentId + 1) % 255);
return id;
}
}

View File

@ -29,13 +29,17 @@ public class MultipartSmsMessageHandler {
private final HashMap<String, MultipartSmsTransportMessageFragments> partialMessages =
new HashMap<String, MultipartSmsTransportMessageFragments>();
private final HashMap<String, Integer> idMap = new HashMap<String, Integer>();
private IncomingTextMessage processMultipartMessage(MultipartSmsTransportMessage message) {
Log.w("MultipartSmsMessageHandler", "Processing multipart message...");
Log.w("MultipartSmsMessageHandler", "Multipart Count: " + message.getMultipartCount());
Log.w("MultipartSmsMessageHandler", "Multipart ID: " + message.getIdentifier());
Log.w("MultipartSmsMessageHandler", "Multipart Key: " + message.getKey());
MultipartSmsTransportMessageFragments container = partialMessages.get(message.getKey());
if (container == null) {
Log.w("MultipartSmsMessageHandler", "Found multipart container: " + container);
if (container == null || container.getSize() != message.getMultipartCount() || container.isExpired()) {
Log.w("MultipartSmsMessageHandler", "Constructing new container...");
container = new MultipartSmsTransportMessageFragments(message.getMultipartCount());
partialMessages.put(message.getKey(), container);
}
@ -81,24 +85,9 @@ public class MultipartSmsMessageHandler {
}
}
private byte getIdForRecipient(String recipient) {
Integer currentId;
if (idMap.containsKey(recipient)) {
currentId = idMap.get(recipient);
idMap.remove(recipient);
} else {
currentId = 0;
}
byte id = currentId.byteValue();
idMap.put(recipient, (currentId + 1) % 255);
return id;
}
public ArrayList<String> divideMessage(OutgoingTextMessage message) {
byte identifier = getIdForRecipient(message.getRecipients().getPrimaryRecipient().getNumber());
String number = message.getRecipients().getPrimaryRecipient().getNumber();
byte identifier = MultipartSmsIdentifier.getInstance().getIdForRecipient(number);
return MultipartSmsTransportMessage.getEncoded(message, identifier);
}
}

View File

@ -2,16 +2,28 @@ package org.thoughtcrime.securesms.sms;
public class MultipartSmsTransportMessageFragments {
private static final long VALID_TIME = 60 * 60 * 1000; // 1 Hour
private final byte[][] fragments;
private final long initializedTime;
public MultipartSmsTransportMessageFragments(int count) {
this.fragments = new byte[count][];
this.fragments = new byte[count][];
this.initializedTime = System.currentTimeMillis();
}
public void add(MultipartSmsTransportMessage fragment) {
this.fragments[fragment.getMultipartIndex()] = fragment.getStrippedMessage();
}
public int getSize() {
return this.fragments.length;
}
public boolean isExpired() {
return (System.currentTimeMillis() - initializedTime) >= VALID_TIME;
}
public boolean isComplete() {
for (int i=0;i<fragments.length;i++)
if (fragments[i] == null) return false;
@ -37,4 +49,9 @@ public class MultipartSmsTransportMessageFragments {
return totalMessage;
}
@Override
public String toString() {
return String.format("[Size: %d, Initialized: %d, Exipired: %s, Complete: %s]",
fragments.length, initializedTime, isExpired()+"", isComplete()+"");
}
}