aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2015-07-29 23:45:37 +0200
committerDaniel Gultsch <daniel@gultsch.de>2015-07-29 23:45:37 +0200
commit58d80f58be2f75b858e93766c61857a78d161005 (patch)
treefe395f0cc34dc70b3b327abcec74cf4400780ab5
parentb7c64cd19d011ad24d64e13ab9154ae07f06a872 (diff)
use gcm for file encryption over http
-rw-r--r--src/main/java/eu/siacs/conversations/entities/DownloadableFile.java97
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java21
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java32
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java4
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java4
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java73
6 files changed, 127 insertions, 104 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
index ca325448..452bf815 100644
--- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
+++ b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
@@ -1,26 +1,7 @@
package eu.siacs.conversations.entities;
-import android.util.Log;
-
import java.io.File;
-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.Key;
-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.utils.MimeUtils;
public class DownloadableFile extends File {
@@ -29,8 +10,7 @@ public class DownloadableFile extends File {
private long expectedSize = 0;
private String sha1sum;
- private Key aeskey;
- private String mime;
+ private byte[] aeskey;
private byte[] iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf };
@@ -84,85 +64,24 @@ public class DownloadableFile extends File {
byte[] iv = new byte[16];
System.arraycopy(key, 0, iv, 0, 16);
System.arraycopy(key, 16, secretKey, 0, 32);
- this.aeskey = new SecretKeySpec(secretKey, "AES");
+ this.aeskey = secretKey;
this.iv = iv;
} else if (key.length >= 32) {
byte[] secretKey = new byte[32];
System.arraycopy(key, 0, secretKey, 0, 32);
- this.aeskey = new SecretKeySpec(secretKey, "AES");
+ this.aeskey = secretKey;
} else if (key.length >= 16) {
byte[] secretKey = new byte[16];
System.arraycopy(key, 0, secretKey, 0, 16);
- this.aeskey = new SecretKeySpec(secretKey, "AES");
+ this.aeskey = secretKey;
}
}
- public Key getKey() {
+ public byte[] getKey() {
return this.aeskey;
}
- public InputStream createInputStream() {
- if (this.getKey() == null) {
- try {
- return new FileInputStream(this);
- } catch (FileNotFoundException e) {
- return null;
- }
- } else {
- try {
- IvParameterSpec ips = new IvParameterSpec(iv);
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, this.getKey(), ips);
- Log.d(Config.LOGTAG, "opening encrypted input stream");
- return new CipherInputStream(new FileInputStream(this), cipher);
- } catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
- return null;
- } catch (NoSuchPaddingException e) {
- Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
- return null;
- } catch (InvalidKeyException e) {
- Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
- return null;
- } catch (InvalidAlgorithmParameterException e) {
- Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
- return null;
- } catch (FileNotFoundException e) {
- return null;
- }
- }
- }
-
- public OutputStream createOutputStream() {
- if (this.getKey() == null) {
- try {
- return new FileOutputStream(this);
- } catch (FileNotFoundException e) {
- return null;
- }
- } else {
- try {
- IvParameterSpec ips = new IvParameterSpec(this.iv);
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE, this.getKey(), ips);
- Log.d(Config.LOGTAG, "opening encrypted output stream");
- return new CipherOutputStream(new FileOutputStream(this),
- cipher);
- } catch (NoSuchAlgorithmException e) {
- Log.d(Config.LOGTAG, "no such algo: " + e.getMessage());
- return null;
- } catch (NoSuchPaddingException e) {
- Log.d(Config.LOGTAG, "no such padding: " + e.getMessage());
- return null;
- } catch (InvalidKeyException e) {
- Log.d(Config.LOGTAG, "invalid key: " + e.getMessage());
- return null;
- } catch (InvalidAlgorithmParameterException e) {
- Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage());
- return null;
- } catch (FileNotFoundException e) {
- return null;
- }
- }
+ public byte[] getIv() {
+ return this.iv;
}
}
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index 30d9a393..51479836 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -2,10 +2,17 @@ package eu.siacs.conversations.http;
import android.content.Intent;
import android.net.Uri;
-import android.os.SystemClock;
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;
@@ -206,7 +213,7 @@ public class HttpDownloadConnection implements Transferable {
}
}
- private void download() throws SSLHandshakeException, IOException {
+ private void download() throws IOException {
HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
if (connection instanceof HttpsURLConnection) {
mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
@@ -215,9 +222,13 @@ public class HttpDownloadConnection implements Transferable {
BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
file.getParentFile().mkdirs();
file.createNewFile();
- OutputStream os = file.createOutputStream();
- if (os == null) {
- throw new IOException();
+ 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);
}
long transmitted = 0;
long expected = file.getExpectedSize();
diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
index c9fb3d8c..70dcc642 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
@@ -1,8 +1,18 @@
package eu.siacs.conversations.http;
import android.app.PendingIntent;
+import android.content.Intent;
+import android.net.Uri;
import android.util.Log;
+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;
@@ -43,7 +53,7 @@ public class HttpUploadConnection implements Transferable {
private byte[] key = null;
private long transmitted = 0;
- private long expected = 1;
+ private int expected = 1;
public HttpUploadConnection(HttpConnectionManager httpConnectionManager) {
this.mHttpConnectionManager = httpConnectionManager;
@@ -142,14 +152,21 @@ 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);
+ }
connection.setRequestMethod("PUT");
- connection.setFixedLengthStreamingMode((int) file.getExpectedSize());
+ connection.setFixedLengthStreamingMode(expected);
connection.setDoOutput(true);
connection.connect();
os = connection.getOutputStream();
- is = file.createInputStream();
transmitted = 0;
- expected = file.getExpectedSize();
int count = -1;
byte[] buffer = new byte[4096];
while (((count = is.read(buffer)) != -1) && !canceled) {
@@ -163,11 +180,13 @@ public class HttpUploadConnection implements Transferable {
int code = connection.getResponseCode();
if (code == 200 || code == 201) {
Log.d(Config.LOGTAG, "finished uploading file");
- Message.FileParams params = message.getFileParams();
if (key != null) {
mGetUrl = new URL(mGetUrl.toString() + "#" + CryptoHelper.bytesToHex(key));
}
mXmppConnectionService.getFileBackend().updateFileParams(message, mGetUrl);
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
+ intent.setData(Uri.fromFile(file));
+ mXmppConnectionService.sendBroadcast(intent);
message.setTransferable(null);
message.setCounterpart(message.getConversation().getJid().toBareJid());
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
@@ -188,12 +207,13 @@ public class HttpUploadConnection implements Transferable {
}
});
} else {
- mXmppConnectionService.resendMessage(message,delayed);
+ mXmppConnectionService.resendMessage(message, delayed);
}
} else {
fail();
}
} catch (IOException e) {
+ e.printStackTrace();
Log.d(Config.LOGTAG,"http upload failed "+e.getMessage());
fail();
} finally {
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 6f31f163..11055b8f 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 = file.createOutputStream();
+ this.fileOutputStream = createOutputStream(file);
if (this.fileOutputStream == null) {
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not create output stream");
callback.onFileTransferAborted();
@@ -120,7 +120,7 @@ public class JingleInbandTransport extends JingleTransport {
this.fileSize = this.remainingSize;
this.digest = MessageDigest.getInstance("SHA-1");
this.digest.reset();
- fileInputStream = this.file.createInputStream();
+ fileInputStream = createInputStream(this.file);
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 8d74f44e..55039070 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
@@ -106,7 +106,7 @@ public class JingleSocks5Transport extends JingleTransport {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
- fileInputStream = file.createInputStream();
+ fileInputStream = createInputStream(file); //file.createInputStream();
if (fileInputStream == null) {
Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": could not create input stream");
callback.onFileTransferAborted();
@@ -157,7 +157,7 @@ public class JingleSocks5Transport extends JingleTransport {
socket.setSoTimeout(30000);
file.getParentFile().mkdirs();
file.createNewFile();
- fileOutputStream = file.createOutputStream();
+ fileOutputStream = createOutputStream(file);
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 e832d3f5..1219794f 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java
@@ -1,5 +1,24 @@
package eu.siacs.conversations.xmpp.jingle;
+import android.util.Log;
+
+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 abstract class JingleTransport {
@@ -12,4 +31,58 @@ 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;
+ }
+ }
}