use of com.biglybt.core.pairing.PairedServiceRequestHandler in project BiglyBT by BiglySoftware.
the class PairingManagerTunnelHandler method createTunnel.
private boolean createTunnel(InetAddress originator, long session, String sid, SecretKeySpec secret, String tunnel_url, String endpoint_url) {
PairedServiceImpl ps = manager.getService(sid);
if (ps == null) {
Debug.out("Service '" + sid + "' not registered");
return (false);
}
PairedServiceRequestHandler handler = ps.getHandler();
if (handler == null) {
Debug.out("Service '" + sid + "' has no handler registered");
return (false);
}
String key = originator.getHostAddress() + ":" + session + ":" + sid;
synchronized (tunnels) {
PairManagerTunnel existing = tunnels.get(key);
if (existing != null) {
return (true);
}
if (tunnels.size() > MAX_TUNNELS) {
long oldest_active = Long.MAX_VALUE;
PairManagerTunnel oldest_tunnel = null;
for (PairManagerTunnel t : tunnels.values()) {
long at = t.getLastActive();
if (at < oldest_active) {
oldest_active = at;
oldest_tunnel = t;
}
}
oldest_tunnel.destroy();
tunnels.remove(oldest_tunnel.getKey());
}
PairManagerTunnel tunnel = new PairManagerTunnel(this, key, originator, sid, handler, secret, tunnel_url, endpoint_url);
tunnels.put(key, tunnel);
System.out.println("Created pair manager tunnel: " + tunnel.getString());
}
return (true);
}
use of com.biglybt.core.pairing.PairedServiceRequestHandler in project BiglyBT by BiglySoftware.
the class PairingManagerTunnelHandler method handleLocalTunnel.
protected boolean handleLocalTunnel(TrackerWebPageRequest request, TrackerWebPageResponse response) throws IOException {
start();
if (SRP_VERIFIER == null || !active) {
throw (new IOException("Secure pairing is not enabled"));
}
boolean good_request = false;
try {
// remove /pairing/tunnel/
String url = request.getURL().substring(16);
int q_pos = url.indexOf('?');
Map<String, String> args = new HashMap<>();
if (q_pos != -1) {
String args_str = url.substring(q_pos + 1);
String[] bits = args_str.split("&");
for (String arg : bits) {
String[] x = arg.split("=");
if (x.length == 2) {
args.put(x[0].toLowerCase(), x[1]);
}
}
url = url.substring(0, q_pos);
}
if (url.startsWith("create")) {
String ac = args.get("ac");
String sid = args.get("sid");
if (ac == null || sid == null) {
throw (new IOException("Access code or service id missing"));
}
if (!ac.equals(manager.peekAccessCode())) {
throw (new IOException("Invalid access code"));
}
PairedServiceImpl ps = manager.getService(sid);
if (ps == null) {
good_request = true;
throw (new IOException("Service '" + sid + "' not registered"));
}
PairedServiceRequestHandler handler = ps.getHandler();
if (handler == null) {
good_request = true;
throw (new IOException("Service '" + sid + "' has no handler registered"));
}
JSONObject json = new JSONObject();
JSONObject result = new JSONObject();
json.put("result", result);
byte[] ss = new byte[] { SRP_SALT[0], SRP_SALT[1], SRP_SALT[2], SRP_SALT[3] };
long tunnel_id = RandomUtils.nextSecureAbsoluteLong();
String tunnel_name = Base32.encode(ss) + "_" + tunnel_id;
synchronized (local_server_map) {
long diff = SystemTime.getMonotonousTime() - last_local_server_create_time;
if (diff < 5000) {
try {
long sleep = 5000 - diff;
System.out.println("Sleeping for " + sleep + " before starting srp");
Thread.sleep(sleep);
} catch (Throwable e) {
}
}
SRP6Server server = new SRP6Server();
server.init(N_3072, G_3072, SRP_VERIFIER, new SHA256Digest(), RandomUtils.SECURE_RANDOM);
BigInteger B = server.generateServerCredentials();
local_server_map.put(tunnel_name, new Object[] { server, handler, null, null });
last_local_server_create_time = SystemTime.getMonotonousTime();
total_local_servers++;
result.put("srp_salt", Base32.encode(SRP_SALT));
result.put("srp_b", Base32.encode(B.toByteArray()));
Map<String, String> headers = request.getHeaders();
String host = headers.get("host");
// remove port number
int pos = host.lastIndexOf("]");
if (pos != -1) {
// ipv6 literal
host = host.substring(0, pos + 1);
} else {
pos = host.indexOf(':');
if (pos != -1) {
host = host.substring(0, pos);
}
}
String abs_url = request.getAbsoluteURL().toString();
// unfortunately there is some nasty code that uses a configured tracker
// address as the default host
abs_url = UrlUtils.setHost(new URL(abs_url), host).toExternalForm();
pos = abs_url.indexOf("/create");
String tunnel_url = abs_url.substring(0, pos) + "/id/" + tunnel_name;
result.put("url", tunnel_url);
}
response.getOutputStream().write(JSONUtils.encodeToJSON(json).getBytes("UTF-8"));
response.setContentType("application/json; charset=UTF-8");
response.setGZIP(true);
good_request = true;
return (true);
} else if (url.startsWith("id/")) {
String tunnel_name = url.substring(3);
Object[] entry;
synchronized (local_server_map) {
entry = local_server_map.get(tunnel_name);
if (entry == null) {
good_request = true;
throw (new IOException("Unknown tunnel id"));
}
}
String srp_a = args.get("srp_a");
String enc_data = args.get("enc_data");
String enc_iv = args.get("enc_iv");
if (srp_a != null && enc_data != null && enc_iv != null) {
try {
synchronized (local_server_map) {
long diff = SystemTime.getMonotonousTime() - last_local_server_agree_time;
if (diff < 5000) {
try {
long sleep = 5000 - diff;
System.out.println("Sleeping for " + sleep + " before completing srp");
Thread.sleep(sleep);
} catch (Throwable e) {
}
}
}
JSONObject json = new JSONObject();
JSONObject result = new JSONObject();
json.put("result", result);
SRP6Server server = (SRP6Server) entry[0];
BigInteger A = new BigInteger(Base32.decode(srp_a));
BigInteger serverS = server.calculateSecret(A);
byte[] shared_secret = serverS.toByteArray();
Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] key = new byte[16];
System.arraycopy(shared_secret, 0, key, 0, 16);
SecretKeySpec secret = new SecretKeySpec(key, "AES");
decipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(Base32.decode(enc_iv)));
byte[] dec = decipher.doFinal(Base32.decode(enc_data));
JSONObject dec_json = (JSONObject) JSONUtils.decodeJSON(new String(dec, "UTF-8"));
String tunnel_url = (String) dec_json.get("url");
if (!tunnel_url.contains(tunnel_name)) {
throw (new IOException("Invalid tunnel url"));
}
String endpoint_url = (String) dec_json.get("endpoint");
entry[2] = secret;
entry[3] = endpoint_url;
result.put("state", "activated");
response.getOutputStream().write(JSONUtils.encodeToJSON(json).getBytes("UTF-8"));
response.setContentType("application/json; charset=UTF-8");
response.setGZIP(true);
good_request = true;
return (true);
} catch (Throwable e) {
throw (new IOException(Debug.getNestedExceptionMessage(e)));
} finally {
last_local_server_agree_time = SystemTime.getMonotonousTime();
}
} else if (args.containsKey("close")) {
synchronized (local_server_map) {
local_server_map.remove(tunnel_name);
}
good_request = true;
return (true);
} else {
PairedServiceRequestHandler request_handler = (PairedServiceRequestHandler) entry[1];
SecretKeySpec secret = (SecretKeySpec) entry[2];
String endpoint_url = (String) entry[3];
if (secret == null) {
throw (new IOException("auth not completed"));
}
byte[] request_data = FileUtil.readInputStreamAsByteArray(request.getInputStream());
try {
byte[] decrypted;
{
byte[] IV = new byte[16];
System.arraycopy(request_data, 0, IV, 0, IV.length);
Cipher decipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(IV));
decrypted = decipher.doFinal(request_data, 16, request_data.length - 16);
}
byte[] reply_bytes = request_handler.handleRequest(request.getClientAddress2().getAddress(), endpoint_url, decrypted);
{
Cipher encipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = encipher.getParameters();
byte[] IV = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] enc = encipher.doFinal(reply_bytes);
byte[] rep_bytes = new byte[IV.length + enc.length];
System.arraycopy(IV, 0, rep_bytes, 0, IV.length);
System.arraycopy(enc, 0, rep_bytes, IV.length, enc.length);
response.getOutputStream().write(rep_bytes);
response.setContentType("application/octet-stream");
good_request = true;
return (true);
}
} catch (Throwable e) {
throw (new IOException(Debug.getNestedExceptionMessage(e)));
}
}
}
throw (new IOException("Unknown tunnel operation"));
} finally {
if (!good_request) {
manager.recordRequest("SRP", request.getClientAddress2().getAddress().getHostAddress(), false);
}
}
}
Aggregations