package com.subgraph.orchid.circuits; import java.util.logging.Logger; import com.subgraph.orchid.CircuitNode; import com.subgraph.orchid.RelayCell; import com.subgraph.orchid.Router; import com.subgraph.orchid.crypto.TorMessageDigest; import com.subgraph.orchid.crypto.TorTapKeyAgreement; public class TapCircuitExtender { private final static Logger logger = Logger.getLogger(TapCircuitExtender.class.getName()); private final CircuitExtender extender; private final TorTapKeyAgreement kex; private final Router router; public TapCircuitExtender(CircuitExtender extender, Router router) { this.extender = extender; this.router = router; this.kex = new TorTapKeyAgreement(router.getOnionKey()); } public CircuitNode extendTo() { logger.fine("Extending to "+ router.getNickname() + " with TAP"); final RelayCell cell = createRelayExtendCell(); extender.sendRelayCell(cell); final RelayCell response = extender.receiveRelayResponse(RelayCell.RELAY_EXTENDED, router); if(response == null) { return null; } return processExtendResponse(response); } private CircuitNode processExtendResponse(RelayCell response) { final byte[] handshakeResponse = new byte[TorTapKeyAgreement.DH_LEN + TorMessageDigest.TOR_DIGEST_SIZE]; response.getByteArray(handshakeResponse); final byte[] keyMaterial = new byte[CircuitNodeCryptoState.KEY_MATERIAL_SIZE]; final byte[] verifyDigest = new byte[TorMessageDigest.TOR_DIGEST_SIZE]; if(!kex.deriveKeysFromHandshakeResponse(handshakeResponse, keyMaterial, verifyDigest)) { return null; } return extender.createNewNode(router, keyMaterial, verifyDigest); } private RelayCell createRelayExtendCell() { final RelayCell cell = extender.createRelayCell(RelayCell.RELAY_EXTEND); cell.putByteArray(router.getAddress().getAddressDataBytes()); cell.putShort(router.getOnionPort()); cell.putByteArray(kex.createOnionSkin()); cell.putByteArray(router.getIdentityHash().getRawBytes()); return cell; } }