From 60cd307f73d5f31f25ba84541fbe1cce4aae2bc2 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 1 Aug 2015 01:19:16 +0200 Subject: [PATCH] enable axolotl encryption for jingle supported file transfers --- .../entities/DownloadableFile.java | 34 +++---- .../http/HttpDownloadConnection.java | 25 ++--- .../http/HttpUploadConnection.java | 24 ++--- .../services/AbstractConnectionManager.java | 97 +++++++++++++++++++ .../services/XmppConnectionService.java | 2 +- .../xmpp/jingle/JingleConnection.java | 97 +++++++++++++++---- .../xmpp/jingle/JingleInbandTransport.java | 10 +- .../xmpp/jingle/JingleSocks5Transport.java | 6 +- .../xmpp/jingle/JingleTransport.java | 61 ++---------- .../xmpp/jingle/stanzas/Content.java | 5 +- 10 files changed, 223 insertions(+), 138 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java index 452bf815c..d35a4b017 100644 --- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java +++ b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java @@ -24,15 +24,7 @@ public class DownloadableFile extends File { } public long getExpectedSize() { - if (this.aeskey != null) { - if (this.expectedSize == 0) { - return 0; - } else { - return (this.expectedSize / 16 + 1) * 16; - } - } else { - return this.expectedSize; - } + return this.expectedSize; } public String getMimeType() { @@ -58,25 +50,33 @@ public class DownloadableFile extends File { this.sha1sum = sum; } - public void setKey(byte[] key) { - if (key.length == 48) { + public void setKeyAndIv(byte[] keyIvCombo) { + if (keyIvCombo.length == 48) { byte[] secretKey = new byte[32]; byte[] iv = new byte[16]; - System.arraycopy(key, 0, iv, 0, 16); - System.arraycopy(key, 16, secretKey, 0, 32); + System.arraycopy(keyIvCombo, 0, iv, 0, 16); + System.arraycopy(keyIvCombo, 16, secretKey, 0, 32); this.aeskey = secretKey; this.iv = iv; - } else if (key.length >= 32) { + } else if (keyIvCombo.length >= 32) { byte[] secretKey = new byte[32]; - System.arraycopy(key, 0, secretKey, 0, 32); + System.arraycopy(keyIvCombo, 0, secretKey, 0, 32); this.aeskey = secretKey; - } else if (key.length >= 16) { + } else if (keyIvCombo.length >= 16) { byte[] secretKey = new byte[16]; - System.arraycopy(key, 0, secretKey, 0, 16); + System.arraycopy(keyIvCombo, 0, secretKey, 0, 16); this.aeskey = secretKey; } } + public void setKey(byte[] key) { + this.aeskey = key; + } + + public void setIv(byte[] iv) { + this.iv = iv; + } + public byte[] getKey() { return this.aeskey; } diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 51479836a..79e4654be 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -4,15 +4,7 @@ import android.content.Intent; import android.net.Uri; import android.util.Log; -import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.io.CipherOutputStream; -import org.bouncycastle.crypto.modes.AEADBlockCipher; -import org.bouncycastle.crypto.modes.GCMBlockCipher; -import org.bouncycastle.crypto.params.AEADParameters; -import org.bouncycastle.crypto.params.KeyParameter; - import java.io.BufferedInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; @@ -28,6 +20,8 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Transferable; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; @@ -90,7 +84,7 @@ public class HttpDownloadConnection implements Transferable { this.file = mXmppConnectionService.getFileBackend().getFile(message, false); String reference = mUrl.getRef(); if (reference != null && reference.length() == 96) { - this.file.setKey(CryptoHelper.hexToBytes(reference)); + this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference)); } if ((this.message.getEncryption() == Message.ENCRYPTION_OTR @@ -194,6 +188,8 @@ public class HttpDownloadConnection implements Transferable { private boolean interactive = false; + private OutputStream os; + public FileDownloader(boolean interactive) { this.interactive = interactive; } @@ -206,8 +202,10 @@ public class HttpDownloadConnection implements Transferable { updateImageBounds(); finish(); } catch (SSLHandshakeException e) { + FileBackend.close(os); changeStatus(STATUS_OFFER); } catch (IOException e) { + FileBackend.close(os); mXmppConnectionService.showErrorToastInUi(R.string.file_not_found_on_remote_host); cancel(); } @@ -222,14 +220,7 @@ public class HttpDownloadConnection implements Transferable { BufferedInputStream is = new BufferedInputStream(connection.getInputStream()); file.getParentFile().mkdirs(); file.createNewFile(); - OutputStream os; - if (file.getKey() != null) { - AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); - cipher.init(false, new AEADParameters(new KeyParameter(file.getKey()), 128, file.getIv())); - os = new CipherOutputStream(new FileOutputStream(file), cipher); - } else { - os = new FileOutputStream(file); - } + os = AbstractConnectionManager.createOutputStream(file,true); long transmitted = 0; long expected = file.getExpectedSize(); int count = -1; diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java index 70dcc6421..b21d0d412 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java @@ -4,15 +4,8 @@ import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; import android.util.Log; +import android.util.Pair; -import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.io.CipherInputStream; -import org.bouncycastle.crypto.modes.AEADBlockCipher; -import org.bouncycastle.crypto.modes.GCMBlockCipher; -import org.bouncycastle.crypto.params.AEADParameters; -import org.bouncycastle.crypto.params.KeyParameter; - -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -28,6 +21,7 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.UiCallback; import eu.siacs.conversations.utils.CryptoHelper; @@ -105,7 +99,7 @@ public class HttpUploadConnection implements Transferable { || message.getEncryption() == Message.ENCRYPTION_OTR) { this.key = new byte[48]; mXmppConnectionService.getRNG().nextBytes(this.key); - this.file.setKey(this.key); + this.file.setKeyAndIv(this.key); } Jid host = account.getXmppConnection().findDiscoItemByFeature(Xmlns.HTTP_UPLOAD); @@ -152,15 +146,9 @@ public class HttpUploadConnection implements Transferable { if (connection instanceof HttpsURLConnection) { mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, true); } - if (file.getKey() != null) { - AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); - cipher.init(true, new AEADParameters(new KeyParameter(file.getKey()), 128, file.getIv())); - expected = cipher.getOutputSize((int) file.getSize()); - is = new CipherInputStream(new FileInputStream(file), cipher); - } else { - expected = (int) file.getSize(); - is = new FileInputStream(file); - } + Pair pair = AbstractConnectionManager.createInputStream(file,true); + is = pair.first; + expected = pair.second; connection.setRequestMethod("PUT"); connection.setFixedLengthStreamingMode(expected); connection.setDoOutput(true); diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java index 676a09c97..b7e7c8d3a 100644 --- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java @@ -1,5 +1,33 @@ package eu.siacs.conversations.services; +import android.util.Log; +import android.util.Pair; + +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.AEADBlockCipher; +import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.crypto.params.AEADParameters; +import org.bouncycastle.crypto.params.KeyParameter; + +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 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; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.entities.DownloadableFile; + public class AbstractConnectionManager { protected XmppConnectionService mXmppConnectionService; @@ -20,4 +48,73 @@ public class AbstractConnectionManager { return 524288; } } + + public static Pair createInputStream(DownloadableFile file, boolean gcm) { + FileInputStream is; + int size; + try { + is = new FileInputStream(file); + size = (int) file.getSize(); + if (file.getKey() == null) { + return new Pair(is,size); + } + } catch (FileNotFoundException e) { + return null; + } + try { + if (gcm) { + AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); + cipher.init(true, new AEADParameters(new KeyParameter(file.getKey()), 128, file.getIv())); + InputStream cis = new org.bouncycastle.crypto.io.CipherInputStream(is, cipher); + return new Pair<>(cis, cipher.getOutputSize(size)); + } else { + IvParameterSpec ips = new IvParameterSpec(file.getIv()); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(file.getKey(), "AES"), ips); + Log.d(Config.LOGTAG, "opening encrypted input stream"); + return new Pair(new CipherInputStream(is, cipher),(size / 16 + 1) * 16); + } + } catch (InvalidKeyException e) { + return null; + } catch (NoSuchAlgorithmException e) { + return null; + } catch (NoSuchPaddingException e) { + return null; + } catch (InvalidAlgorithmParameterException e) { + return null; + } + } + + public static OutputStream createOutputStream(DownloadableFile file, boolean gcm) { + FileOutputStream os; + try { + os = new FileOutputStream(file); + if (file.getKey() == null) { + return os; + } + } catch (FileNotFoundException e) { + return null; + } + try { + if (gcm) { + AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine()); + cipher.init(false, new AEADParameters(new KeyParameter(file.getKey()), 128, file.getIv())); + return new org.bouncycastle.crypto.io.CipherOutputStream(os, cipher); + } else { + IvParameterSpec ips = new IvParameterSpec(file.getIv()); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(file.getKey(), "AES"), ips); + Log.d(Config.LOGTAG, "opening encrypted output stream"); + return new CipherOutputStream(os, cipher); + } + } catch (InvalidKeyException e) { + return null; + } catch (NoSuchAlgorithmException e) { + return null; + } catch (NoSuchPaddingException e) { + return null; + } catch (InvalidAlgorithmParameterException e) { + return null; + } + } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 61453ab07..ffe587d69 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -755,6 +755,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } break; case Message.ENCRYPTION_AXOLOTL: + message.setAxolotlFingerprint(account.getAxolotlService().getOwnPublicKey().getFingerprint().replaceAll("\\s", "")); if (message.needsUploading()) { if (account.httpUploadAvailable() || message.fixCounterpart()) { this.sendFileMessage(message,delay); @@ -765,7 +766,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa XmppAxolotlMessage axolotlMessage = account.getAxolotlService().fetchAxolotlMessageFromCache(message); if (axolotlMessage == null) { account.getAxolotlService().preparePayloadMessage(message, delay); - message.setAxolotlFingerprint(account.getAxolotlService().getOwnPublicKey().getFingerprint().replaceAll("\\s", "")); } else { packet = mMessageGenerator.generateAxolotlChat(message, axolotlMessage); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index e15fc5224..e9ca66b7c 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -2,9 +2,11 @@ package eu.siacs.conversations.xmpp.jingle; import android.content.Intent; import android.net.Uri; -import android.os.SystemClock; import android.util.Log; +import android.util.Pair; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; @@ -14,13 +16,19 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import eu.siacs.conversations.Config; +import eu.siacs.conversations.crypto.axolotl.AxolotlService; +import eu.siacs.conversations.crypto.axolotl.OnMessageCreatedCallback; +import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.TransferablePlaceholder; +import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.jid.Jid; @@ -66,8 +74,13 @@ public class JingleConnection implements Transferable { private boolean acceptedAutomatically = false; + private XmppAxolotlMessage mXmppAxolotlMessage; + private JingleTransport transport = null; + private OutputStream mFileOutputStream; + private InputStream mFileInputStream; + private OnIqPacketReceived responseListener = new OnIqPacketReceived() { @Override @@ -113,6 +126,14 @@ public class JingleConnection implements Transferable { } }; + public InputStream getFileInputStream() { + return this.mFileInputStream; + } + + public OutputStream getFileOutputStream() { + return this.mFileOutputStream; + } + private OnProxyActivated onProxyActivated = new OnProxyActivated() { @Override @@ -194,7 +215,22 @@ public class JingleConnection implements Transferable { mXmppConnectionService.sendIqPacket(account,response,null); } - public void init(Message message) { + public void init(final Message message) { + if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { + Conversation conversation = message.getConversation(); + conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation.getContact(), new OnMessageCreatedCallback() { + @Override + public void run(XmppAxolotlMessage xmppAxolotlMessage) { + init(message, xmppAxolotlMessage); + } + }); + } else { + init(message, null); + } + } + + private void init(Message message, XmppAxolotlMessage xmppAxolotlMessage) { + this.mXmppAxolotlMessage = xmppAxolotlMessage; this.contentCreator = "initiator"; this.contentName = this.mJingleConnectionManager.nextRandomId(); this.message = message; @@ -238,8 +274,7 @@ public class JingleConnection implements Transferable { }); mergeCandidate(candidate); } else { - Log.d(Config.LOGTAG, - "no primary candidate of our own was found"); + Log.d(Config.LOGTAG,"no primary candidate of our own was found"); sendInitRequest(); } } @@ -267,13 +302,16 @@ public class JingleConnection implements Transferable { this.contentCreator = content.getAttribute("creator"); this.contentName = content.getAttribute("name"); this.transportId = content.getTransportId(); - this.mergeCandidates(JingleCandidate.parse(content.socks5transport() - .getChildren())); + this.mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren())); this.fileOffer = packet.getJingleContent().getFileOffer(); mXmppConnectionService.sendIqPacket(account,packet.generateResponse(IqPacket.TYPE.RESULT),null); if (fileOffer != null) { + Element encrypted = fileOffer.findChild("encrypted", AxolotlService.PEP_PREFIX); + if (encrypted != null) { + this.mXmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, packet.getFrom().toBareJid()); + } Element fileSize = fileOffer.findChild("size"); Element fileNameElement = fileOffer.findChild("name"); if (fileNameElement != null) { @@ -319,10 +357,8 @@ public class JingleConnection implements Transferable { message.setBody(Long.toString(size)); conversation.add(message); mXmppConnectionService.updateConversationUi(); - if (size < this.mJingleConnectionManager - .getAutoAcceptFileSize()) { - Log.d(Config.LOGTAG, "auto accepting file from " - + packet.getFrom()); + if (size < this.mJingleConnectionManager.getAutoAcceptFileSize()) { + Log.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom()); this.acceptedAutomatically = true; this.sendAccept(); } else { @@ -333,22 +369,32 @@ public class JingleConnection implements Transferable { + " allowed size:" + this.mJingleConnectionManager .getAutoAcceptFileSize()); - this.mXmppConnectionService.getNotificationService() - .push(message); + this.mXmppConnectionService.getNotificationService().push(message); } - this.file = this.mXmppConnectionService.getFileBackend() - .getFile(message, false); - if (message.getEncryption() == Message.ENCRYPTION_OTR) { + this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); + if (mXmppAxolotlMessage != null) { + XmppAxolotlMessage.XmppAxolotlKeyTransportMessage transportMessage = account.getAxolotlService().processReceivingKeyTransportMessage(mXmppAxolotlMessage); + if (transportMessage != null) { + message.setEncryption(Message.ENCRYPTION_AXOLOTL); + this.file.setKey(transportMessage.getKey()); + this.file.setIv(transportMessage.getIv()); + message.setAxolotlFingerprint(transportMessage.getFingerprint()); + } else { + Log.d(Config.LOGTAG,"could not process KeyTransportMessage"); + } + } else if (message.getEncryption() == Message.ENCRYPTION_OTR) { byte[] key = conversation.getSymmetricKey(); if (key == null) { this.sendCancel(); this.fail(); return; } else { - this.file.setKey(key); + this.file.setKeyAndIv(key); } } + this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file,message.getEncryption() == Message.ENCRYPTION_AXOLOTL); this.file.setExpectedSize(size); + Log.d(Config.LOGTAG, "receiving file: expecting size of " + this.file.getExpectedSize()); } else { this.sendCancel(); this.fail(); @@ -364,19 +410,30 @@ public class JingleConnection implements Transferable { Content content = new Content(this.contentCreator, this.contentName); if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { content.setTransportId(this.transportId); - this.file = this.mXmppConnectionService.getFileBackend().getFile( - message, false); + this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); + Pair pair; if (message.getEncryption() == Message.ENCRYPTION_OTR) { Conversation conversation = this.message.getConversation(); if (!this.mXmppConnectionService.renewSymmetricKey(conversation)) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not set symmetric key"); cancel(); } + this.file.setKeyAndIv(conversation.getSymmetricKey()); + pair = AbstractConnectionManager.createInputStream(this.file,false); + this.file.setExpectedSize(pair.second); content.setFileOffer(this.file, true); - this.file.setKey(conversation.getSymmetricKey()); + } 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).addChild(mXmppAxolotlMessage.toElement()); } else { + pair = AbstractConnectionManager.createInputStream(this.file,false); + this.file.setExpectedSize(pair.second); content.setFileOffer(this.file, false); } + this.mFileInputStream = pair.first; this.transportId = this.mJingleConnectionManager.nextRandomId(); content.setTransportId(this.transportId); content.socks5transport().setChildren(getCandidatesAsElements()); @@ -748,6 +805,8 @@ public class JingleConnection implements Transferable { if (this.transport != null && this.transport instanceof JingleInbandTransport) { this.transport.disconnect(); } + FileBackend.close(mFileInputStream); + FileBackend.close(mFileOutputStream); if (this.message != null) { if (this.responder.equals(account.getJid())) { this.message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_FAILED)); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 11055b8f4..ab7ab73b8 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -93,7 +93,7 @@ public class JingleInbandTransport extends JingleTransport { digest.reset(); file.getParentFile().mkdirs(); file.createNewFile(); - this.fileOutputStream = createOutputStream(file); + this.fileOutputStream = connection.getFileOutputStream(); if (this.fileOutputStream == null) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not create output stream"); callback.onFileTransferAborted(); @@ -112,15 +112,11 @@ public class JingleInbandTransport extends JingleTransport { this.onFileTransmissionStatusChanged = callback; this.file = file; try { - if (this.file.getKey() != null) { - this.remainingSize = (this.file.getSize() / 16 + 1) * 16; - } else { - this.remainingSize = this.file.getSize(); - } + this.remainingSize = this.file.getExpectedSize(); this.fileSize = this.remainingSize; this.digest = MessageDigest.getInstance("SHA-1"); this.digest.reset(); - fileInputStream = createInputStream(this.file); + fileInputStream = connection.getFileInputStream(); if (fileInputStream == null) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could no create input stream"); callback.onFileTransferAborted(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 55039070b..7545dd646 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -106,13 +106,13 @@ public class JingleSocks5Transport extends JingleTransport { try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); - fileInputStream = createInputStream(file); //file.createInputStream(); + fileInputStream = connection.getFileInputStream(); if (fileInputStream == null) { Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create input stream"); callback.onFileTransferAborted(); return; } - long size = file.getSize(); + long size = file.getExpectedSize(); long transmitted = 0; int count; byte[] buffer = new byte[8192]; @@ -157,7 +157,7 @@ public class JingleSocks5Transport extends JingleTransport { socket.setSoTimeout(30000); file.getParentFile().mkdirs(); file.createNewFile(); - fileOutputStream = createOutputStream(file); + fileOutputStream = connection.getFileOutputStream(); if (fileOutputStream == null) { callback.onFileTransferAborted(); Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create output stream"); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java index 1219794fd..b32111584 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java @@ -1,6 +1,13 @@ package eu.siacs.conversations.xmpp.jingle; import android.util.Log; +import android.util.Pair; + +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.AEADBlockCipher; +import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.crypto.params.AEADParameters; +import org.bouncycastle.crypto.params.KeyParameter; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -31,58 +38,4 @@ public abstract class JingleTransport { final OnFileTransmissionStatusChanged callback); public abstract void disconnect(); - - protected InputStream createInputStream(DownloadableFile file) { - FileInputStream is; - try { - is = new FileInputStream(file); - if (file.getKey() == null) { - return is; - } - } catch (FileNotFoundException e) { - return null; - } - try { - IvParameterSpec ips = new IvParameterSpec(file.getIv()); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(file.getKey(), "AES"), ips); - Log.d(Config.LOGTAG, "opening encrypted input stream"); - return new CipherInputStream(is, cipher); - } catch (InvalidKeyException e) { - return null; - } catch (NoSuchAlgorithmException e) { - return null; - } catch (NoSuchPaddingException e) { - return null; - } catch (InvalidAlgorithmParameterException e) { - return null; - } - } - - protected OutputStream createOutputStream(DownloadableFile file) { - FileOutputStream os; - try { - os = new FileOutputStream(file); - if (file.getKey() == null) { - return os; - } - } catch (FileNotFoundException e) { - return null; - } - try { - IvParameterSpec ips = new IvParameterSpec(file.getIv()); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(file.getKey(), "AES"), ips); - Log.d(Config.LOGTAG, "opening encrypted output stream"); - return new CipherOutputStream(os, cipher); - } catch (InvalidKeyException e) { - return null; - } catch (NoSuchAlgorithmException e) { - return null; - } catch (NoSuchPaddingException e) { - return null; - } catch (InvalidAlgorithmParameterException e) { - return null; - } - } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java index bcadbe778..f752cc5d3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java @@ -25,17 +25,18 @@ public class Content extends Element { this.transportId = sid; } - public void setFileOffer(DownloadableFile actualFile, boolean otr) { + public Element setFileOffer(DownloadableFile actualFile, boolean otr) { Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3"); Element offer = description.addChild("offer"); Element file = offer.addChild("file"); - file.addChild("size").setContent(Long.toString(actualFile.getSize())); + file.addChild("size").setContent(Long.toString(actualFile.getExpectedSize())); if (otr) { file.addChild("name").setContent(actualFile.getName() + ".otr"); } else { file.addChild("name").setContent(actualFile.getName()); } + return file; } public Element getFileOffer() {