transport/ reformat

This commit is contained in:
Shikhar Bhushan
2010-03-01 23:54:40 +01:00
parent f63d09969c
commit a1ab7bdc8f
43 changed files with 264 additions and 151 deletions

View File

@@ -19,7 +19,7 @@ import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.StreamCopier; import net.schmizz.sshj.common.StreamCopier;
import net.schmizz.sshj.connection.channel.direct.Session; import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Shell; import net.schmizz.sshj.connection.channel.direct.Session.Shell;
import net.schmizz.sshj.transport.verification.ConsoleHostKeyVerifier; import net.schmizz.sshj.transport.verification.ConsoleKnownHostsVerifier;
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts; import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
import java.io.File; import java.io.File;
@@ -38,7 +38,7 @@ class RudimentaryPTY {
final SSHClient ssh = new SSHClient(); final SSHClient ssh = new SSHClient();
final File khFile = new File(OpenSSHKnownHosts.detectSSHDir(), "known_hosts"); final File khFile = new File(OpenSSHKnownHosts.detectSSHDir(), "known_hosts");
ssh.addHostKeyVerifier(new ConsoleHostKeyVerifier(khFile, System.console())); ssh.addHostKeyVerifier(new ConsoleKnownHostsVerifier(khFile, System.console()));
ssh.connect("localhost"); ssh.connect("localhost");

View File

@@ -47,7 +47,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** Decodes packets from the SSH binary protocol per the current algorithms. */ /** Decodes packets from the SSH binary protocol per the current algorithms. */
final class Decoder extends Converter { final class Decoder
extends Converter {
private static final int MAX_PACKET_LEN = 256 * 1024; private static final int MAX_PACKET_LEN = 256 * 1024;
@@ -81,7 +82,8 @@ final class Decoder extends Converter {
* *
* @return number of bytes needed before further decoding possible * @return number of bytes needed before further decoding possible
*/ */
private int decode() throws SSHException { private int decode()
throws SSHException {
int need; int need;
/* Decoding loop */ /* Decoding loop */
@@ -134,7 +136,8 @@ final class Decoder extends Converter {
return need; return need;
} }
private void checkMAC(final byte[] data) throws TransportException { private void checkMAC(final byte[] data)
throws TransportException {
mac.update(seq); // seq num mac.update(seq); // seq num
mac.update(data, 0, packetLength + 4); // packetLength+4 = entire packet w/o mac mac.update(data, 0, packetLength + 4); // packetLength+4 = entire packet w/o mac
mac.doFinal(macResult, 0); // compute mac.doFinal(macResult, 0); // compute
@@ -143,13 +146,15 @@ final class Decoder extends Converter {
throw new TransportException(DisconnectReason.MAC_ERROR, "MAC Error"); throw new TransportException(DisconnectReason.MAC_ERROR, "MAC Error");
} }
private SSHPacket decompressed() throws TransportException { private SSHPacket decompressed()
throws TransportException {
uncompressBuffer.clear(); uncompressBuffer.clear();
compression.uncompress(inputBuffer, uncompressBuffer); compression.uncompress(inputBuffer, uncompressBuffer);
return uncompressBuffer; return uncompressBuffer;
} }
private int decryptLength() throws TransportException { private int decryptLength()
throws TransportException {
cipher.update(inputBuffer.array(), 0, cipherSize); cipher.update(inputBuffer.array(), 0, cipherSize);
final int len = inputBuffer.readInt(); // Read packet length final int len = inputBuffer.readInt(); // Read packet length
@@ -178,7 +183,8 @@ final class Decoder extends Converter {
* Returns the number of bytes expected in the next call in order to decode the packet length, and if the packet * Returns the number of bytes expected in the next call in order to decode the packet length, and if the packet
* length has already been decoded; to decode the payload. This number is accurate and should be taken to heart. * length has already been decoded; to decode the payload. This number is accurate and should be taken to heart.
*/ */
int received(byte[] b, int len) throws SSHException { int received(byte[] b, int len)
throws SSHException {
inputBuffer.putRawBytes(b, 0, len); inputBuffer.putRawBytes(b, 0, len);
if (needed <= len) if (needed <= len)
needed = decode(); needed = decode();

View File

@@ -46,7 +46,8 @@ import org.slf4j.LoggerFactory;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
/** Encodes packets into the SSH binary protocol per the current algorithms. */ /** Encodes packets into the SSH binary protocol per the current algorithms. */
final class Encoder extends Converter { final class Encoder
extends Converter {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
@@ -62,7 +63,7 @@ final class Encoder extends Converter {
private SSHPacket checkHeaderSpace(SSHPacket buffer) { private SSHPacket checkHeaderSpace(SSHPacket buffer) {
if (buffer.rpos() < 5) { if (buffer.rpos() < 5) {
log.warn("Performance cost: when sending a packet, ensure that " log.warn("Performance cost: when sending a packet, ensure that "
+ "5 bytes are available in front of the buffer"); + "5 bytes are available in front of the buffer");
SSHPacket nb = new SSHPacket(buffer.available() + 5); SSHPacket nb = new SSHPacket(buffer.available() + 5);
nb.rpos(5); nb.rpos(5);
nb.wpos(5); nb.wpos(5);

View File

@@ -41,7 +41,8 @@ import net.schmizz.sshj.common.SSHPacket;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
final class Heartbeater extends Thread { final class Heartbeater
extends Thread {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());

View File

@@ -55,7 +55,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
/** Algorithm negotiation and key exchange. */ /** Algorithm negotiation and key exchange. */
final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable { final class KeyExchanger
implements SSHPacketHandler, ErrorNotifiable {
private static enum Expected { private static enum Expected {
/** we have sent or are sending KEXINIT, and expect the server's KEXINIT */ /** we have sent or are sending KEXINIT, and expect the server's KEXINIT */
@@ -91,7 +92,7 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
private NegotiatedAlgorithms negotiatedAlgs; private NegotiatedAlgorithms negotiatedAlgs;
private final Event<TransportException> kexInitSent = new Event<TransportException>("kexinit sent", private final Event<TransportException> kexInitSent = new Event<TransportException>("kexinit sent",
TransportException.chainer); TransportException.chainer);
private final Event<TransportException> done; private final Event<TransportException> done;
@@ -145,7 +146,8 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
* @throws TransportException if there is an error during key exchange * @throws TransportException if there is an error during key exchange
* @see {@link Transport#setTimeout} for setting timeout for kex * @see {@link Transport#setTimeout} for setting timeout for kex
*/ */
void startKex(boolean waitForDone) throws TransportException { void startKex(boolean waitForDone)
throws TransportException {
if (!kexOngoing.getAndSet(true)) { if (!kexOngoing.getAndSet(true)) {
done.clear(); done.clear();
sendKexInit(); sendKexInit();
@@ -154,17 +156,20 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
waitForDone(); waitForDone();
} }
void waitForDone() throws TransportException { void waitForDone()
throws TransportException {
done.await(transport.getTimeout(), TimeUnit.SECONDS); done.await(transport.getTimeout(), TimeUnit.SECONDS);
} }
private synchronized void ensureKexOngoing() throws TransportException { private synchronized void ensureKexOngoing()
throws TransportException {
if (!isKexOngoing()) if (!isKexOngoing())
throw new TransportException(DisconnectReason.PROTOCOL_ERROR, throw new TransportException(DisconnectReason.PROTOCOL_ERROR,
"Key exchange packet received when key exchange was not ongoing"); "Key exchange packet received when key exchange was not ongoing");
} }
private static void ensureReceivedMatchesExpected(Message got, Message expected) throws TransportException { private static void ensureReceivedMatchesExpected(Message got, Message expected)
throws TransportException {
if (got != expected) if (got != expected)
throw new TransportException(DisconnectReason.PROTOCOL_ERROR, "Was expecting " + expected); throw new TransportException(DisconnectReason.PROTOCOL_ERROR, "Was expecting " + expected);
} }
@@ -174,14 +179,16 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
* *
* @throws TransportException * @throws TransportException
*/ */
private void sendKexInit() throws TransportException { private void sendKexInit()
throws TransportException {
log.info("Sending SSH_MSG_KEXINIT"); log.info("Sending SSH_MSG_KEXINIT");
clientProposal = new Proposal(transport.getConfig()); clientProposal = new Proposal(transport.getConfig());
transport.write(clientProposal.getPacket()); transport.write(clientProposal.getPacket());
kexInitSent.set(); kexInitSent.set();
} }
private void sendNewKeys() throws TransportException { private void sendNewKeys()
throws TransportException {
log.info("Sending SSH_MSG_NEWKEYS"); log.info("Sending SSH_MSG_NEWKEYS");
transport.write(new SSHPacket(Message.NEWKEYS)); transport.write(new SSHPacket(Message.NEWKEYS));
} }
@@ -193,7 +200,8 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
* *
* @throws TransportException * @throws TransportException
*/ */
private synchronized void verifyHost(PublicKey key) throws TransportException { private synchronized void verifyHost(PublicKey key)
throws TransportException {
for (HostKeyVerifier hkv : hostVerifiers) { for (HostKeyVerifier hkv : hostVerifiers) {
log.debug("Trying to verify host key with {}", hkv); log.debug("Trying to verify host key with {}", hkv);
if (hkv.verify(transport.getRemoteHost(), transport.getRemotePort(), key)) if (hkv.verify(transport.getRemoteHost(), transport.getRemotePort(), key))
@@ -201,8 +209,10 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
} }
throw new TransportException(DisconnectReason.HOST_KEY_NOT_VERIFIABLE, "Could not verify `" throw new TransportException(DisconnectReason.HOST_KEY_NOT_VERIFIABLE, "Could not verify `"
+ KeyType.fromKey(key) + "` host key with fingerprint `" + SecurityUtils.getFingerprint(key) + KeyType
+ "` for `" + transport.getRemoteHost() + "` on port " + transport.getRemotePort()); .fromKey(key) + "` host key with fingerprint `" + SecurityUtils.getFingerprint(key)
+ "` for `" + transport
.getRemoteHost() + "` on port " + transport.getRemotePort());
} }
private void setKexDone() { private void setKexDone() {
@@ -211,7 +221,8 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
done.set(); done.set();
} }
private void gotKexInit(SSHPacket buf) throws TransportException { private void gotKexInit(SSHPacket buf)
throws TransportException {
Proposal serverProposal = new Proposal(buf); Proposal serverProposal = new Proposal(buf);
negotiatedAlgs = clientProposal.negotiate(serverProposal); negotiatedAlgs = clientProposal.negotiate(serverProposal);
log.debug("Negotiated algorithms: {}", negotiatedAlgs); log.debug("Negotiated algorithms: {}", negotiatedAlgs);
@@ -255,9 +266,9 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
// session id is 'H' from the first key exchange and does not change thereafter // session id is 'H' from the first key exchange and does not change thereafter
sessionID = Arrays.copyOf(kex.getH(), kex.getH().length); sessionID = Arrays.copyOf(kex.getH(), kex.getH().length);
final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer() // final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer()
.putMPInt(kex.getK()) // .putMPInt(kex.getK())
.putRawBytes(kex.getH()) // .putRawBytes(kex.getH())
.putByte((byte) 0) // <placeholder> .putByte((byte) 0) // <placeholder>
.putRawBytes(sessionID); .putRawBytes(sessionID);
final int pos = hashInput.available() - sessionID.length - 1; // Position of <placeholder> final int pos = hashInput.available() - sessionID.length - 1; // Position of <placeholder>
@@ -286,36 +297,37 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
hash.update(hashInput.array(), 0, hashInput.available()); hash.update(hashInput.array(), 0, hashInput.available());
final byte[] integrityKey_S2C = hash.digest(); final byte[] integrityKey_S2C = hash.digest();
final Cipher cipher_C2S = Factory.Named.Util.create(transport.getConfig().getCipherFactories(), negotiatedAlgs final Cipher cipher_C2S = Factory.Named.Util.create(transport.getConfig().getCipherFactories(),
.getClient2ServerCipherAlgorithm()); negotiatedAlgs.getClient2ServerCipherAlgorithm());
cipher_C2S.init(Cipher.Mode.Encrypt, // cipher_C2S.init(Cipher.Mode.Encrypt,
resizedKey(encryptionKey_C2S, cipher_C2S.getBlockSize(), hash, kex.getK(), kex.getH()), // resizedKey(encryptionKey_C2S, cipher_C2S.getBlockSize(), hash, kex.getK(), kex.getH()),
initialIV_C2S); initialIV_C2S);
final Cipher cipher_S2C = Factory.Named.Util.create(transport.getConfig().getCipherFactories(), // final Cipher cipher_S2C = Factory.Named.Util.create(transport.getConfig().getCipherFactories(),
negotiatedAlgs.getServer2ClientCipherAlgorithm()); negotiatedAlgs.getServer2ClientCipherAlgorithm());
cipher_S2C.init(Cipher.Mode.Decrypt, // cipher_S2C.init(Cipher.Mode.Decrypt,
resizedKey(encryptionKey_S2C, cipher_S2C.getBlockSize(), hash, kex.getK(), kex.getH()), // resizedKey(encryptionKey_S2C, cipher_S2C.getBlockSize(), hash, kex.getK(), kex.getH()),
initialIV_S2C); initialIV_S2C);
final MAC mac_C2S = Factory.Named.Util.create(transport.getConfig().getMACFactories(), negotiatedAlgs final MAC mac_C2S = Factory.Named.Util.create(transport.getConfig().getMACFactories(), negotiatedAlgs
.getClient2ServerMACAlgorithm()); .getClient2ServerMACAlgorithm());
mac_C2S.init(integrityKey_C2S); mac_C2S.init(integrityKey_C2S);
final MAC mac_S2C = Factory.Named.Util.create(transport.getConfig().getMACFactories(), // final MAC mac_S2C = Factory.Named.Util.create(transport.getConfig().getMACFactories(),
negotiatedAlgs.getServer2ClientMACAlgorithm()); negotiatedAlgs.getServer2ClientMACAlgorithm());
mac_S2C.init(integrityKey_S2C); mac_S2C.init(integrityKey_S2C);
final Compression compression_S2C = Factory.Named.Util.create(transport.getConfig().getCompressionFactories(), final Compression compression_S2C = Factory.Named.Util.create(transport.getConfig().getCompressionFactories(),
negotiatedAlgs.getServer2ClientCompressionAlgorithm()); negotiatedAlgs.getServer2ClientCompressionAlgorithm());
final Compression compression_C2S = Factory.Named.Util.create(transport.getConfig().getCompressionFactories(), final Compression compression_C2S = Factory.Named.Util.create(transport.getConfig().getCompressionFactories(),
negotiatedAlgs.getClient2ServerCompressionAlgorithm()); negotiatedAlgs.getClient2ServerCompressionAlgorithm());
transport.getEncoder().setAlgorithms(cipher_C2S, mac_C2S, compression_C2S); transport.getEncoder().setAlgorithms(cipher_C2S, mac_C2S, compression_C2S);
transport.getDecoder().setAlgorithms(cipher_S2C, mac_S2C, compression_S2C); transport.getDecoder().setAlgorithms(cipher_S2C, mac_S2C, compression_S2C);
} }
public void handle(Message msg, SSHPacket buf) throws TransportException { public void handle(Message msg, SSHPacket buf)
throws TransportException {
switch (expected) { switch (expected) {
case KEXINIT: case KEXINIT:

View File

@@ -137,7 +137,8 @@ class Proposal {
} }
public NegotiatedAlgorithms negotiate(Proposal other) throws TransportException { public NegotiatedAlgorithms negotiate(Proposal other)
throws TransportException {
return new NegotiatedAlgorithms( return new NegotiatedAlgorithms(
firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()), // firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()), //
firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()), // firstMatch(this.getSignatureAlgorithms(), other.getSignatureAlgorithms()), //
@@ -150,7 +151,8 @@ class Proposal {
); );
} }
private static String firstMatch(List<String> a, List<String> b) throws TransportException { private static String firstMatch(List<String> a, List<String> b)
throws TransportException {
for (String aa : a) for (String aa : a)
for (String bb : b) for (String bb : b)
if (aa.equals(bb)) if (aa.equals(bb))

View File

@@ -41,7 +41,8 @@ import org.slf4j.LoggerFactory;
import java.io.InputStream; import java.io.InputStream;
final class Reader extends Thread { final class Reader
extends Thread {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());

View File

@@ -47,7 +47,8 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
/** Transport layer of the SSH protocol. */ /** Transport layer of the SSH protocol. */
public interface Transport extends SSHPacketHandler { public interface Transport
extends SSHPacketHandler {
/** /**
* Sets the {@code socket} to be used by this transport; and identification information is exchanged. A {@link * Sets the {@code socket} to be used by this transport; and identification information is exchanged. A {@link
@@ -55,11 +56,13 @@ public interface Transport extends SSHPacketHandler {
* *
* @throws TransportException if there is an error during exchange of identification information * @throws TransportException if there is an error during exchange of identification information
*/ */
void init(String host, int port, InputStream in, OutputStream out) throws TransportException; void init(String host, int port, InputStream in, OutputStream out)
throws TransportException;
void addHostKeyVerifier(HostKeyVerifier hkv); void addHostKeyVerifier(HostKeyVerifier hkv);
void doKex() throws TransportException; void doKex()
throws TransportException;
/** @return the version string used by this client to identify itself to an SSH server, e.g. "SSHJ_3_0" */ /** @return the version string used by this client to identify itself to an SSH server, e.g. "SSHJ_3_0" */
String getClientVersion(); String getClientVersion();
@@ -110,7 +113,8 @@ public interface Transport extends SSHPacketHandler {
* *
* @throws IOException if the request failed for any reason * @throws IOException if the request failed for any reason
*/ */
void reqService(Service service) throws TransportException; void reqService(Service service)
throws TransportException;
/** /**
* Sets the currently active {@link net.schmizz.sshj.Service}. Handling of non-transport-layer packets is {@link * Sets the currently active {@link net.schmizz.sshj.Service}. Handling of non-transport-layer packets is {@link
@@ -139,7 +143,8 @@ public interface Transport extends SSHPacketHandler {
* *
* @throws TransportException if an error occured sending the packet * @throws TransportException if an error occured sending the packet
*/ */
long sendUnimplemented() throws TransportException; long sendUnimplemented()
throws TransportException;
/** /**
* Returns whether this transport is active. * Returns whether this transport is active.
@@ -154,7 +159,8 @@ public interface Transport extends SSHPacketHandler {
* *
* @throws TransportException * @throws TransportException
*/ */
void join() throws TransportException; void join()
throws TransportException;
/** Send a disconnection packet with reason as {@link DisconnectReason#BY_APPLICATION}, and closes this transport. */ /** Send a disconnection packet with reason as {@link DisconnectReason#BY_APPLICATION}, and closes this transport. */
void disconnect(); void disconnect();
@@ -186,5 +192,6 @@ public interface Transport extends SSHPacketHandler {
* *
* @throws TransportException if an error occurred sending the packet * @throws TransportException if an error occurred sending the packet
*/ */
long write(SSHPacket payload) throws TransportException; long write(SSHPacket payload)
throws TransportException;
} }

View File

@@ -40,7 +40,8 @@ import net.schmizz.sshj.common.DisconnectReason;
import net.schmizz.sshj.common.SSHException; import net.schmizz.sshj.common.SSHException;
/** Transport-layer exception */ /** Transport-layer exception */
public class TransportException extends SSHException { public class TransportException
extends SSHException {
/** @see {@link net.schmizz.concurrent.ExceptionChainer} */ /** @see {@link net.schmizz.concurrent.ExceptionChainer} */
public static final ExceptionChainer<TransportException> chainer = new ExceptionChainer<TransportException>() { public static final ExceptionChainer<TransportException> chainer = new ExceptionChainer<TransportException>() {

View File

@@ -57,9 +57,11 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/** A thread-safe {@link Transport} implementation. */ /** A thread-safe {@link Transport} implementation. */
public final class TransportImpl implements Transport { public final class TransportImpl
implements Transport {
private static final class NullService extends AbstractService { private static final class NullService
extends AbstractService {
NullService(Transport trans) { NullService(Transport trans) {
super("null-service", trans); super("null-service", trans);
} }
@@ -96,10 +98,10 @@ public final class TransportImpl implements Transport {
private final Decoder decoder; private final Decoder decoder;
private final Event<TransportException> serviceAccept = new Event<TransportException>("service accept", private final Event<TransportException> serviceAccept = new Event<TransportException>("service accept",
TransportException.chainer); TransportException.chainer);
private final Event<TransportException> close = new Event<TransportException>("transport close", private final Event<TransportException> close = new Event<TransportException>("transport close",
TransportException.chainer); TransportException.chainer);
/** Client version identification string */ /** Client version identification string */
private final String clientID; private final String clientID;
@@ -131,7 +133,8 @@ public final class TransportImpl implements Transport {
clientID = "SSH-2.0-" + config.getVersion(); clientID = "SSH-2.0-" + config.getVersion();
} }
public void init(String remoteHost, int remotePort, InputStream in, OutputStream out) throws TransportException { public void init(String remoteHost, int remotePort, InputStream in, OutputStream out)
throws TransportException {
connInfo = new ConnInfo(remoteHost, remotePort, in, out); connInfo = new ConnInfo(remoteHost, remotePort, in, out);
try { try {
@@ -169,7 +172,8 @@ public final class TransportImpl implements Transport {
* *
* @throws IOException * @throws IOException
*/ */
private String readIdentification(Buffer.PlainBuffer buffer) throws IOException { private String readIdentification(Buffer.PlainBuffer buffer)
throws IOException {
String ident; String ident;
byte[] data = new byte[256]; byte[] data = new byte[256];
@@ -205,7 +209,7 @@ public final class TransportImpl implements Transport {
if (!ident.startsWith("SSH-2.0-") && !ident.startsWith("SSH-1.99-")) if (!ident.startsWith("SSH-2.0-") && !ident.startsWith("SSH-1.99-"))
throw new TransportException(DisconnectReason.PROTOCOL_VERSION_NOT_SUPPORTED, throw new TransportException(DisconnectReason.PROTOCOL_VERSION_NOT_SUPPORTED,
"Server does not support SSHv2, identified as: " + ident); "Server does not support SSHv2, identified as: " + ident);
return ident; return ident;
} }
@@ -214,7 +218,8 @@ public final class TransportImpl implements Transport {
kexer.addHostKeyVerifier(hkv); kexer.addHostKeyVerifier(hkv);
} }
public void doKex() throws TransportException { public void doKex()
throws TransportException {
kexer.startKex(true); kexer.startKex(true);
} }
@@ -274,7 +279,8 @@ public final class TransportImpl implements Transport {
this.service = service; this.service = service;
} }
public void reqService(Service service) throws TransportException { public void reqService(Service service)
throws TransportException {
serviceAccept.lock(); serviceAccept.lock();
try { try {
serviceAccept.clear(); serviceAccept.clear();
@@ -293,7 +299,8 @@ public final class TransportImpl implements Transport {
* *
* @throws TransportException if there is an error while sending the request * @throws TransportException if there is an error while sending the request
*/ */
private void sendServiceRequest(String serviceName) throws TransportException { private void sendServiceRequest(String serviceName)
throws TransportException {
log.debug("Sending SSH_MSG_SERVICE_REQUEST for {}", serviceName); log.debug("Sending SSH_MSG_SERVICE_REQUEST for {}", serviceName);
write(new SSHPacket(Message.SERVICE_REQUEST).putString(serviceName)); write(new SSHPacket(Message.SERVICE_REQUEST).putString(serviceName));
} }
@@ -308,13 +315,15 @@ public final class TransportImpl implements Transport {
return authed; return authed;
} }
public long sendUnimplemented() throws TransportException { public long sendUnimplemented()
throws TransportException {
final long seq = decoder.getSequenceNumber(); final long seq = decoder.getSequenceNumber();
log.info("Sending SSH_MSG_UNIMPLEMENTED for packet #{}", seq); log.info("Sending SSH_MSG_UNIMPLEMENTED for packet #{}", seq);
return write(new SSHPacket(Message.UNIMPLEMENTED).putInt(seq)); return write(new SSHPacket(Message.UNIMPLEMENTED).putInt(seq));
} }
public void join() throws TransportException { public void join()
throws TransportException {
close.await(); close.await();
} }
@@ -348,7 +357,8 @@ public final class TransportImpl implements Transport {
} }
} }
public long write(SSHPacket payload) throws TransportException { public long write(SSHPacket payload)
throws TransportException {
writeLock.lock(); writeLock.lock();
try { try {
@@ -406,7 +416,8 @@ public final class TransportImpl implements Transport {
* *
* @throws SSHException if an error occurs during handling (unrecoverable) * @throws SSHException if an error occurs during handling (unrecoverable)
*/ */
public void handle(Message msg, SSHPacket buf) throws SSHException { public void handle(Message msg, SSHPacket buf)
throws SSHException {
this.msg = msg; this.msg = msg;
log.trace("Received packet {}", msg); log.trace("Received packet {}", msg);
@@ -450,19 +461,21 @@ public final class TransportImpl implements Transport {
log.info("Received SSH_MSG_DEBUG (display={}) '{}'", display, message); log.info("Received SSH_MSG_DEBUG (display={}) '{}'", display, message);
} }
private void gotDisconnect(SSHPacket buf) throws TransportException { private void gotDisconnect(SSHPacket buf)
throws TransportException {
DisconnectReason code = DisconnectReason.fromInt(buf.readInt()); DisconnectReason code = DisconnectReason.fromInt(buf.readInt());
String message = buf.readString(); String message = buf.readString();
log.info("Received SSH_MSG_DISCONNECT (reason={}, msg={})", code, message); log.info("Received SSH_MSG_DISCONNECT (reason={}, msg={})", code, message);
throw new TransportException(code, "Disconnected; server said: " + message); throw new TransportException(code, "Disconnected; server said: " + message);
} }
private void gotServiceAccept() throws TransportException { private void gotServiceAccept()
throws TransportException {
serviceAccept.lock(); serviceAccept.lock();
try { try {
if (!serviceAccept.hasWaiters()) if (!serviceAccept.hasWaiters())
throw new TransportException(DisconnectReason.PROTOCOL_ERROR, throw new TransportException(DisconnectReason.PROTOCOL_ERROR,
"Got a service accept notification when none was awaited"); "Got a service accept notification when none was awaited");
serviceAccept.set(); serviceAccept.set();
} finally { } finally {
serviceAccept.unlock(); serviceAccept.unlock();
@@ -476,7 +489,8 @@ public final class TransportImpl implements Transport {
* *
* @throws TransportException * @throws TransportException
*/ */
private void gotUnimplemented(SSHPacket buf) throws SSHException { private void gotUnimplemented(SSHPacket buf)
throws SSHException {
long seqNum = buf.readLong(); long seqNum = buf.readLong();
log.info("Received SSH_MSG_UNIMPLEMENTED #{}", seqNum); log.info("Received SSH_MSG_UNIMPLEMENTED #{}", seqNum);
if (kexer.isKexOngoing()) if (kexer.isKexOngoing())

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** AES128CBC cipher */ /** AES128CBC cipher */
public class AES128CBC extends BaseCipher { public class AES128CBC
extends BaseCipher {
/** Named factory for AES128CBC Cipher */ /** Named factory for AES128CBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new AES128CBC(); return new AES128CBC();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code aes128-ctr} cipher */ /** {@code aes128-ctr} cipher */
public class AES128CTR extends BaseCipher { public class AES128CTR
extends BaseCipher {
/** Named factory for AES128CBC Cipher */ /** Named factory for AES128CBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new AES128CTR(); return new AES128CTR();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code aes192-cbc} cipher */ /** {@code aes192-cbc} cipher */
public class AES192CBC extends BaseCipher { public class AES192CBC
extends BaseCipher {
/** Named factory for AES192CBC Cipher */ /** Named factory for AES192CBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new AES192CBC(); return new AES192CBC();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code aes192-ctr} cipher */ /** {@code aes192-ctr} cipher */
public class AES192CTR extends BaseCipher { public class AES192CTR
extends BaseCipher {
/** Named factory for AES192CTR Cipher */ /** Named factory for AES192CTR Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new AES192CTR(); return new AES192CTR();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code aes256-ctr} cipher */ /** {@code aes256-ctr} cipher */
public class AES256CBC extends BaseCipher { public class AES256CBC
extends BaseCipher {
/** Named factory for AES256CBC Cipher */ /** Named factory for AES256CBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new AES256CBC(); return new AES256CBC();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code aes256-ctr} cipher */ /** {@code aes256-ctr} cipher */
public class AES256CTR extends BaseCipher { public class AES256CTR
extends BaseCipher {
/** Named factory for AES256CBC Cipher */ /** Named factory for AES256CBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new AES256CTR(); return new AES256CTR();
} }

View File

@@ -44,7 +44,8 @@ import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
/** Base class for all Cipher implementations delegating to the JCE provider. */ /** Base class for all Cipher implementations delegating to the JCE provider. */
public class BaseCipher implements Cipher { public class BaseCipher
implements Cipher {
private static byte[] resize(byte[] data, int size) { private static byte[] resize(byte[] data, int size) {
if (data.length > size) { if (data.length > size) {
@@ -83,7 +84,7 @@ public class BaseCipher implements Cipher {
try { try {
cipher = SecurityUtils.getCipher(transformation); cipher = SecurityUtils.getCipher(transformation);
cipher.init((mode == Mode.Encrypt ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE), cipher.init((mode == Mode.Encrypt ? javax.crypto.Cipher.ENCRYPT_MODE : javax.crypto.Cipher.DECRYPT_MODE),
new SecretKeySpec(key, algorithm), new IvParameterSpec(iv)); new SecretKeySpec(key, algorithm), new IvParameterSpec(iv));
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
cipher = null; cipher = null;
throw new SSHRuntimeException(e); throw new SSHRuntimeException(e);

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code blowfish-ctr} cipher */ /** {@code blowfish-ctr} cipher */
public class BlowfishCBC extends BaseCipher { public class BlowfishCBC
extends BaseCipher {
/** Named factory for BlowfishCBC Cipher */ /** Named factory for BlowfishCBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new BlowfishCBC(); return new BlowfishCBC();
} }

View File

@@ -39,7 +39,8 @@ package net.schmizz.sshj.transport.cipher;
public interface Cipher { public interface Cipher {
enum Mode { enum Mode {
Encrypt, Decrypt Encrypt,
Decrypt
} }
/** /**

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** Represents a no-op cipher. */ /** Represents a no-op cipher. */
public class NoneCipher implements Cipher { public class NoneCipher
implements Cipher {
/** Named factory for the no-op Cipher */ /** Named factory for the no-op Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new NoneCipher(); return new NoneCipher();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.cipher; package net.schmizz.sshj.transport.cipher;
/** {@code 3des-cbc} cipher */ /** {@code 3des-cbc} cipher */
public class TripleDESCBC extends BaseCipher { public class TripleDESCBC
extends BaseCipher {
/** Named factory for TripleDESCBC Cipher */ /** Named factory for TripleDESCBC Cipher */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Cipher> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Cipher> {
public Cipher create() { public Cipher create() {
return new TripleDESCBC(); return new TripleDESCBC();
} }

View File

@@ -43,7 +43,8 @@ public interface Compression {
/** Enum identifying if this object will be used to compress or uncompress data. */ /** Enum identifying if this object will be used to compress or uncompress data. */
enum Type { enum Type {
Inflater, Deflater Inflater,
Deflater
} }
/** /**
@@ -77,6 +78,7 @@ public interface Compression {
* @param from the buffer containing the data to uncompress * @param from the buffer containing the data to uncompress
* @param to the buffer receiving the uncompressed data * @param to the buffer receiving the uncompressed data
*/ */
void uncompress(SSHPacket from, SSHPacket to) throws TransportException; void uncompress(SSHPacket from, SSHPacket to)
throws TransportException;
} }

View File

@@ -40,10 +40,12 @@ package net.schmizz.sshj.transport.compression;
* *
* @see Compression#isDelayed() * @see Compression#isDelayed()
*/ */
public class DelayedZlibCompression extends ZlibCompression { public class DelayedZlibCompression
extends ZlibCompression {
/** Named factory for the ZLib Delayed Compression. */ /** Named factory for the ZLib Delayed Compression. */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Compression> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Compression> {
public Compression create() { public Compression create() {
return new DelayedZlibCompression(); return new DelayedZlibCompression();
} }

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.compression; package net.schmizz.sshj.transport.compression;
/** No-op <code>Compression</code>. */ /** No-op <code>Compression</code>. */
public abstract class NoneCompression implements Compression { public abstract class NoneCompression
implements Compression {
/** Named factory for the no-op <code>Compression</code> */ /** Named factory for the no-op <code>Compression</code> */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Compression> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Compression> {
public Compression create() { public Compression create() {
return null; return null;
} }

View File

@@ -43,10 +43,12 @@ import net.schmizz.sshj.common.SSHRuntimeException;
import net.schmizz.sshj.transport.TransportException; import net.schmizz.sshj.transport.TransportException;
/** ZLib based Compression. */ /** ZLib based Compression. */
public class ZlibCompression implements Compression { public class ZlibCompression
implements Compression {
/** Named factory for the ZLib Compression. */ /** Named factory for the ZLib Compression. */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Compression> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Compression> {
public Compression create() { public Compression create() {
return new ZlibCompression(); return new ZlibCompression();
} }
@@ -97,7 +99,8 @@ public class ZlibCompression implements Compression {
return false; return false;
} }
public void uncompress(SSHPacket from, SSHPacket to) throws TransportException { public void uncompress(SSHPacket from, SSHPacket to)
throws TransportException {
stream.next_in = from.array(); stream.next_in = from.array();
stream.next_in_index = from.rpos(); stream.next_in_index = from.rpos();
stream.avail_in = from.available(); stream.avail_in = from.available();
@@ -115,7 +118,7 @@ public class ZlibCompression implements Compression {
return; // wtf.. but this works *head spins* return; // wtf.. but this works *head spins*
default: default:
throw new TransportException(DisconnectReason.COMPRESSION_ERROR, "uncompress: inflate returned " throw new TransportException(DisconnectReason.COMPRESSION_ERROR, "uncompress: inflate returned "
+ status); + status);
} }
} }
} }

View File

@@ -42,7 +42,8 @@ import java.security.GeneralSecurityException;
import java.security.MessageDigest; import java.security.MessageDigest;
/** Base class for Digest algorithms based on the JCE provider. */ /** Base class for Digest algorithms based on the JCE provider. */
public class BaseDigest implements Digest { public class BaseDigest
implements Digest {
private final String algorithm; private final String algorithm;
private final int bsize; private final int bsize;

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.digest; package net.schmizz.sshj.transport.digest;
/** MD5 Digest. */ /** MD5 Digest. */
public class MD5 extends BaseDigest { public class MD5
extends BaseDigest {
/** Named factory for MD5 digest */ /** Named factory for MD5 digest */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Digest> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Digest> {
public Digest create() { public Digest create() {
return new MD5(); return new MD5();

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.digest; package net.schmizz.sshj.transport.digest;
/** SHA1 Digest. */ /** SHA1 Digest. */
public class SHA1 extends BaseDigest { public class SHA1
extends BaseDigest {
/** Named factory for SHA1 digest */ /** Named factory for SHA1 digest */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Digest> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Digest> {
public Digest create() { public Digest create() {
return new SHA1(); return new SHA1();

View File

@@ -56,7 +56,8 @@ import java.security.PublicKey;
* Base class for DHG key exchange algorithms. Implementations will only have to configure the required data on the * Base class for DHG key exchange algorithms. Implementations will only have to configure the required data on the
* {@link DH} class in the * {@link DH} class in the
*/ */
public abstract class AbstractDHG implements KeyExchange { public abstract class AbstractDHG
implements KeyExchange {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
@@ -92,7 +93,8 @@ public abstract class AbstractDHG implements KeyExchange {
return ByteArrayUtils.copyOf(K); return ByteArrayUtils.copyOf(K);
} }
public void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws TransportException { public void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C)
throws TransportException {
this.trans = trans; this.trans = trans;
this.V_S = ByteArrayUtils.copyOf(V_S); this.V_S = ByteArrayUtils.copyOf(V_S);
this.V_C = ByteArrayUtils.copyOf(V_C); this.V_C = ByteArrayUtils.copyOf(V_C);
@@ -106,7 +108,8 @@ public abstract class AbstractDHG implements KeyExchange {
trans.write(new SSHPacket(Message.KEXDH_INIT).putMPInt(e)); trans.write(new SSHPacket(Message.KEXDH_INIT).putMPInt(e));
} }
public boolean next(Message msg, SSHPacket packet) throws TransportException { public boolean next(Message msg, SSHPacket packet)
throws TransportException {
if (msg != Message.KEXDH_31) if (msg != Message.KEXDH_31)
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "Unxpected packet: " + msg); throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "Unxpected packet: " + msg);
@@ -131,7 +134,8 @@ public abstract class AbstractDHG implements KeyExchange {
sha.update(buf.array(), 0, buf.available()); sha.update(buf.array(), 0, buf.available());
H = sha.digest(); H = sha.digest();
Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(), KeyType.fromKey(hostKey).toString()); Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(),
KeyType.fromKey(hostKey).toString());
signature.init(hostKey, null); signature.init(hostKey, null);
signature.update(H, 0, H.length); signature.update(H, 0, H.length);
if (!signature.verify(sig)) if (!signature.verify(sig))

View File

@@ -40,10 +40,12 @@ package net.schmizz.sshj.transport.kex;
* *
* @see <a href="http://www.ietf.org/rfc/rfc4253.txt">RFC 4253</a> * @see <a href="http://www.ietf.org/rfc/rfc4253.txt">RFC 4253</a>
*/ */
public class DHG1 extends AbstractDHG { public class DHG1
extends AbstractDHG {
/** Named factory for DHG1 key exchange */ /** Named factory for DHG1 key exchange */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<KeyExchange> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<KeyExchange> {
public KeyExchange create() { public KeyExchange create() {
return new DHG1(); return new DHG1();

View File

@@ -41,10 +41,12 @@ package net.schmizz.sshj.transport.kex;
* DHG14 does not work with the default JCE implementation provided by Sun because it does not support 2048 bits * DHG14 does not work with the default JCE implementation provided by Sun because it does not support 2048 bits
* encryption. It requires BouncyCastle to be used. * encryption. It requires BouncyCastle to be used.
*/ */
public class DHG14 extends AbstractDHG { public class DHG14
extends AbstractDHG {
/** Named factory for DHG14 key exchange */ /** Named factory for DHG14 key exchange */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<KeyExchange> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<KeyExchange> {
public KeyExchange create() { public KeyExchange create() {
return new DHG14(); return new DHG14();

View File

@@ -73,7 +73,8 @@ public interface KeyExchange {
* @param I_S the server key init packet * @param I_S the server key init packet
* @param I_C the client key init packet * @param I_C the client key init packet
*/ */
void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) throws TransportException; void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C)
throws TransportException;
/** /**
* Process the next packet * Process the next packet
@@ -82,6 +83,7 @@ public interface KeyExchange {
* *
* @return a boolean indicating if the processing is complete or if more packets are to be received * @return a boolean indicating if the processing is complete or if more packets are to be received
*/ */
boolean next(Message msg, SSHPacket buffer) throws TransportException; boolean next(Message msg, SSHPacket buffer)
throws TransportException;
} }

View File

@@ -43,7 +43,8 @@ import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
/** Base class for <code>MAC</code> implementations based on the JCE provider. */ /** Base class for <code>MAC</code> implementations based on the JCE provider. */
public class BaseMAC implements MAC { public class BaseMAC
implements MAC {
private final String algorithm; private final String algorithm;
private final int defbsize; private final int defbsize;

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.mac; package net.schmizz.sshj.transport.mac;
/** HMAC-MD5 <code>MAC</code>. */ /** HMAC-MD5 <code>MAC</code>. */
public class HMACMD5 extends BaseMAC { public class HMACMD5
extends BaseMAC {
/** Named factory for the HMACMD5 <code>MAC</code> */ /** Named factory for the HMACMD5 <code>MAC</code> */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<MAC> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
public MAC create() { public MAC create() {
return new HMACMD5(); return new HMACMD5();

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.mac; package net.schmizz.sshj.transport.mac;
/** HMAC-MD5-96 <code>MAC</code> */ /** HMAC-MD5-96 <code>MAC</code> */
public class HMACMD596 extends BaseMAC { public class HMACMD596
extends BaseMAC {
/** Named factory for the HMAC-MD5-96 <code>MAC</code> */ /** Named factory for the HMAC-MD5-96 <code>MAC</code> */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<MAC> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
public MAC create() { public MAC create() {
return new HMACMD596(); return new HMACMD596();

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.mac; package net.schmizz.sshj.transport.mac;
/** HMAC-SHA1 <code>MAC</code> */ /** HMAC-SHA1 <code>MAC</code> */
public class HMACSHA1 extends BaseMAC { public class HMACSHA1
extends BaseMAC {
/** Named factory for the HMAC-SHA1 <code>MAC</code> */ /** Named factory for the HMAC-SHA1 <code>MAC</code> */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<MAC> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
public MAC create() { public MAC create() {
return new HMACSHA1(); return new HMACSHA1();

View File

@@ -36,10 +36,12 @@
package net.schmizz.sshj.transport.mac; package net.schmizz.sshj.transport.mac;
/** HMAC-SHA1-96 <code>MAC</code> */ /** HMAC-SHA1-96 <code>MAC</code> */
public class HMACSHA196 extends BaseMAC { public class HMACSHA196
extends BaseMAC {
/** Named factory for the HMAC-SHA1-96 <code>MAC</code> */ /** Named factory for the HMAC-SHA1-96 <code>MAC</code> */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<MAC> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<MAC> {
public MAC create() { public MAC create() {
return new HMACSHA196(); return new HMACSHA196();

View File

@@ -44,10 +44,12 @@ import java.security.SecureRandom;
* BouncyCastle <code>Random</code>. This pseudo random number generator uses the a very fast PRNG from BouncyCastle. * BouncyCastle <code>Random</code>. This pseudo random number generator uses the a very fast PRNG from BouncyCastle.
* The JRE random will be used when creating a new generator to add some random data to the seed. * The JRE random will be used when creating a new generator to add some random data to the seed.
*/ */
public class BouncyCastleRandom implements Random { public class BouncyCastleRandom
implements Random {
/** Named factory for the BouncyCastle <code>Random</code> */ /** Named factory for the BouncyCastle <code>Random</code> */
public static class Factory implements net.schmizz.sshj.common.Factory<Random> { public static class Factory
implements net.schmizz.sshj.common.Factory<Random> {
public Random create() { public Random create() {
return new BouncyCastleRandom(); return new BouncyCastleRandom();

View File

@@ -38,10 +38,12 @@ package net.schmizz.sshj.transport.random;
import java.security.SecureRandom; import java.security.SecureRandom;
/** A {@link Random} implementation using the built-in {@link SecureRandom} PRNG. */ /** A {@link Random} implementation using the built-in {@link SecureRandom} PRNG. */
public class JCERandom implements Random { public class JCERandom
implements Random {
/** Named factory for the JCE {@link Random} */ /** Named factory for the JCE {@link Random} */
public static class Factory implements net.schmizz.sshj.common.Factory.Named<Random> { public static class Factory
implements net.schmizz.sshj.common.Factory.Named<Random> {
public Random create() { public Random create() {
return new JCERandom(); return new JCERandom();

View File

@@ -38,7 +38,8 @@ package net.schmizz.sshj.transport.random;
import net.schmizz.sshj.common.Factory; import net.schmizz.sshj.common.Factory;
/** A random factory wrapper that uses a single random instance. The underlying random instance has to be thread safe. */ /** A random factory wrapper that uses a single random instance. The underlying random instance has to be thread safe. */
public class SingletonRandomFactory implements Random, Factory<Random> { public class SingletonRandomFactory
implements Random, Factory<Random> {
private final Random random; private final Random random;
public SingletonRandomFactory(Factory<Random> factory) { public SingletonRandomFactory(Factory<Random> factory) {

View File

@@ -23,14 +23,16 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.security.PublicKey; import java.security.PublicKey;
public class ConsoleHostKeyVerifier extends OpenSSHKnownHosts { public class ConsoleKnownHostsVerifier
extends OpenSSHKnownHosts {
private static final String YES = "yes"; private static final String YES = "yes";
private static final String NO = "no"; private static final String NO = "no";
private final Console console; private final Console console;
public ConsoleHostKeyVerifier(File khFile, Console console) throws IOException { public ConsoleKnownHostsVerifier(File khFile, Console console)
throws IOException {
super(khFile); super(khFile);
this.console = console; this.console = console;
} }
@@ -38,7 +40,7 @@ public class ConsoleHostKeyVerifier extends OpenSSHKnownHosts {
@Override @Override
protected boolean hostKeyUnverifiableAction(String hostname, PublicKey key) { protected boolean hostKeyUnverifiableAction(String hostname, PublicKey key) {
console.printf("The authenticity of host '%s' can't be established.\n" + console.printf("The authenticity of host '%s' can't be established.\n" +
"%s key fingerprint is %s.\n", hostname, KeyType.fromKey(key), SecurityUtils.getFingerprint(key)); "%s key fingerprint is %s.\n", hostname, KeyType.fromKey(key), SecurityUtils.getFingerprint(key));
String response = console.readLine("Are you sure you want to continue connecting (yes/no)? "); String response = console.readLine("Are you sure you want to continue connecting (yes/no)? ");
while (!(response.equalsIgnoreCase(YES) || response.equalsIgnoreCase(NO))) { while (!(response.equalsIgnoreCase(YES) || response.equalsIgnoreCase(NO))) {
response = console.readLine("Please explicitly enter yes/no: "); response = console.readLine("Please explicitly enter yes/no: ");
@@ -56,21 +58,22 @@ public class ConsoleHostKeyVerifier extends OpenSSHKnownHosts {
} }
@Override @Override
protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key) throws IOException { protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key)
throws IOException {
final KeyType type = KeyType.fromKey(key); final KeyType type = KeyType.fromKey(key);
final String fp = SecurityUtils.getFingerprint(key); final String fp = SecurityUtils.getFingerprint(key);
final String path = khFile.getAbsolutePath(); final String path = khFile.getAbsolutePath();
console.printf( console.printf(
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" +
"@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @\n" + "@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @\n" +
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" +
"IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n" + "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n" +
"Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n" + "Someone could be eavesdropping on you right now (man-in-the-middle attack)!\n" +
"It is also possible that the host key has just been changed.\n" + "It is also possible that the host key has just been changed.\n" +
"The fingerprint for the %s key sent by the remote host is\n" + "The fingerprint for the %s key sent by the remote host is\n" +
"%s.\n" + "%s.\n" +
"Please contact your system administrator or" + "Please contact your system administrator or" +
"add correct host key in %s to get rid of this message.\n", type, fp, path); "add correct host key in %s to get rid of this message.\n", type, fp, path);
return false; return false;
} }
} }

View File

@@ -66,7 +66,8 @@ import java.util.List;
* *
* @see <a href="http://nms.lcs.mit.edu/projects/ssh/README.hashed-hosts">Hashed hostnames spec</a> * @see <a href="http://nms.lcs.mit.edu/projects/ssh/README.hashed-hosts">Hashed hostnames spec</a>
*/ */
public class OpenSSHKnownHosts implements HostKeyVerifier { public class OpenSSHKnownHosts
implements HostKeyVerifier {
private static final String LS = System.getProperty("line.separator"); private static final String LS = System.getProperty("line.separator");
@@ -95,7 +96,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
* *
* @throws SSHException if it could not be parsed for any reason * @throws SSHException if it could not be parsed for any reason
*/ */
public Entry(String line) throws SSHException { public Entry(String line)
throws SSHException {
String[] parts = line.split(" "); String[] parts = line.split(" ");
if (parts.length != 3) if (parts.length != 3)
throw new SSHException("Line parts not 3: " + line); throw new SSHException("Line parts not 3: " + line);
@@ -107,7 +109,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
} }
/** Checks whether this entry is applicable to some {@code hostname} */ /** Checks whether this entry is applicable to some {@code hostname} */
public boolean appliesTo(String hostname) throws IOException { public boolean appliesTo(String hostname)
throws IOException {
if (!hosts.isEmpty() && hosts.get(0).startsWith("|1|")) { // Hashed hostname if (!hosts.isEmpty() && hosts.get(0).startsWith("|1|")) { // Hashed hostname
final String[] splitted = hosts.get(0).split("\\|"); final String[] splitted = hosts.get(0).split("\\|");
if (splitted.length != 4) if (splitted.length != 4)
@@ -192,7 +195,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
* *
* @throws IOException if there is an error reading the file * @throws IOException if there is an error reading the file
*/ */
public OpenSSHKnownHosts(File khFile) throws IOException { public OpenSSHKnownHosts(File khFile)
throws IOException {
this.khFile = khFile; this.khFile = khFile;
if (khFile.exists()) { if (khFile.exists()) {
BufferedReader br = new BufferedReader(new FileReader(khFile)); BufferedReader br = new BufferedReader(new FileReader(khFile));
@@ -242,7 +246,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
return false; return false;
} }
protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key) throws IOException { protected boolean hostKeyChangedAction(Entry entry, String hostname, PublicKey key)
throws IOException {
log.warn("Host key for `{}` has changed!", hostname); log.warn("Host key for `{}` has changed!", hostname);
return false; return false;
} }
@@ -251,7 +256,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
return entries; return entries;
} }
public void write() throws IOException { public void write()
throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(khFile)); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(khFile));
for (Entry entry : entries) for (Entry entry : entries)
bos.write((entry.getLine() + LS).getBytes()); bos.write((entry.getLine() + LS).getBytes());

View File

@@ -17,7 +17,8 @@ package net.schmizz.sshj.transport.verification;
import java.security.PublicKey; import java.security.PublicKey;
public final class InsecureAccepter implements HostKeyVerifier { public final class PromiscuousVerifier
implements HostKeyVerifier {
public boolean verify(String hostname, int port, PublicKey key) { public boolean verify(String hostname, int port, PublicKey key) {
return true; return true;