From 431b6204cd2ed291b81943b46ea9c2851cb2ec1a Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Thu, 4 Oct 2018 13:22:05 +0200 Subject: refactored file encryption to give access to inner stream MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conscrypt on some plattforms doesn’t like when we close the CipherInputStream. Therefor we refactor the api to give us access to the inner stream so we can close that independently. --- .../messenger/http/HttpUploadConnection.java | 30 ++++---------- .../services/AbstractConnectionManager.java | 27 ++++++------ .../messenger/xmpp/jingle/JingleConnection.java | 48 ++++++++++------------ .../xmpp/jingle/JingleInbandTransport.java | 25 ++++------- .../xmpp/jingle/JingleSocks5Transport.java | 4 +- 5 files changed, 54 insertions(+), 80 deletions(-) (limited to 'src/main/java/de/pixart/messenger') diff --git a/src/main/java/de/pixart/messenger/http/HttpUploadConnection.java b/src/main/java/de/pixart/messenger/http/HttpUploadConnection.java index 16caecd08..a88298417 100644 --- a/src/main/java/de/pixart/messenger/http/HttpUploadConnection.java +++ b/src/main/java/de/pixart/messenger/http/HttpUploadConnection.java @@ -2,9 +2,8 @@ package de.pixart.messenger.http; import android.os.PowerManager; import android.util.Log; -import android.util.Pair; -import java.io.FileNotFoundException; +import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -30,7 +29,7 @@ import de.pixart.messenger.utils.WakeLockHelper; public class HttpUploadConnection implements Transferable { - public static final List WHITE_LISTED_HEADERS = Arrays.asList( + static final List WHITE_LISTED_HEADERS = Arrays.asList( "Authorization", "Cookie", "Expires" @@ -51,8 +50,6 @@ public class HttpUploadConnection implements Transferable { private long transmitted = 0; - private InputStream mFileInputStream; - public HttpUploadConnection(Method method, HttpConnectionManager httpConnectionManager) { this.method = method; this.mHttpConnectionManager = httpConnectionManager; @@ -93,7 +90,6 @@ public class HttpUploadConnection implements Transferable { mHttpConnectionManager.finishUploadConnection(this); message.setTransferable(null); mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, errorMessage); - FileBackend.close(mFileInputStream); } public void init(Message message, boolean delay) { @@ -118,7 +114,7 @@ public class HttpUploadConnection implements Transferable { if (method == Method.P1_S3) { try { - md5 = Checksum.md5(AbstractConnectionManager.createInputStream(file, true).first); + md5 = Checksum.md5(AbstractConnectionManager.upgrade(file, new FileInputStream(file), true)); } catch (Exception e) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": unable to calculate md5()", e); fail(e.getMessage()); @@ -127,18 +123,8 @@ public class HttpUploadConnection implements Transferable { } else { md5 = null; } - - Pair pair; - try { - pair = AbstractConnectionManager.createInputStream(file, true); - } catch (FileNotFoundException e) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not find file to upload - " + e.getMessage()); - fail(e.getMessage()); - return; - } - this.file.setExpectedSize(pair.second); + this.file.setExpectedSize(file.getSize() + (file.getKey() != null ? 16 : 0)); message.resetFileParams(); - this.mFileInputStream = pair.first; this.mSlotRequester.request(method, account, file, mime, md5, new SlotRequester.OnSlotRequested() { @Override public void success(SlotRequester.Slot slot) { @@ -159,9 +145,11 @@ public class HttpUploadConnection implements Transferable { private void upload() { OutputStream os = null; + InputStream fileInputStream = null; HttpURLConnection connection = null; PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_upload_" + message.getUuid()); try { + fileInputStream = new FileInputStream(file); final int expectedFileSize = (int) file.getExpectedSize(); final int readTimeout = (expectedFileSize / 2048) + Config.SOCKET_TIMEOUT; //assuming a minimum transfer speed of 16kbit/s wakeLock.acquire(readTimeout); @@ -188,18 +176,18 @@ public class HttpUploadConnection implements Transferable { connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000); connection.setReadTimeout(readTimeout * 1000); connection.connect(); + final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream, true); os = connection.getOutputStream(); transmitted = 0; int count; byte[] buffer = new byte[4096]; - while (((count = mFileInputStream.read(buffer)) != -1) && !canceled) { + while (((count = innerInputStream.read(buffer)) != -1) && !canceled) { transmitted += count; os.write(buffer, 0, count); mHttpConnectionManager.updateConversationUi(false); } os.flush(); os.close(); - mFileInputStream.close(); int code = connection.getResponseCode(); InputStream is = connection.getErrorStream(); if (is != null) { @@ -234,7 +222,7 @@ public class HttpUploadConnection implements Transferable { Log.d(Config.LOGTAG, "http upload failed " + e.getMessage()); fail(e.getMessage()); } finally { - FileBackend.close(mFileInputStream); + FileBackend.close(fileInputStream); FileBackend.close(os); if (connection != null) { connection.disconnect(); diff --git a/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java b/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java index 65711ef42..a65a990c8 100644 --- a/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java +++ b/src/main/java/de/pixart/messenger/services/AbstractConnectionManager.java @@ -3,18 +3,21 @@ package de.pixart.messenger.services; import android.content.Context; import android.os.PowerManager; import android.os.SystemClock; -import android.util.Pair; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.util.concurrent.atomic.AtomicLong; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; +import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -34,32 +37,26 @@ public class AbstractConnectionManager { this.mXmppConnectionService = service; } - public static Pair createInputStream(DownloadableFile file, boolean gcm) throws FileNotFoundException { - FileInputStream is; - int size; - is = new FileInputStream(file); - size = (int) file.getSize(); - if (file.getKey() == null) { - return new Pair<>(is, size); - } - try { + public static InputStream upgrade(DownloadableFile file, InputStream is, boolean gcm) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, NoSuchProviderException { + if (file.getKey() != null && file.getIv() != null) { if (gcm) { Cipher cipher = Compatibility.twentyTwo() ? Cipher.getInstance(CIPHERMODE) : Cipher.getInstance(CIPHERMODE, PROVIDER); SecretKeySpec keySpec = new SecretKeySpec(file.getKey(), KEYTYPE); IvParameterSpec ivSpec = new IvParameterSpec(file.getIv()); cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); - return new Pair<>(new CipherInputStream(is, cipher), cipher.getOutputSize(size)); + return new CipherInputStream(is, cipher); } else { IvParameterSpec ips = new IvParameterSpec(file.getIv()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(file.getKey(), KEYTYPE), ips); - return new Pair<>(new CipherInputStream(is, cipher), (size / 16 + 1) * 16); + return new CipherInputStream(is, cipher); } - } catch (Exception e) { - throw new AssertionError(e); + } else { + return is; } } + public static OutputStream createAppendedOutputStream(DownloadableFile file) { return createOutputStream(file, false, true); } diff --git a/src/main/java/de/pixart/messenger/xmpp/jingle/JingleConnection.java b/src/main/java/de/pixart/messenger/xmpp/jingle/JingleConnection.java index 6c726c8b9..77540bc9c 100644 --- a/src/main/java/de/pixart/messenger/xmpp/jingle/JingleConnection.java +++ b/src/main/java/de/pixart/messenger/xmpp/jingle/JingleConnection.java @@ -2,8 +2,8 @@ package de.pixart.messenger.xmpp.jingle; import android.util.Base64; import android.util.Log; -import android.util.Pair; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -489,36 +489,32 @@ public class JingleConnection implements Transferable { if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { content.setTransportId(this.transportId); this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); - Pair pair; - try { - if (message.getEncryption() == Message.ENCRYPTION_OTR) { - Conversational conversation = this.message.getConversation(); - if (!this.mXmppConnectionService.renewSymmetricKey((Conversation) conversation)) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not set symmetric key"); - cancel(); - } - Conversation c = (Conversation) this.message.getConversation(); - this.file.setKeyAndIv(c.getSymmetricKey()); - pair = AbstractConnectionManager.createInputStream(this.file, false); - this.file.setExpectedSize(pair.second); - content.setFileOffer(this.file, true, this.ftVersion); - } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { - this.file.setKey(mXmppAxolotlMessage.getInnerKey()); - this.file.setIv(mXmppAxolotlMessage.getIV()); - pair = AbstractConnectionManager.createInputStream(this.file, true); - this.file.setExpectedSize(pair.second); - content.setFileOffer(this.file, false, this.ftVersion).addChild(mXmppAxolotlMessage.toElement()); - } else { - pair = AbstractConnectionManager.createInputStream(this.file, false); - this.file.setExpectedSize(pair.second); - content.setFileOffer(this.file, false, this.ftVersion); + if (message.getEncryption() == Message.ENCRYPTION_OTR) { + Conversational conversation = this.message.getConversation(); + if (!this.mXmppConnectionService.renewSymmetricKey((Conversation) conversation)) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": could not set symmetric key"); + cancel(); } + Conversation c = (Conversation) this.message.getConversation(); + this.file.setKeyAndIv(c.getSymmetricKey()); + this.file.setExpectedSize((file.getSize() / 16 + 1) * 16); + content.setFileOffer(this.file, true, this.ftVersion); + } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { + this.file.setKey(mXmppAxolotlMessage.getInnerKey()); + this.file.setIv(mXmppAxolotlMessage.getIV()); + this.file.setExpectedSize(file.getSize() + 16); + content.setFileOffer(this.file, false, this.ftVersion).addChild(mXmppAxolotlMessage.toElement()); + } else { + this.file.setExpectedSize(file.getSize()); + content.setFileOffer(this.file, false, this.ftVersion); + } + message.resetFileParams(); + try { + this.mFileInputStream = new FileInputStream(file); } catch (FileNotFoundException e) { cancel(); return; } - message.resetFileParams(); - this.mFileInputStream = pair.first; content.setTransportId(this.transportId); content.socks5transport().setChildren(getCandidatesAsElements()); packet.setContent(content); diff --git a/src/main/java/de/pixart/messenger/xmpp/jingle/JingleInbandTransport.java b/src/main/java/de/pixart/messenger/xmpp/jingle/JingleInbandTransport.java index 151e9409f..df8b962c4 100644 --- a/src/main/java/de/pixart/messenger/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/de/pixart/messenger/xmpp/jingle/JingleInbandTransport.java @@ -14,6 +14,7 @@ import de.pixart.messenger.Config; import de.pixart.messenger.entities.Account; import de.pixart.messenger.entities.DownloadableFile; import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.services.AbstractConnectionManager; import de.pixart.messenger.xml.Element; import de.pixart.messenger.xmpp.OnIqPacketReceived; import de.pixart.messenger.xmpp.stanzas.IqPacket; @@ -35,6 +36,7 @@ public class JingleInbandTransport extends JingleTransport { private JingleConnection connection; private InputStream fileInputStream = null; + private InputStream innerInputStream = null; private OutputStream fileOutputStream = null; private long remainingSize = 0; private long fileSize = 0; @@ -129,10 +131,11 @@ public class JingleInbandTransport extends JingleTransport { callback.onFileTransferAborted(); return; } + innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream, false); if (this.connected) { this.sendNextBlock(); } - } catch (NoSuchAlgorithmException e) { + } catch (Exception e) { callback.onFileTransferAborted(); Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": " + e.getMessage()); } @@ -141,26 +144,14 @@ public class JingleInbandTransport extends JingleTransport { @Override public void disconnect() { this.connected = false; - if (this.fileOutputStream != null) { - try { - this.fileOutputStream.close(); - } catch (IOException e) { - - } - } - if (this.fileInputStream != null) { - try { - this.fileInputStream.close(); - } catch (IOException e) { - - } - } + FileBackend.close(fileOutputStream); + FileBackend.close(fileInputStream); } private void sendNextBlock() { byte[] buffer = new byte[this.blockSize]; try { - int count = fileInputStream.read(buffer); + int count = innerInputStream.read(buffer); if (count == -1) { sendClose(); file.setSha1Sum(digest.digest()); @@ -168,7 +159,7 @@ public class JingleInbandTransport extends JingleTransport { fileInputStream.close(); return; } else if (count != buffer.length) { - int rem = fileInputStream.read(buffer, count, buffer.length - count); + int rem = innerInputStream.read(buffer, count, buffer.length - count); if (rem > 0) { count += rem; } diff --git a/src/main/java/de/pixart/messenger/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/de/pixart/messenger/xmpp/jingle/JingleSocks5Transport.java index 374e02750..35498664f 100644 --- a/src/main/java/de/pixart/messenger/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/de/pixart/messenger/xmpp/jingle/JingleSocks5Transport.java @@ -15,6 +15,7 @@ import java.security.NoSuchAlgorithmException; import de.pixart.messenger.Config; import de.pixart.messenger.entities.DownloadableFile; import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.services.AbstractConnectionManager; import de.pixart.messenger.utils.CryptoHelper; import de.pixart.messenger.utils.SocksSocketFactory; import de.pixart.messenger.utils.WakeLockHelper; @@ -94,11 +95,12 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransferAborted(); return; } + final InputStream innerInputStream = AbstractConnectionManager.upgrade(file, fileInputStream, false); long size = file.getExpectedSize(); long transmitted = 0; int count; byte[] buffer = new byte[8192]; - while ((count = fileInputStream.read(buffer)) > 0) { + while ((count = innerInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, count); digest.update(buffer, 0, count); transmitted += count; -- cgit v1.2.3