package org.torproject.jtor.hiddenservice.publishing; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStreamWriter; import java.math.BigInteger; import java.net.InetAddress; import java.net.Socket; import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import org.torproject.jtor.TorException; import org.torproject.jtor.crypto.TorPrivateKey; import org.torproject.jtor.crypto.TorPublicKey; import org.torproject.jtor.data.exitpolicy.PortRange; import org.torproject.jtor.directory.Directory; import org.torproject.jtor.directory.DirectoryServer; import org.torproject.jtor.directory.Router; import org.torproject.jtor.hiddenservice.ServiceDescriptor; // TODO: Auto-generated Javadoc /** * The Class HiddenService. */ public class HiddenService { /** The introduction points. */ private ArrayList<Router> introductionPoints = new ArrayList<Router>(); /** The hidden service descriptor. */ private ServiceDescriptor hiddenServiceDescriptor; /** The private key. */ private TorPrivateKey privateKey; public TorPrivateKey getPrivateKey() { return privateKey; } /** The service name. */ private String serviceName; /** The service ports. */ private PortRange servicePorts; /** the host name .onion address */ private String hostname; private Directory directory; public HiddenService(String serviceName, PortRange servicePorts, TorPrivateKey key){ } public HiddenService(PortRange servicePorts, TorPrivateKey key){ } public HiddenService(TorPrivateKey key){ this.privateKey = key; generateServiceDescriptor(); } /** * Instantiates a brand new hidden service. * * @param serviceName * the service name * @param servicePorts * the service's ports */ public HiddenService(String serviceName, PortRange servicePorts, Directory directory) { this.serviceName = serviceName; this.servicePorts = servicePorts; this.directory = directory; generateKeyPair(); generateServiceDescriptor(); } /** * * @param hsDirectory * the directory of the hidden service configuration files private_key and hostname * will instantiate a hidden service from tor HS configuration. * @throws FileNotFoundException */ public static HiddenService createServiceFromDirectory(File hsDirectory) throws TorException{ if (hsDirectory == null || !hsDirectory.isDirectory()) throw new TorException("Directory is null or is not a directory."); else { FileInputStream fileScanner; try { fileScanner = new FileInputStream(hsDirectory = new File(hsDirectory.getAbsolutePath()+"/private_key")); if (!hsDirectory.exists()) throw new TorException(new FileNotFoundException("Hidden Service Private Key file not found")); byte[] fileData = new byte[(int)hsDirectory.length()]; fileScanner.read(fileData); TorPrivateKey privateKey = TorPrivateKey.createFromPEMBuffer(new String(fileData)); //Log: Successfully loaded Private Key fileScanner = new FileInputStream(hsDirectory = new File(hsDirectory.getParent()+"/hostname")); fileData = new byte[(int)hsDirectory.length()]; fileScanner.read(fileData); return new HiddenService(privateKey); }catch (IOException e){ throw new TorException(e); } } } public String getHostname() { return hostname; } private void generateKeyPair() { privateKey = TorPrivateKey.generateNewKeypair(); } /** * Gets the service name. * * @return the service name */ public String getServiceName() { return serviceName; } /** * Sets the service name. * * @param serviceName * the new service name */ public void setServiceName(String serviceName) { this.serviceName = serviceName; } /** * Gets the service ports. * * @return the service ports */ public PortRange getServicePorts() { return servicePorts; } /** * Sets the service ports. * * @param servicePorts * the new service ports */ public void setServicePorts(PortRange servicePorts) { this.servicePorts = servicePorts; } /** * Gets the introduction points. * * @return the introduction points */ public ArrayList<Router> getIntroductionPoints() { return introductionPoints; } /** * Gets the hidden service descripter. * * @return the hidden service descripter */ public ServiceDescriptor getHiddenServiceDescriptor() { return hiddenServiceDescriptor; } /** * Sets the private key. * * @param privateKey * the new private key */ public void setPrivateKey(TorPrivateKey privateKey) { this.privateKey = privateKey; } /** * Generate service descriptor. */ public void generateServiceDescriptor() { if (privateKey != null) { hiddenServiceDescriptor = ServiceDescriptor.generateServiceDescriptor(privateKey); hiddenServiceDescriptor.generateDescriptorID(); } } /** * Advertise descriptor. */ public void advertiseDescriptor() { String descriptor = hiddenServiceDescriptor.getDescriptorString(); final String path = "/tor/rendezvous/publish"; ArrayList<DirectoryServer> authorities = new ArrayList<DirectoryServer>(directory.getDirectoryAuthorities()); for (DirectoryServer server : authorities) { // Create a socket to the host int port = 80; InetAddress addr = server.getAddress().toInetAddress(); try { Socket socket = new Socket(addr, port); BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF8")); wr.write("POST "+path+" HTTP/1.1\r\n"); // Send data wr.write(descriptor); wr.flush(); wr.close(); } catch (Exception e) { //log post error } } } /** * Adds the introduction point. * * @param point * the point */ public void addIntroductionPoint(Router point) { hiddenServiceDescriptor.addRendPoint(point); } /** * Establish introduction points. */ public void establishIntroductionPoints() { } public String toString() { hiddenServiceDescriptor.generateDescriptorString(); return ("Hidden Service: " + serviceName + ":" + servicePorts.toString() + " Permanent ID : " + toHex(hiddenServiceDescriptor.getPermanentID()) + " Service Descriptor : \n" + hiddenServiceDescriptor.getDescriptorString()); } /** * helper method, not sure if I need it or where to put it... * @param bytes * @return */ private static String toHex(byte[] bytes) { BigInteger bi = new BigInteger(1, bytes); return String.format("%0" + (bytes.length << 1) + "X", bi); } }