Encrypt and save crash reports, send them the next time TorPlugin start

Will currently fail at runtime; requires a public key and a server onion.
This commit is contained in:
str4d
2016-03-31 11:11:55 +00:00
parent 28086cd359
commit d545aaa892
18 changed files with 342 additions and 32 deletions

View File

@@ -17,6 +17,7 @@ import org.briarproject.messaging.MessagingModule;
import org.briarproject.plugins.PluginsModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.reliability.ReliabilityModule;
import org.briarproject.reporting.ReportingModule;
import org.briarproject.settings.SettingsModule;
import org.briarproject.sync.SyncModule;
import org.briarproject.system.SystemModule;
@@ -42,6 +43,7 @@ import dagger.Module;
PluginsModule.class,
PropertiesModule.class,
ReliabilityModule.class,
ReportingModule.class,
SettingsModule.class,
SyncModule.class,
SystemModule.class,

View File

@@ -18,6 +18,7 @@ import org.briarproject.util.ByteUtils;
import org.briarproject.util.StringUtils;
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.CryptoException;
import org.spongycastle.crypto.Digest;
import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
import org.spongycastle.crypto.digests.SHA256Digest;
@@ -28,6 +29,7 @@ import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.crypto.params.KeyParameter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
@@ -438,6 +440,18 @@ class CryptoComponentImpl implements CryptoComponent {
}
}
public String encryptToKey(byte[] publicKey, byte[] plaintext) {
MessageEncrypter encrypter = new MessageEncrypter(secureRandom);
try {
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);
return AsciiArmour.wrap(ciphertext, 70);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (CryptoException e) {
throw new RuntimeException(e);
}
}
// Key derivation function based on a pseudo-random function - see
// NIST SP 800-108, section 5.1
private byte[] macKdf(SecretKey key, byte[]... inputs) {

View File

@@ -70,6 +70,14 @@ public class MessageEncrypter {
return generator.generateKeyPair();
}
byte[] encrypt(byte[] keyBytes, byte[] plaintext)
throws IOException, CryptoException {
InputStream in = new ByteArrayInputStream(keyBytes);
ECPublicKeyParameters publicKey =
(ECPublicKeyParameters) parser.readKey(in);
return encrypt(publicKey, plaintext);
}
byte[] encrypt(ECPublicKeyParameters pubKey, byte[] plaintext)
throws CryptoException {
IESEngine engine = getEngine();
@@ -159,10 +167,7 @@ public class MessageEncrypter {
}
// Encrypt a decrypted message
InputStream in = new FileInputStream(args[1]);
byte[] b = StringUtils.fromHexString(readFully(in).trim());
in = new ByteArrayInputStream(b);
ECPublicKeyParameters publicKey =
(ECPublicKeyParameters) encrypter.parser.readKey(in);
byte[] publicKey = StringUtils.fromHexString(readFully(in).trim());
String message = readFully(System.in);
byte[] plaintext = message.getBytes(Charset.forName("UTF-8"));
byte[] ciphertext = encrypter.encrypt(publicKey, plaintext);

View File

@@ -0,0 +1,124 @@
package org.briarproject.reporting;
import com.google.common.io.Files;
import net.sourceforge.jsocks.socks.Socks5Proxy;
import net.sourceforge.jsocks.socks.SocksException;
import net.sourceforge.jsocks.socks.SocksSocket;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.reporting.DevConfig;
import org.briarproject.api.reporting.DevReporter;
import org.briarproject.util.StringUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
class DevReporterImpl implements DevReporter {
private static final Logger LOG =
Logger.getLogger(DevReporterImpl.class.getName());
private static final int TIMEOUT = 30 * 1000; // 30 seconds
private static final String PREFIX = "briar-";
private static final String REPORT_EXT = ".report";
private static final String CRLF = "\r\n";
private CryptoComponent crypto;
private DevConfig devConfig;
public DevReporterImpl(CryptoComponent crypto, DevConfig devConfig) {
this.crypto = crypto;
this.devConfig = devConfig;
}
private Socket connectToDevelopers(int socksPort, int devPort)
throws UnknownHostException, SocksException, SocketException {
Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", socksPort);
proxy.resolveAddrLocally(false);
Socket s =
new SocksSocket(proxy, devConfig.getDevOnionAddress(), devPort);
s.setSoTimeout(TIMEOUT);
return s;
}
@Override
public void encryptCrashReportToFile(File crashReportDir,
String crashReport) throws FileNotFoundException {
String encryptedReport =
crypto.encryptToKey(devConfig.getDevPublicKey(),
StringUtils.toUtf8(crashReport));
String filename = PREFIX + new Date().getTime() + REPORT_EXT;
File report = new File(crashReportDir, filename);
PrintWriter writer = null;
try {
writer = new PrintWriter(
new OutputStreamWriter(new FileOutputStream(report)));
writer.append(encryptedReport);
writer.flush();
} finally {
if (writer != null)
writer.close();
}
}
@Override
public void sendCrashReports(File crashReportDir, int socksPort) {
File[] reports = crashReportDir.listFiles();
if (reports == null || reports.length == 0)
return; // No crash reports to send
LOG.info("Connecting to developers' Hidden Service");
Socket s;
try {
s = connectToDevelopers(socksPort,
devConfig.getDevReportPort());
} catch (IOException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, "Tor SOCKS proxy failed", e);
return;
}
LOG.info("Sending crash reports to developers");
OutputStream output;
PrintWriter writer = null;
try {
output = s.getOutputStream();
writer = new PrintWriter(
new OutputStreamWriter(output, "UTF-8"), true);
for (File f : reports) {
List<String> encryptedReport = Files.readLines(f,
Charset.forName("UTF-8"));
writer.append(f.getName()).append(CRLF);
for (String line : encryptedReport) {
writer.append(line).append(CRLF);
}
writer.append(CRLF);
f.delete();
}
writer.flush();
LOG.info("Crash reports sent");
} catch (IOException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, "Connection to developers failed", e);
} finally {
if (writer != null)
writer.close();
}
}
}

View File

@@ -0,0 +1,18 @@
package org.briarproject.reporting;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.reporting.DevConfig;
import org.briarproject.api.reporting.DevReporter;
import dagger.Module;
import dagger.Provides;
@Module
public class ReportingModule {
@Provides
DevReporter provideDevReportTask(CryptoComponent crypto,
DevConfig devConfig) {
return new DevReporterImpl(crypto, devConfig);
}
}