From 8524cc5598bd0b866aaefcd3f4e7bccd8560f1a5 Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sat, 25 May 2013 13:17:18 -0700 Subject: [PATCH] Resolved a few MMS issues. 1) Fixed the "Unsupported Encoding!" problem. 2) Workaround for the Sprint issue, where the MMSC is adding a single extra byte to the end of each encrypted message. 3) Fixed the "large blob of base64 text" on encrypted MMS problem. --- .../securesms/crypto/DecryptingQueue.java | 16 +++++++++++++++- .../securesms/crypto/KeyExchangeMessage.java | 3 ++- .../securesms/mms/MmsDownloadHelper.java | 7 +++---- .../securesms/mms/MmsSendHelper.java | 6 +++--- .../thoughtcrime/securesms/mms/PartParser.java | 8 ++++++-- .../securesms/service/MmsSender.java | 17 +++++++++-------- 6 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java index 99fb8ffff2..edf9233881 100644 --- a/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java +++ b/src/org/thoughtcrime/securesms/crypto/DecryptingQueue.java @@ -190,7 +190,21 @@ public class DecryptingQueue { synchronized (SessionCipher.CIPHER_LOCK) { Log.w("DecryptingQueue", "Decrypting: " + Hex.toString(ciphertextPduBytes)); SessionCipher cipher = new SessionCipher(context, masterSecret, recipient, new TextTransport()); - plaintextPduBytes = cipher.decryptMessage(ciphertextPduBytes); + try { + plaintextPduBytes = cipher.decryptMessage(ciphertextPduBytes); + } catch (InvalidMessageException ime) { + // XXX - For some reason, Sprint seems to append a single character to the + // end of message text segments. I don't know why, so here we just try + // truncating the message by one if the MAC fails. + if (ciphertextPduBytes.length > 2) { + Log.w("DecryptingQueue", "Attempting truncated decrypt..."); + byte[] truncated = new byte[ciphertextPduBytes.length - 1]; + System.arraycopy(ciphertextPduBytes, 0, truncated, 0, truncated.length); + plaintextPduBytes = cipher.decryptMessage(truncated); + } else { + throw ime; + } + } } MultimediaMessagePdu plaintextGenericPdu = (MultimediaMessagePdu)new PduParser(plaintextPduBytes).parse(); diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeMessage.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeMessage.java index 67e8806864..2a28518323 100644 --- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeMessage.java +++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeMessage.java @@ -90,7 +90,8 @@ public class KeyExchangeMessage { this.serialized = messageBody; if (messageVersion > Message.SUPPORTED_VERSION) - throw new InvalidVersionException("Key exchange with version: " + messageVersion + " but we only support: " + Message.SUPPORTED_VERSION); + throw new InvalidVersionException("Key exchange with version: " + messageVersion + + " but we only support: " + Message.SUPPORTED_VERSION); if (messageVersion >= 1) keyBytes = Base64.decodeWithoutPadding(messageBody); diff --git a/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java b/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java index 8ea09dd591..bf94d65648 100644 --- a/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java +++ b/src/org/thoughtcrime/securesms/mms/MmsDownloadHelper.java @@ -23,16 +23,15 @@ import android.util.Log; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; -import ws.com.google.android.mms.pdu.PduParser; -import ws.com.google.android.mms.pdu.RetrieveConf; - import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import ws.com.google.android.mms.pdu.PduParser; +import ws.com.google.android.mms.pdu.RetrieveConf; + public class MmsDownloadHelper extends MmsCommunication { private static byte[] makeRequest(Context context, MmsConnectionParameters connectionParameters, String url) diff --git a/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java b/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java index 8b0ec4cd58..dcbf3c6b65 100644 --- a/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java +++ b/src/org/thoughtcrime/securesms/mms/MmsSendHelper.java @@ -30,13 +30,13 @@ import org.apache.http.entity.ByteArrayEntity; import org.thoughtcrime.securesms.service.MmscProcessor; import org.thoughtcrime.securesms.util.Util; -import ws.com.google.android.mms.pdu.PduParser; -import ws.com.google.android.mms.pdu.SendConf; - import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import ws.com.google.android.mms.pdu.PduParser; +import ws.com.google.android.mms.pdu.SendConf; + public class MmsSendHelper extends MmsCommunication { private static byte[] makePost(Context context, MmsConnectionParameters parameters, byte[] mms) throws ClientProtocolException, IOException { diff --git a/src/org/thoughtcrime/securesms/mms/PartParser.java b/src/org/thoughtcrime/securesms/mms/PartParser.java index b152075a40..74986c437a 100644 --- a/src/org/thoughtcrime/securesms/mms/PartParser.java +++ b/src/org/thoughtcrime/securesms/mms/PartParser.java @@ -19,8 +19,12 @@ public class PartParser { String partText; try { - partText = new String(body.getPart(i).getData(), - CharacterSets.getMimeName(body.getPart(i).getCharset())); + String characterSet = CharacterSets.getMimeName(body.getPart(i).getCharset()); + + if (characterSet.equals(CharacterSets.MIMENAME_ANY_CHARSET)) + characterSet = CharacterSets.MIMENAME_ISO_8859_1; + + partText = new String(body.getPart(i).getData(), characterSet); } catch (UnsupportedEncodingException e) { Log.w("PartParser", e); partText = "Unsupported Encoding!"; diff --git a/src/org/thoughtcrime/securesms/service/MmsSender.java b/src/org/thoughtcrime/securesms/service/MmsSender.java index 8dc3136008..6fa5b39037 100644 --- a/src/org/thoughtcrime/securesms/service/MmsSender.java +++ b/src/org/thoughtcrime/securesms/service/MmsSender.java @@ -209,20 +209,21 @@ public class MmsSender extends MmscProcessor { EncodedStringValue[] encodedRecipient = pdu.getTo(); String recipient = encodedRecipient[0].getString(); byte[] pduBytes = new PduComposer(context, pdu).make(); - byte[] encryptedPdu = getEncryptedPdu(masterSecret, recipient, pduBytes); - Log.w("MmsSendeR", "Got encrypted bytes: " + encryptedPdu.length); - PduBody body = new PduBody(); - PduPart part = new PduPart(); + byte[] encryptedPduBytes = getEncryptedPdu(masterSecret, recipient, pduBytes); + + PduBody body = new PduBody(); + PduPart part = new PduPart(); + SendReq encryptedPdu = new SendReq(pdu.getPduHeaders(), body); part.setContentId((System.currentTimeMillis()+"").getBytes()); part.setContentType(ContentType.TEXT_PLAIN.getBytes()); part.setName((System.currentTimeMillis()+"").getBytes()); - part.setData(encryptedPdu); + part.setData(encryptedPduBytes); body.addPart(part); - pdu.setSubject(new EncodedStringValue(WirePrefix.calculateEncryptedMmsSubject())); - pdu.setBody(body); + encryptedPdu.setSubject(new EncodedStringValue(WirePrefix.calculateEncryptedMmsSubject())); + encryptedPdu.setBody(body); - return pdu; + return encryptedPdu; } private void scheduleSendWithMmsRadioAndProxy(SendItem item) {