Search in sources :

Example 1 with PairedServiceImpl

use of com.biglybt.core.pairing.impl.PairingManagerImpl.PairedServiceImpl 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);
}
Also used : PairedServiceRequestHandler(com.biglybt.core.pairing.PairedServiceRequestHandler) PairedServiceImpl(com.biglybt.core.pairing.impl.PairingManagerImpl.PairedServiceImpl)

Example 2 with PairedServiceImpl

use of com.biglybt.core.pairing.impl.PairingManagerImpl.PairedServiceImpl 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);
        }
    }
}
Also used : IOException(java.io.IOException) URL(java.net.URL) JSONObject(org.json.simple.JSONObject) SHA256Digest(org.gudy.bouncycastle.crypto.digests.SHA256Digest) PairedServiceRequestHandler(com.biglybt.core.pairing.PairedServiceRequestHandler) SecretKeySpec(javax.crypto.spec.SecretKeySpec) SRP6Server(org.gudy.bouncycastle.crypto.agreement.srp.SRP6Server) BigInteger(java.math.BigInteger) PairedServiceImpl(com.biglybt.core.pairing.impl.PairingManagerImpl.PairedServiceImpl) IvParameterSpec(javax.crypto.spec.IvParameterSpec) Cipher(javax.crypto.Cipher) AlgorithmParameters(java.security.AlgorithmParameters)

Aggregations

PairedServiceRequestHandler (com.biglybt.core.pairing.PairedServiceRequestHandler)2 PairedServiceImpl (com.biglybt.core.pairing.impl.PairingManagerImpl.PairedServiceImpl)2 IOException (java.io.IOException)1 BigInteger (java.math.BigInteger)1 URL (java.net.URL)1 AlgorithmParameters (java.security.AlgorithmParameters)1 Cipher (javax.crypto.Cipher)1 IvParameterSpec (javax.crypto.spec.IvParameterSpec)1 SecretKeySpec (javax.crypto.spec.SecretKeySpec)1 SRP6Server (org.gudy.bouncycastle.crypto.agreement.srp.SRP6Server)1 SHA256Digest (org.gudy.bouncycastle.crypto.digests.SHA256Digest)1 JSONObject (org.json.simple.JSONObject)1