mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 23:30:55 +03:00
transport/ reformat
This commit is contained in:
@@ -19,7 +19,7 @@ import net.schmizz.sshj.SSHClient;
|
||||
import net.schmizz.sshj.common.StreamCopier;
|
||||
import net.schmizz.sshj.connection.channel.direct.Session;
|
||||
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 java.io.File;
|
||||
@@ -38,7 +38,7 @@ class RudimentaryPTY {
|
||||
final SSHClient ssh = new SSHClient();
|
||||
|
||||
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");
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/** 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;
|
||||
|
||||
@@ -81,7 +82,8 @@ final class Decoder extends Converter {
|
||||
*
|
||||
* @return number of bytes needed before further decoding possible
|
||||
*/
|
||||
private int decode() throws SSHException {
|
||||
private int decode()
|
||||
throws SSHException {
|
||||
int need;
|
||||
|
||||
/* Decoding loop */
|
||||
@@ -134,7 +136,8 @@ final class Decoder extends Converter {
|
||||
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(data, 0, packetLength + 4); // packetLength+4 = entire packet w/o mac
|
||||
mac.doFinal(macResult, 0); // compute
|
||||
@@ -143,13 +146,15 @@ final class Decoder extends Converter {
|
||||
throw new TransportException(DisconnectReason.MAC_ERROR, "MAC Error");
|
||||
}
|
||||
|
||||
private SSHPacket decompressed() throws TransportException {
|
||||
private SSHPacket decompressed()
|
||||
throws TransportException {
|
||||
uncompressBuffer.clear();
|
||||
compression.uncompress(inputBuffer, uncompressBuffer);
|
||||
return uncompressBuffer;
|
||||
}
|
||||
|
||||
private int decryptLength() throws TransportException {
|
||||
private int decryptLength()
|
||||
throws TransportException {
|
||||
cipher.update(inputBuffer.array(), 0, cipherSize);
|
||||
|
||||
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
|
||||
* 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);
|
||||
if (needed <= len)
|
||||
needed = decode();
|
||||
|
||||
@@ -46,7 +46,8 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/** 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());
|
||||
|
||||
@@ -62,7 +63,7 @@ final class Encoder extends Converter {
|
||||
private SSHPacket checkHeaderSpace(SSHPacket buffer) {
|
||||
if (buffer.rpos() < 5) {
|
||||
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);
|
||||
nb.rpos(5);
|
||||
nb.wpos(5);
|
||||
|
||||
@@ -41,7 +41,8 @@ import net.schmizz.sshj.common.SSHPacket;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
final class Heartbeater extends Thread {
|
||||
final class Heartbeater
|
||||
extends Thread {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/** Algorithm negotiation and key exchange. */
|
||||
final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
|
||||
final class KeyExchanger
|
||||
implements SSHPacketHandler, ErrorNotifiable {
|
||||
|
||||
private static enum Expected {
|
||||
/** 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 final Event<TransportException> kexInitSent = new Event<TransportException>("kexinit sent",
|
||||
TransportException.chainer);
|
||||
TransportException.chainer);
|
||||
|
||||
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
|
||||
* @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)) {
|
||||
done.clear();
|
||||
sendKexInit();
|
||||
@@ -154,17 +156,20 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
|
||||
waitForDone();
|
||||
}
|
||||
|
||||
void waitForDone() throws TransportException {
|
||||
void waitForDone()
|
||||
throws TransportException {
|
||||
done.await(transport.getTimeout(), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private synchronized void ensureKexOngoing() throws TransportException {
|
||||
private synchronized void ensureKexOngoing()
|
||||
throws TransportException {
|
||||
if (!isKexOngoing())
|
||||
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)
|
||||
throw new TransportException(DisconnectReason.PROTOCOL_ERROR, "Was expecting " + expected);
|
||||
}
|
||||
@@ -174,14 +179,16 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
|
||||
*
|
||||
* @throws TransportException
|
||||
*/
|
||||
private void sendKexInit() throws TransportException {
|
||||
private void sendKexInit()
|
||||
throws TransportException {
|
||||
log.info("Sending SSH_MSG_KEXINIT");
|
||||
clientProposal = new Proposal(transport.getConfig());
|
||||
transport.write(clientProposal.getPacket());
|
||||
kexInitSent.set();
|
||||
}
|
||||
|
||||
private void sendNewKeys() throws TransportException {
|
||||
private void sendNewKeys()
|
||||
throws TransportException {
|
||||
log.info("Sending SSH_MSG_NEWKEYS");
|
||||
transport.write(new SSHPacket(Message.NEWKEYS));
|
||||
}
|
||||
@@ -193,7 +200,8 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
|
||||
*
|
||||
* @throws TransportException
|
||||
*/
|
||||
private synchronized void verifyHost(PublicKey key) throws TransportException {
|
||||
private synchronized void verifyHost(PublicKey key)
|
||||
throws TransportException {
|
||||
for (HostKeyVerifier hkv : hostVerifiers) {
|
||||
log.debug("Trying to verify host key with {}", hkv);
|
||||
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 `"
|
||||
+ KeyType.fromKey(key) + "` host key with fingerprint `" + SecurityUtils.getFingerprint(key)
|
||||
+ "` for `" + transport.getRemoteHost() + "` on port " + transport.getRemotePort());
|
||||
+ KeyType
|
||||
.fromKey(key) + "` host key with fingerprint `" + SecurityUtils.getFingerprint(key)
|
||||
+ "` for `" + transport
|
||||
.getRemoteHost() + "` on port " + transport.getRemotePort());
|
||||
}
|
||||
|
||||
private void setKexDone() {
|
||||
@@ -211,7 +221,8 @@ final class KeyExchanger implements SSHPacketHandler, ErrorNotifiable {
|
||||
done.set();
|
||||
}
|
||||
|
||||
private void gotKexInit(SSHPacket buf) throws TransportException {
|
||||
private void gotKexInit(SSHPacket buf)
|
||||
throws TransportException {
|
||||
Proposal serverProposal = new Proposal(buf);
|
||||
negotiatedAlgs = clientProposal.negotiate(serverProposal);
|
||||
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
|
||||
sessionID = Arrays.copyOf(kex.getH(), kex.getH().length);
|
||||
|
||||
final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer() //
|
||||
.putMPInt(kex.getK()) //
|
||||
.putRawBytes(kex.getH()) //
|
||||
final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer()
|
||||
.putMPInt(kex.getK())
|
||||
.putRawBytes(kex.getH())
|
||||
.putByte((byte) 0) // <placeholder>
|
||||
.putRawBytes(sessionID);
|
||||
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());
|
||||
final byte[] integrityKey_S2C = hash.digest();
|
||||
|
||||
final Cipher cipher_C2S = Factory.Named.Util.create(transport.getConfig().getCipherFactories(), negotiatedAlgs
|
||||
.getClient2ServerCipherAlgorithm());
|
||||
cipher_C2S.init(Cipher.Mode.Encrypt, //
|
||||
resizedKey(encryptionKey_C2S, cipher_C2S.getBlockSize(), hash, kex.getK(), kex.getH()), //
|
||||
initialIV_C2S);
|
||||
final Cipher cipher_C2S = Factory.Named.Util.create(transport.getConfig().getCipherFactories(),
|
||||
negotiatedAlgs.getClient2ServerCipherAlgorithm());
|
||||
cipher_C2S.init(Cipher.Mode.Encrypt,
|
||||
resizedKey(encryptionKey_C2S, cipher_C2S.getBlockSize(), hash, kex.getK(), kex.getH()),
|
||||
initialIV_C2S);
|
||||
|
||||
final Cipher cipher_S2C = Factory.Named.Util.create(transport.getConfig().getCipherFactories(), //
|
||||
negotiatedAlgs.getServer2ClientCipherAlgorithm());
|
||||
cipher_S2C.init(Cipher.Mode.Decrypt, //
|
||||
resizedKey(encryptionKey_S2C, cipher_S2C.getBlockSize(), hash, kex.getK(), kex.getH()), //
|
||||
initialIV_S2C);
|
||||
final Cipher cipher_S2C = Factory.Named.Util.create(transport.getConfig().getCipherFactories(),
|
||||
negotiatedAlgs.getServer2ClientCipherAlgorithm());
|
||||
cipher_S2C.init(Cipher.Mode.Decrypt,
|
||||
resizedKey(encryptionKey_S2C, cipher_S2C.getBlockSize(), hash, kex.getK(), kex.getH()),
|
||||
initialIV_S2C);
|
||||
|
||||
final MAC mac_C2S = Factory.Named.Util.create(transport.getConfig().getMACFactories(), negotiatedAlgs
|
||||
.getClient2ServerMACAlgorithm());
|
||||
mac_C2S.init(integrityKey_C2S);
|
||||
|
||||
final MAC mac_S2C = Factory.Named.Util.create(transport.getConfig().getMACFactories(), //
|
||||
negotiatedAlgs.getServer2ClientMACAlgorithm());
|
||||
final MAC mac_S2C = Factory.Named.Util.create(transport.getConfig().getMACFactories(),
|
||||
negotiatedAlgs.getServer2ClientMACAlgorithm());
|
||||
mac_S2C.init(integrityKey_S2C);
|
||||
|
||||
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(),
|
||||
negotiatedAlgs.getClient2ServerCompressionAlgorithm());
|
||||
negotiatedAlgs.getClient2ServerCompressionAlgorithm());
|
||||
|
||||
transport.getEncoder().setAlgorithms(cipher_C2S, mac_C2S, compression_C2S);
|
||||
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) {
|
||||
|
||||
case KEXINIT:
|
||||
|
||||
@@ -137,7 +137,8 @@ class Proposal {
|
||||
|
||||
}
|
||||
|
||||
public NegotiatedAlgorithms negotiate(Proposal other) throws TransportException {
|
||||
public NegotiatedAlgorithms negotiate(Proposal other)
|
||||
throws TransportException {
|
||||
return new NegotiatedAlgorithms(
|
||||
firstMatch(this.getKeyExchangeAlgorithms(), other.getKeyExchangeAlgorithms()), //
|
||||
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 bb : b)
|
||||
if (aa.equals(bb))
|
||||
|
||||
@@ -41,7 +41,8 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
final class Reader extends Thread {
|
||||
final class Reader
|
||||
extends Thread {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/** 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
|
||||
@@ -55,11 +56,13 @@ public interface Transport extends SSHPacketHandler {
|
||||
*
|
||||
* @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 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" */
|
||||
String getClientVersion();
|
||||
@@ -110,7 +113,8 @@ public interface Transport extends SSHPacketHandler {
|
||||
*
|
||||
* @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
|
||||
@@ -139,7 +143,8 @@ public interface Transport extends SSHPacketHandler {
|
||||
*
|
||||
* @throws TransportException if an error occured sending the packet
|
||||
*/
|
||||
long sendUnimplemented() throws TransportException;
|
||||
long sendUnimplemented()
|
||||
throws TransportException;
|
||||
|
||||
/**
|
||||
* Returns whether this transport is active.
|
||||
@@ -154,7 +159,8 @@ public interface Transport extends SSHPacketHandler {
|
||||
*
|
||||
* @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. */
|
||||
void disconnect();
|
||||
@@ -186,5 +192,6 @@ public interface Transport extends SSHPacketHandler {
|
||||
*
|
||||
* @throws TransportException if an error occurred sending the packet
|
||||
*/
|
||||
long write(SSHPacket payload) throws TransportException;
|
||||
long write(SSHPacket payload)
|
||||
throws TransportException;
|
||||
}
|
||||
@@ -40,7 +40,8 @@ import net.schmizz.sshj.common.DisconnectReason;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
|
||||
/** Transport-layer exception */
|
||||
public class TransportException extends SSHException {
|
||||
public class TransportException
|
||||
extends SSHException {
|
||||
|
||||
/** @see {@link net.schmizz.concurrent.ExceptionChainer} */
|
||||
public static final ExceptionChainer<TransportException> chainer = new ExceptionChainer<TransportException>() {
|
||||
|
||||
@@ -57,9 +57,11 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/** 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) {
|
||||
super("null-service", trans);
|
||||
}
|
||||
@@ -96,10 +98,10 @@ public final class TransportImpl implements Transport {
|
||||
private final Decoder decoder;
|
||||
|
||||
private final Event<TransportException> serviceAccept = new Event<TransportException>("service accept",
|
||||
TransportException.chainer);
|
||||
TransportException.chainer);
|
||||
|
||||
private final Event<TransportException> close = new Event<TransportException>("transport close",
|
||||
TransportException.chainer);
|
||||
TransportException.chainer);
|
||||
|
||||
/** Client version identification string */
|
||||
private final String clientID;
|
||||
@@ -131,7 +133,8 @@ public final class TransportImpl implements Transport {
|
||||
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);
|
||||
|
||||
try {
|
||||
@@ -169,7 +172,8 @@ public final class TransportImpl implements Transport {
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private String readIdentification(Buffer.PlainBuffer buffer) throws IOException {
|
||||
private String readIdentification(Buffer.PlainBuffer buffer)
|
||||
throws IOException {
|
||||
String ident;
|
||||
|
||||
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-"))
|
||||
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;
|
||||
}
|
||||
@@ -214,7 +218,8 @@ public final class TransportImpl implements Transport {
|
||||
kexer.addHostKeyVerifier(hkv);
|
||||
}
|
||||
|
||||
public void doKex() throws TransportException {
|
||||
public void doKex()
|
||||
throws TransportException {
|
||||
kexer.startKex(true);
|
||||
}
|
||||
|
||||
@@ -274,7 +279,8 @@ public final class TransportImpl implements Transport {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public void reqService(Service service) throws TransportException {
|
||||
public void reqService(Service service)
|
||||
throws TransportException {
|
||||
serviceAccept.lock();
|
||||
try {
|
||||
serviceAccept.clear();
|
||||
@@ -293,7 +299,8 @@ public final class TransportImpl implements Transport {
|
||||
*
|
||||
* @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);
|
||||
write(new SSHPacket(Message.SERVICE_REQUEST).putString(serviceName));
|
||||
}
|
||||
@@ -308,13 +315,15 @@ public final class TransportImpl implements Transport {
|
||||
return authed;
|
||||
}
|
||||
|
||||
public long sendUnimplemented() throws TransportException {
|
||||
public long sendUnimplemented()
|
||||
throws TransportException {
|
||||
final long seq = decoder.getSequenceNumber();
|
||||
log.info("Sending SSH_MSG_UNIMPLEMENTED for packet #{}", seq);
|
||||
return write(new SSHPacket(Message.UNIMPLEMENTED).putInt(seq));
|
||||
}
|
||||
|
||||
public void join() throws TransportException {
|
||||
public void join()
|
||||
throws TransportException {
|
||||
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();
|
||||
try {
|
||||
|
||||
@@ -406,7 +416,8 @@ public final class TransportImpl implements Transport {
|
||||
*
|
||||
* @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;
|
||||
|
||||
log.trace("Received packet {}", msg);
|
||||
@@ -450,19 +461,21 @@ public final class TransportImpl implements Transport {
|
||||
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());
|
||||
String message = buf.readString();
|
||||
log.info("Received SSH_MSG_DISCONNECT (reason={}, msg={})", code, message);
|
||||
throw new TransportException(code, "Disconnected; server said: " + message);
|
||||
}
|
||||
|
||||
private void gotServiceAccept() throws TransportException {
|
||||
private void gotServiceAccept()
|
||||
throws TransportException {
|
||||
serviceAccept.lock();
|
||||
try {
|
||||
if (!serviceAccept.hasWaiters())
|
||||
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();
|
||||
} finally {
|
||||
serviceAccept.unlock();
|
||||
@@ -476,7 +489,8 @@ public final class TransportImpl implements Transport {
|
||||
*
|
||||
* @throws TransportException
|
||||
*/
|
||||
private void gotUnimplemented(SSHPacket buf) throws SSHException {
|
||||
private void gotUnimplemented(SSHPacket buf)
|
||||
throws SSHException {
|
||||
long seqNum = buf.readLong();
|
||||
log.info("Received SSH_MSG_UNIMPLEMENTED #{}", seqNum);
|
||||
if (kexer.isKexOngoing())
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** AES128CBC cipher */
|
||||
public class AES128CBC extends BaseCipher {
|
||||
public class AES128CBC
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new AES128CBC();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code aes128-ctr} cipher */
|
||||
public class AES128CTR extends BaseCipher {
|
||||
public class AES128CTR
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new AES128CTR();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code aes192-cbc} cipher */
|
||||
public class AES192CBC extends BaseCipher {
|
||||
public class AES192CBC
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new AES192CBC();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code aes192-ctr} cipher */
|
||||
public class AES192CTR extends BaseCipher {
|
||||
public class AES192CTR
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new AES192CTR();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code aes256-ctr} cipher */
|
||||
public class AES256CBC extends BaseCipher {
|
||||
public class AES256CBC
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new AES256CBC();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code aes256-ctr} cipher */
|
||||
public class AES256CTR extends BaseCipher {
|
||||
public class AES256CTR
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new AES256CTR();
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/** 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) {
|
||||
if (data.length > size) {
|
||||
@@ -83,7 +84,7 @@ public class BaseCipher implements Cipher {
|
||||
try {
|
||||
cipher = SecurityUtils.getCipher(transformation);
|
||||
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) {
|
||||
cipher = null;
|
||||
throw new SSHRuntimeException(e);
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code blowfish-ctr} cipher */
|
||||
public class BlowfishCBC extends BaseCipher {
|
||||
public class BlowfishCBC
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new BlowfishCBC();
|
||||
}
|
||||
|
||||
@@ -39,7 +39,8 @@ package net.schmizz.sshj.transport.cipher;
|
||||
public interface Cipher {
|
||||
|
||||
enum Mode {
|
||||
Encrypt, Decrypt
|
||||
Encrypt,
|
||||
Decrypt
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** Represents a no-op cipher. */
|
||||
public class NoneCipher implements Cipher {
|
||||
public class NoneCipher
|
||||
implements 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() {
|
||||
return new NoneCipher();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.cipher;
|
||||
|
||||
/** {@code 3des-cbc} cipher */
|
||||
public class TripleDESCBC extends BaseCipher {
|
||||
public class TripleDESCBC
|
||||
extends BaseCipher {
|
||||
|
||||
/** 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() {
|
||||
return new TripleDESCBC();
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ public interface Compression {
|
||||
|
||||
/** Enum identifying if this object will be used to compress or uncompress data. */
|
||||
enum Type {
|
||||
Inflater, Deflater
|
||||
Inflater,
|
||||
Deflater
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +78,7 @@ public interface Compression {
|
||||
* @param from the buffer containing the data to uncompress
|
||||
* @param to the buffer receiving the uncompressed data
|
||||
*/
|
||||
void uncompress(SSHPacket from, SSHPacket to) throws TransportException;
|
||||
void uncompress(SSHPacket from, SSHPacket to)
|
||||
throws TransportException;
|
||||
|
||||
}
|
||||
|
||||
@@ -40,10 +40,12 @@ package net.schmizz.sshj.transport.compression;
|
||||
*
|
||||
* @see Compression#isDelayed()
|
||||
*/
|
||||
public class DelayedZlibCompression extends ZlibCompression {
|
||||
public class DelayedZlibCompression
|
||||
extends ZlibCompression {
|
||||
|
||||
/** 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() {
|
||||
return new DelayedZlibCompression();
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.compression;
|
||||
|
||||
/** 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> */
|
||||
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() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -43,10 +43,12 @@ import net.schmizz.sshj.common.SSHRuntimeException;
|
||||
import net.schmizz.sshj.transport.TransportException;
|
||||
|
||||
/** ZLib based Compression. */
|
||||
public class ZlibCompression implements Compression {
|
||||
public class ZlibCompression
|
||||
implements 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() {
|
||||
return new ZlibCompression();
|
||||
}
|
||||
@@ -97,7 +99,8 @@ public class ZlibCompression implements Compression {
|
||||
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_index = from.rpos();
|
||||
stream.avail_in = from.available();
|
||||
@@ -115,7 +118,7 @@ public class ZlibCompression implements Compression {
|
||||
return; // wtf.. but this works *head spins*
|
||||
default:
|
||||
throw new TransportException(DisconnectReason.COMPRESSION_ERROR, "uncompress: inflate returned "
|
||||
+ status);
|
||||
+ status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/** 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 int bsize;
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.digest;
|
||||
|
||||
/** MD5 Digest. */
|
||||
public class MD5 extends BaseDigest {
|
||||
public class MD5
|
||||
extends BaseDigest {
|
||||
|
||||
/** 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() {
|
||||
return new MD5();
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.digest;
|
||||
|
||||
/** SHA1 Digest. */
|
||||
public class SHA1 extends BaseDigest {
|
||||
public class SHA1
|
||||
extends BaseDigest {
|
||||
|
||||
/** 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() {
|
||||
return new SHA1();
|
||||
|
||||
@@ -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
|
||||
* {@link DH} class in the
|
||||
*/
|
||||
public abstract class AbstractDHG implements KeyExchange {
|
||||
public abstract class AbstractDHG
|
||||
implements KeyExchange {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@@ -92,7 +93,8 @@ public abstract class AbstractDHG implements KeyExchange {
|
||||
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.V_S = ByteArrayUtils.copyOf(V_S);
|
||||
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));
|
||||
}
|
||||
|
||||
public boolean next(Message msg, SSHPacket packet) throws TransportException {
|
||||
public boolean next(Message msg, SSHPacket packet)
|
||||
throws TransportException {
|
||||
if (msg != Message.KEXDH_31)
|
||||
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());
|
||||
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.update(H, 0, H.length);
|
||||
if (!signature.verify(sig))
|
||||
|
||||
@@ -40,10 +40,12 @@ package net.schmizz.sshj.transport.kex;
|
||||
*
|
||||
* @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 */
|
||||
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() {
|
||||
return new DHG1();
|
||||
|
||||
@@ -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
|
||||
* encryption. It requires BouncyCastle to be used.
|
||||
*/
|
||||
public class DHG14 extends AbstractDHG {
|
||||
public class DHG14
|
||||
extends AbstractDHG {
|
||||
|
||||
/** 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() {
|
||||
return new DHG14();
|
||||
|
||||
@@ -73,7 +73,8 @@ public interface KeyExchange {
|
||||
* @param I_S the server 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
|
||||
@@ -82,6 +83,7 @@ public interface KeyExchange {
|
||||
*
|
||||
* @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;
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/** 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 int defbsize;
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.mac;
|
||||
|
||||
/** HMAC-MD5 <code>MAC</code>. */
|
||||
public class HMACMD5 extends BaseMAC {
|
||||
public class HMACMD5
|
||||
extends BaseMAC {
|
||||
|
||||
/** 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() {
|
||||
return new HMACMD5();
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.mac;
|
||||
|
||||
/** 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> */
|
||||
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() {
|
||||
return new HMACMD596();
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.mac;
|
||||
|
||||
/** HMAC-SHA1 <code>MAC</code> */
|
||||
public class HMACSHA1 extends BaseMAC {
|
||||
public class HMACSHA1
|
||||
extends BaseMAC {
|
||||
|
||||
/** 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() {
|
||||
return new HMACSHA1();
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
package net.schmizz.sshj.transport.mac;
|
||||
|
||||
/** 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> */
|
||||
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() {
|
||||
return new HMACSHA196();
|
||||
|
||||
@@ -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.
|
||||
* 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> */
|
||||
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() {
|
||||
return new BouncyCastleRandom();
|
||||
|
||||
@@ -38,10 +38,12 @@ package net.schmizz.sshj.transport.random;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/** 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} */
|
||||
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() {
|
||||
return new JCERandom();
|
||||
|
||||
@@ -38,7 +38,8 @@ package net.schmizz.sshj.transport.random;
|
||||
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. */
|
||||
public class SingletonRandomFactory implements Random, Factory<Random> {
|
||||
public class SingletonRandomFactory
|
||||
implements Random, Factory<Random> {
|
||||
private final Random random;
|
||||
|
||||
public SingletonRandomFactory(Factory<Random> factory) {
|
||||
|
||||
@@ -23,14 +23,16 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
|
||||
public class ConsoleHostKeyVerifier extends OpenSSHKnownHosts {
|
||||
public class ConsoleKnownHostsVerifier
|
||||
extends OpenSSHKnownHosts {
|
||||
|
||||
private static final String YES = "yes";
|
||||
private static final String NO = "no";
|
||||
|
||||
private final Console console;
|
||||
|
||||
public ConsoleHostKeyVerifier(File khFile, Console console) throws IOException {
|
||||
public ConsoleKnownHostsVerifier(File khFile, Console console)
|
||||
throws IOException {
|
||||
super(khFile);
|
||||
this.console = console;
|
||||
}
|
||||
@@ -38,7 +40,7 @@ public class ConsoleHostKeyVerifier extends OpenSSHKnownHosts {
|
||||
@Override
|
||||
protected boolean hostKeyUnverifiableAction(String hostname, PublicKey key) {
|
||||
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)? ");
|
||||
while (!(response.equalsIgnoreCase(YES) || response.equalsIgnoreCase(NO))) {
|
||||
response = console.readLine("Please explicitly enter yes/no: ");
|
||||
@@ -56,21 +58,22 @@ public class ConsoleHostKeyVerifier extends OpenSSHKnownHosts {
|
||||
}
|
||||
|
||||
@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 String fp = SecurityUtils.getFingerprint(key);
|
||||
final String path = khFile.getAbsolutePath();
|
||||
console.printf(
|
||||
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n" +
|
||||
"@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @\n" +
|
||||
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\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" +
|
||||
"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" +
|
||||
"%s.\n" +
|
||||
"Please contact your system administrator or" +
|
||||
"add correct host key in %s to get rid of this message.\n", type, fp, path);
|
||||
"@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @\n" +
|
||||
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\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" +
|
||||
"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" +
|
||||
"%s.\n" +
|
||||
"Please contact your system administrator or" +
|
||||
"add correct host key in %s to get rid of this message.\n", type, fp, path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
*/
|
||||
public class OpenSSHKnownHosts implements HostKeyVerifier {
|
||||
public class OpenSSHKnownHosts
|
||||
implements HostKeyVerifier {
|
||||
|
||||
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
|
||||
*/
|
||||
public Entry(String line) throws SSHException {
|
||||
public Entry(String line)
|
||||
throws SSHException {
|
||||
String[] parts = line.split(" ");
|
||||
if (parts.length != 3)
|
||||
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} */
|
||||
public boolean appliesTo(String hostname) throws IOException {
|
||||
public boolean appliesTo(String hostname)
|
||||
throws IOException {
|
||||
if (!hosts.isEmpty() && hosts.get(0).startsWith("|1|")) { // Hashed hostname
|
||||
final String[] splitted = hosts.get(0).split("\\|");
|
||||
if (splitted.length != 4)
|
||||
@@ -192,7 +195,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
|
||||
*
|
||||
* @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;
|
||||
if (khFile.exists()) {
|
||||
BufferedReader br = new BufferedReader(new FileReader(khFile));
|
||||
@@ -242,7 +246,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
@@ -251,7 +256,8 @@ public class OpenSSHKnownHosts implements HostKeyVerifier {
|
||||
return entries;
|
||||
}
|
||||
|
||||
public void write() throws IOException {
|
||||
public void write()
|
||||
throws IOException {
|
||||
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(khFile));
|
||||
for (Entry entry : entries)
|
||||
bos.write((entry.getLine() + LS).getBytes());
|
||||
|
||||
@@ -17,7 +17,8 @@ package net.schmizz.sshj.transport.verification;
|
||||
|
||||
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) {
|
||||
return true;
|
||||
Reference in New Issue
Block a user