From 197352b6694357535f1c9e5f77f25265c20d5336 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Wed, 9 Aug 2017 23:42:35 -0400 Subject: [PATCH] Read support for 12-byte IVs in addition to 16-byte IVs --- .../eu/siacs/conversations/entities/DownloadableFile.java | 7 +++++++ src/main/java/eu/siacs/conversations/entities/Message.java | 2 +- .../siacs/conversations/http/AesGcmURLStreamHandler.java | 6 ++++++ .../siacs/conversations/http/HttpDownloadConnection.java | 4 ++-- .../eu/siacs/conversations/http/HttpUploadConnection.java | 2 +- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java index 638647a9..8e35a9a6 100644 --- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java +++ b/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); diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 040e6edb..ca88c341 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/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)); diff --git a/src/main/java/eu/siacs/conversations/http/AesGcmURLStreamHandler.java b/src/main/java/eu/siacs/conversations/http/AesGcmURLStreamHandler.java index e74e50b7..00b5985c 100644 --- a/src/main/java/eu/siacs/conversations/http/AesGcmURLStreamHandler.java +++ b/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 diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 83a0cd96..223df4cc 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/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; diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java index fd1ddb1e..b1352b0e 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +++ b/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); }