enable axolotl encryption for jingle supported file transfers

This commit is contained in:
Daniel Gultsch 2015-08-01 01:19:16 +02:00
parent 6059b96456
commit 60cd307f73
10 changed files with 223 additions and 138 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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<InputStream,Integer> pair = AbstractConnectionManager.createInputStream(file,true);
is = pair.first;
expected = pair.second;
connection.setRequestMethod("PUT");
connection.setFixedLengthStreamingMode(expected);
connection.setDoOutput(true);

View File

@ -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<InputStream,Integer> 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<InputStream,Integer>(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<InputStream,Integer>(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;
}
}
}

View File

@ -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);
}

View File

@ -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<InputStream,Integer> 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));

View File

@ -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();

View File

@ -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");

View File

@ -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;
}
}
}

View File

@ -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() {