Merge pull request #2580 from moparisthebest/master

Daniel Gultsch created

Read support for 12-byte IVs in addition to 16-byte IVs

Change summary

src/main/java/eu/siacs/conversations/entities/DownloadableFile.java   | 7 
src/main/java/eu/siacs/conversations/entities/Message.java            | 2 
src/main/java/eu/siacs/conversations/http/AesGcmURLStreamHandler.java | 6 
src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java | 4 
src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java   | 2 
5 files changed, 17 insertions(+), 4 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/entities/DownloadableFile.java 🔗

@@ -49,11 +49,18 @@ public class DownloadableFile extends File {
 	}
 
 	public void setKeyAndIv(byte[] keyIvCombo) {
+		// originally, we used a 16 byte IV, then found for aes-gcm a 12 byte IV is ideal
+		// this code supports reading either length, with sending 12 byte IV to be done in future
 		if (keyIvCombo.length == 48) {
 			this.aeskey = new byte[32];
 			this.iv = new byte[16];
 			System.arraycopy(keyIvCombo, 0, this.iv, 0, 16);
 			System.arraycopy(keyIvCombo, 16, this.aeskey, 0, 32);
+		} else if (keyIvCombo.length == 44) {
+			this.aeskey = new byte[32];
+			this.iv = new byte[12];
+			System.arraycopy(keyIvCombo, 0, this.iv, 0, 12);
+			System.arraycopy(keyIvCombo, 12, this.aeskey, 0, 32);
 		} else if (keyIvCombo.length >= 32) {
 			this.aeskey = new byte[32];
 			System.arraycopy(keyIvCombo, 0, aeskey, 0, 32);

src/main/java/eu/siacs/conversations/entities/Message.java 🔗

@@ -670,7 +670,7 @@ public class Message extends AbstractEntity {
 				final URL url = new URL(body);
 				final String ref = url.getRef();
 				final String protocol = url.getProtocol();
-				final boolean encrypted = ref != null && ref.matches("([A-Fa-f0-9]{2}){48}");
+				final boolean encrypted = ref != null && AesGcmURLStreamHandler.IV_KEY.matcher(ref).matches();
 				treatAsDownloadable = (AesGcmURLStreamHandler.PROTOCOL_NAME.equalsIgnoreCase(protocol) && encrypted)
 						|| (("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) && (oob || encrypted));
 

src/main/java/eu/siacs/conversations/http/AesGcmURLStreamHandler.java 🔗

@@ -4,10 +4,16 @@ import java.io.IOException;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
+import java.util.regex.Pattern;
 
 
 public class AesGcmURLStreamHandler extends URLStreamHandler {
 
+    /**
+     * This matches a 48 or 44 byte IV + KEY hex combo, like used in http/aesgcm upload anchors
+     */
+    public static final Pattern IV_KEY = Pattern.compile("([A-Fa-f0-9]{2}){48}|([A-Fa-f0-9]{2}){44}");
+
     public static final String PROTOCOL_NAME = "aesgcm";
 
     @Override

src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java 🔗

@@ -92,7 +92,7 @@ public class HttpDownloadConnection implements Transferable {
 			message.setRelativeFilePath(message.getUuid() + "." + extension);
 			this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
 			final String reference = mUrl.getRef();
-			if (reference != null && reference.matches("([A-Fa-f0-9]{2}){48}")) {
+			if (reference != null && AesGcmURLStreamHandler.IV_KEY.matcher(reference).matches()) {
 				this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
 			}
 
@@ -373,7 +373,7 @@ public class HttpDownloadConnection implements Transferable {
 			message.setType(Message.TYPE_FILE);
 			final URL url;
 			final String ref = mUrl.getRef();
-			if (ref != null && ref.matches("([A-Fa-f0-9]{2}){48}")) {
+			if (ref != null && AesGcmURLStreamHandler.IV_KEY.matcher(ref).matches()) {
 				url = CryptoHelper.toAesGcmUrl(mUrl);
 			} else {
 				url = mUrl;

src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java 🔗

@@ -105,7 +105,7 @@ public class HttpUploadConnection implements Transferable {
 		if (Config.ENCRYPT_ON_HTTP_UPLOADED
 				|| message.getEncryption() == Message.ENCRYPTION_AXOLOTL
 				|| message.getEncryption() == Message.ENCRYPTION_OTR) {
-			this.key = new byte[48];
+			this.key = new byte[48]; // todo: change this to 44 for 12-byte IV instead of 16-byte at some point in future
 			mXmppConnectionService.getRNG().nextBytes(this.key);
 			this.file.setKeyAndIv(this.key);
 		}