Package com.subgraph.orchid.circuits

Source Code of com.subgraph.orchid.circuits.CircuitExtender

package com.subgraph.orchid.circuits;

import java.util.logging.Logger;

import com.subgraph.orchid.Cell;
import com.subgraph.orchid.CircuitNode;
import com.subgraph.orchid.RelayCell;
import com.subgraph.orchid.Router;
import com.subgraph.orchid.TorException;
import com.subgraph.orchid.circuits.cells.CellImpl;
import com.subgraph.orchid.circuits.cells.RelayCellImpl;
import com.subgraph.orchid.crypto.TorCreateFastKeyAgreement;
import com.subgraph.orchid.crypto.TorKeyAgreement;
import com.subgraph.orchid.crypto.TorMessageDigest;
import com.subgraph.orchid.crypto.TorStreamCipher;

public class CircuitExtender {
  private final static Logger logger = Logger.getLogger(CircuitExtender.class.getName());
 
  private final static int DH_BYTES = 1024 / 8;
  private final static int PKCS1_OAEP_PADDING_OVERHEAD = 42;
  private final static int CIPHER_KEY_LEN = TorStreamCipher.KEY_LEN;
  final static int TAP_ONIONSKIN_LEN = PKCS1_OAEP_PADDING_OVERHEAD + CIPHER_KEY_LEN + DH_BYTES;
  final static int TAP_ONIONSKIN_REPLY_LEN = DH_BYTES + TorMessageDigest.TOR_DIGEST_SIZE;
 
 
  private final CircuitImpl circuit;
  private final boolean ntorEnabled;
 
 
  CircuitExtender(CircuitImpl circuit, boolean ntorEnabled) {
    this.circuit = circuit;
    this.ntorEnabled = ntorEnabled;
  }
 
 
  CircuitNode createFastTo(Router targetRouter) {
    logger.fine("Creating 'fast' to "+ targetRouter);
    final TorCreateFastKeyAgreement kex = new TorCreateFastKeyAgreement();
    sendCreateFastCell(kex);
    return receiveAndProcessCreateFastResponse(targetRouter, kex);
  }

  private void sendCreateFastCell(TorCreateFastKeyAgreement kex) {
    final Cell cell = CellImpl.createCell(circuit.getCircuitId(), Cell.CREATE_FAST);
    cell.putByteArray(kex.createOnionSkin());
    circuit.sendCell(cell);
  }
 
  private CircuitNode receiveAndProcessCreateFastResponse(Router targetRouter, TorKeyAgreement kex) {
    final Cell cell = circuit.receiveControlCellResponse();
    if(cell == null) {
      throw new TorException("Timeout building circuit waiting for CREATE_FAST response from "+ targetRouter);
    }

    return processCreatedFastCell(targetRouter, cell, kex);
  }
 
  private CircuitNode processCreatedFastCell(Router targetRouter, Cell cell, TorKeyAgreement kex) {
    final byte[] payload = new byte[TorMessageDigest.TOR_DIGEST_SIZE * 2];
    final byte[] keyMaterial = new byte[CircuitNodeCryptoState.KEY_MATERIAL_SIZE];
    final byte[] verifyHash = new byte[TorMessageDigest.TOR_DIGEST_SIZE];
    cell.getByteArray(payload);
    if(!kex.deriveKeysFromHandshakeResponse(payload, keyMaterial, verifyHash)) {
      // XXX
      return null;
    }
    final CircuitNode node = CircuitNodeImpl.createFirstHop(targetRouter, keyMaterial, verifyHash);
    circuit.appendNode(node);
    return node;
  }
 
  CircuitNode extendTo(Router targetRouter) {
    if(circuit.getCircuitLength() == 0) {
      throw new TorException("Cannot EXTEND an empty circuit");
    }
   
    if(useNtor(targetRouter)) {
      final NTorCircuitExtender nce = new NTorCircuitExtender(this, targetRouter);
      return nce.extendTo();
    } else {
      final TapCircuitExtender tce = new TapCircuitExtender(this, targetRouter);
      return tce.extendTo();
    }
  }

  private boolean useNtor(Router targetRouter) {
    return ntorEnabled && targetRouter.getNTorOnionKey() != null;
  }
 
  private void logProtocolViolation(String sourceName, Router targetRouter) {
    final String version = (targetRouter == null) ? "(none)" : targetRouter.getVersion();
    final String targetName = (targetRouter == null) ? "(none)" : targetRouter.getNickname();
    logger.warning("Protocol error extending circuit from ("+ sourceName +") to ("+ targetName +") [version: "+ version +"]");
  }

  private String nodeToName(CircuitNode node) {
    if(node == null || node.getRouter() == null) {
      return "(null)";
    }
    final Router router = node.getRouter();
    return router.getNickname();
  }


  public void sendRelayCell(RelayCell cell) {
    circuit.sendRelayCell(cell);
  }


  public RelayCell receiveRelayResponse(int expectedCommand, Router extendTarget) {
    final RelayCell cell = circuit.receiveRelayCell();
    if(cell == null) {
      throw new TorException("Timeout building circuit");
    }
    final int command = cell.getRelayCommand();
    if(command == RelayCell.RELAY_TRUNCATED) {
      final int code = cell.getByte() & 0xFF;
      final String msg = CellImpl.errorToDescription(code);
      final String source = nodeToName(cell.getCircuitNode());
      if(code == Cell.ERROR_PROTOCOL) {
        logProtocolViolation(source, extendTarget);
      }
      throw new TorException("Error from ("+ source +") while extending to ("+ extendTarget.getNickname() + "): "+ msg);
    } else if(command != expectedCommand) {
      final String expected = RelayCellImpl.commandToDescription(expectedCommand);
      final String received = RelayCellImpl.commandToDescription(command);
      throw new TorException("Received incorrect extend response, expecting "+ expected + " but received "+ received);
    } else {
      return cell;
    }
  }


  public CircuitNode createNewNode(Router r, byte[] keyMaterial, byte[] verifyDigest) {
    final CircuitNode node = CircuitNodeImpl.createNode(r, circuit.getFinalCircuitNode(), keyMaterial, verifyDigest);
    logger.fine("Adding new circuit node for "+ r.getNickname());
    circuit.appendNode(node);
    return node;

  }

  public RelayCell createRelayCell(int command) {
    return new RelayCellImpl(circuit.getFinalCircuitNode(), circuit.getCircuitId(), 0, command, true);
  }
 
  Router getFinalRouter() {
    final CircuitNode node = circuit.getFinalCircuitNode();
    if(node != null) {
      return node.getRouter();
    } else {
      return null;
    }
  }
}
TOP

Related Classes of com.subgraph.orchid.circuits.CircuitExtender

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.