mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
(reformat)
This commit is contained in:
@@ -15,7 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.transport.verification;
|
package net.schmizz.sshj.transport.verification;
|
||||||
|
|
||||||
import net.schmizz.sshj.common.*;
|
import net.schmizz.sshj.common.Base64;
|
||||||
|
import net.schmizz.sshj.common.Buffer;
|
||||||
|
import net.schmizz.sshj.common.IOUtils;
|
||||||
|
import net.schmizz.sshj.common.KeyType;
|
||||||
|
import net.schmizz.sshj.common.SSHException;
|
||||||
|
import net.schmizz.sshj.common.SecurityUtils;
|
||||||
import net.schmizz.sshj.transport.mac.HMACSHA1;
|
import net.schmizz.sshj.transport.mac.HMACSHA1;
|
||||||
import net.schmizz.sshj.transport.mac.MAC;
|
import net.schmizz.sshj.transport.mac.MAC;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -41,348 +46,361 @@ 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
|
public class OpenSSHKnownHosts
|
||||||
implements HostKeyVerifier {
|
implements HostKeyVerifier {
|
||||||
|
|
||||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
protected final File khFile;
|
protected final File khFile;
|
||||||
protected final List<HostEntry> entries = new ArrayList<HostEntry>();
|
protected final List<HostEntry> entries = new ArrayList<HostEntry>();
|
||||||
|
|
||||||
public OpenSSHKnownHosts(File khFile) throws IOException {
|
public OpenSSHKnownHosts(File khFile)
|
||||||
this.khFile = khFile;
|
throws IOException {
|
||||||
if (khFile.exists()) {
|
this.khFile = khFile;
|
||||||
final BufferedReader br = new BufferedReader(new FileReader(khFile));
|
if (khFile.exists()) {
|
||||||
try {
|
final BufferedReader br = new BufferedReader(new FileReader(khFile));
|
||||||
// Read in the file, storing each line as an entry
|
try {
|
||||||
String line;
|
// Read in the file, storing each line as an entry
|
||||||
while ((line = br.readLine()) != null)
|
String line;
|
||||||
try {
|
while ((line = br.readLine()) != null)
|
||||||
HostEntry entry = EntryFactory.parseEntry(line);
|
try {
|
||||||
if (entry != null) {
|
HostEntry entry = EntryFactory.parseEntry(line);
|
||||||
entries.add(entry);
|
if (entry != null) {
|
||||||
}
|
entries.add(entry);
|
||||||
} catch (SSHException ignore) {
|
}
|
||||||
log.debug("Bad line ({}): {} ", ignore.toString(), line);
|
} catch (SSHException ignore) {
|
||||||
}
|
log.debug("Bad line ({}): {} ", ignore.toString(), line);
|
||||||
} finally {
|
}
|
||||||
IOUtils.closeQuietly(br);
|
} finally {
|
||||||
}
|
IOUtils.closeQuietly(br);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
return khFile;
|
return khFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean verify(final String hostname, final int port, final PublicKey key) {
|
public boolean verify(final String hostname, final int port, final PublicKey key) {
|
||||||
final KeyType type = KeyType.fromKey(key);
|
final KeyType type = KeyType.fromKey(key);
|
||||||
if (type == KeyType.UNKNOWN)
|
if (type == KeyType.UNKNOWN)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
final String adjustedHostname = (port != 22) ? "[" + hostname + "]:" + port : hostname;
|
final String adjustedHostname = (port != 22) ? "[" + hostname + "]:" + port : hostname;
|
||||||
|
|
||||||
for (HostEntry e : entries)
|
for (HostEntry e : entries)
|
||||||
try {
|
try {
|
||||||
if (e.appliesTo(type, adjustedHostname))
|
if (e.appliesTo(type, adjustedHostname))
|
||||||
return e.verify(key) || hostKeyChangedAction(e, adjustedHostname, key);
|
return e.verify(key) || hostKeyChangedAction(e, adjustedHostname, key);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
log.error("Error with {}: {}", e, ioe);
|
log.error("Error with {}: {}", e, ioe);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return hostKeyUnverifiableAction(adjustedHostname, key);
|
return hostKeyUnverifiableAction(adjustedHostname, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hostKeyUnverifiableAction(String hostname, PublicKey key) {
|
protected boolean hostKeyUnverifiableAction(String hostname, PublicKey key) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean hostKeyChangedAction(HostEntry entry, String hostname, PublicKey key) {
|
protected boolean hostKeyChangedAction(HostEntry entry, String hostname, PublicKey key) {
|
||||||
log.warn("Host key for `{}` has changed!", hostname);
|
log.warn("Host key for `{}` has changed!", hostname);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<HostEntry> entries() {
|
public List<HostEntry> entries() {
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String LS = System.getProperty("line.separator");
|
private static final String LS = System.getProperty("line.separator");
|
||||||
|
|
||||||
public void write()
|
public void write()
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(khFile));
|
final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(khFile));
|
||||||
try {
|
try {
|
||||||
for (HostEntry entry : entries)
|
for (HostEntry entry : entries)
|
||||||
bos.write((entry.getLine() + LS).getBytes(IOUtils.UTF8));
|
bos.write((entry.getLine() + LS).getBytes(IOUtils.UTF8));
|
||||||
} finally {
|
} finally {
|
||||||
bos.close();
|
bos.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File detectSSHDir() {
|
public static File detectSSHDir() {
|
||||||
final File sshDir = new File(System.getProperty("user.home"), ".ssh");
|
final File sshDir = new File(System.getProperty("user.home"), ".ssh");
|
||||||
return sshDir.exists() ? sshDir : null;
|
return sshDir.exists() ? sshDir : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each line in these files contains the following fields: markers
|
* Each line in these files contains the following fields: markers
|
||||||
* (optional), hostnames, bits, exponent, modulus, comment. The fields are
|
* (optional), hostnames, bits, exponent, modulus, comment. The fields are
|
||||||
* separated by spaces.
|
* separated by spaces.
|
||||||
* <p/>
|
* <p/>
|
||||||
* The marker is optional, but if it is present then it must be one of
|
* The marker is optional, but if it is present then it must be one of
|
||||||
* ``@cert-authority'', to indicate that the line contains a certification
|
* ``@cert-authority'', to indicate that the line contains a certification
|
||||||
* authority (CA) key, or ``@revoked'', to indicate that the key contained
|
* authority (CA) key, or ``@revoked'', to indicate that the key contained
|
||||||
* on the line is revoked and must not ever be accepted. Only one marker
|
* on the line is revoked and must not ever be accepted. Only one marker
|
||||||
* should be used on a key line.
|
* should be used on a key line.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Hostnames is a comma-separated list of patterns (`*' and `?' act as
|
* Hostnames is a comma-separated list of patterns (`*' and `?' act as
|
||||||
* wildcards); each pattern in turn is matched against the canonical host
|
* wildcards); each pattern in turn is matched against the canonical host
|
||||||
* name (when authenticating a client) or against the user-supplied name
|
* name (when authenticating a client) or against the user-supplied name
|
||||||
* (when authenticating a server). A pattern may also be preceded by `!' to
|
* (when authenticating a server). A pattern may also be preceded by `!' to
|
||||||
* indicate negation: if the host name matches a negated pattern, it is not
|
* indicate negation: if the host name matches a negated pattern, it is not
|
||||||
* accepted (by that line) even if it matched another pattern on the line.
|
* accepted (by that line) even if it matched another pattern on the line.
|
||||||
* A hostname or address may optionally be enclosed within `[' and `]'
|
* A hostname or address may optionally be enclosed within `[' and `]'
|
||||||
* brackets then followed by `:' and a non-standard port number.
|
* brackets then followed by `:' and a non-standard port number.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Alternately, hostnames may be stored in a hashed form which hides host
|
* Alternately, hostnames may be stored in a hashed form which hides host
|
||||||
* names and addresses should the file's contents be disclosed. Hashed
|
* names and addresses should the file's contents be disclosed. Hashed
|
||||||
* hostnames start with a `|' character. Only one hashed hostname may
|
* hostnames start with a `|' character. Only one hashed hostname may
|
||||||
* appear on a single line and none of the above negation or wildcard
|
* appear on a single line and none of the above negation or wildcard
|
||||||
* operators may be applied.
|
* operators may be applied.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Bits, exponent, and modulus are taken directly from the RSA host key;
|
* Bits, exponent, and modulus are taken directly from the RSA host key;
|
||||||
* they can be obtained, for example, from /etc/ssh/ssh_host_key.pub. The
|
* they can be obtained, for example, from /etc/ssh/ssh_host_key.pub. The
|
||||||
* optional comment field continues to the end of the line, and is not used.
|
* optional comment field continues to the end of the line, and is not used.
|
||||||
* <p/>
|
* <p/>
|
||||||
* Lines starting with `#' and empty lines are ignored as comments.
|
* Lines starting with `#' and empty lines are ignored as comments.
|
||||||
*/
|
*/
|
||||||
public static class EntryFactory {
|
public static class EntryFactory {
|
||||||
|
|
||||||
public static HostEntry parseEntry(String line) throws IOException {
|
public static HostEntry parseEntry(String line)
|
||||||
if (isComment(line)) {
|
throws IOException {
|
||||||
return new CommentEntry(line);
|
if (isComment(line)) {
|
||||||
}
|
return new CommentEntry(line);
|
||||||
|
}
|
||||||
|
|
||||||
String[] split = line.split(" ");
|
String[] split = line.split(" ");
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Marker marker = getMarker(split[i]);
|
Marker marker = getMarker(split[i]);
|
||||||
if (marker != null) {
|
if (marker != null) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
String hostnames = split[i++];
|
String hostnames = split[i++];
|
||||||
String sType = split[i++];
|
String sType = split[i++];
|
||||||
KeyType type = KeyType.fromString(sType);
|
KeyType type = KeyType.fromString(sType);
|
||||||
PublicKey key;
|
PublicKey key;
|
||||||
|
|
||||||
if (isType(type)) {
|
if (isType(type)) {
|
||||||
String sKey = split[i++];
|
String sKey = split[i++];
|
||||||
key = getKey(sKey);
|
key = getKey(sKey);
|
||||||
} else if (isBits(sType)) {
|
} else if (isBits(sType)) {
|
||||||
type = KeyType.RSA;
|
type = KeyType.RSA;
|
||||||
int bits = Integer.valueOf(sType);
|
int bits = Integer.valueOf(sType);
|
||||||
BigInteger e = new BigInteger(split[i++]);
|
BigInteger e = new BigInteger(split[i++]);
|
||||||
BigInteger n = new BigInteger(split[i++]);
|
BigInteger n = new BigInteger(split[i++]);
|
||||||
try {
|
try {
|
||||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
|
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("RSA");
|
||||||
key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
|
key = keyFactory.generatePublic(new RSAPublicKeySpec(n, e));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("Error reading entry {}, could not create key", line, ex);
|
logger.error("Error reading entry {}, could not create key", line, ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error("Error reading entry {}, could not determine type", line);
|
logger.error("Error reading entry {}, could not determine type", line);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHashed(hostnames)) {
|
if (isHashed(hostnames)) {
|
||||||
return new HashedEntry(marker, hostnames, type, key);
|
return new HashedEntry(marker, hostnames, type, key);
|
||||||
} else {
|
} else {
|
||||||
return new SimpleEntry(marker, hostnames, type, key);
|
return new SimpleEntry(marker, hostnames, type, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PublicKey getKey(String sKey) throws IOException {
|
private static PublicKey getKey(String sKey)
|
||||||
return new Buffer.PlainBuffer(Base64.decode(sKey)).readPublicKey();
|
throws IOException {
|
||||||
}
|
return new Buffer.PlainBuffer(Base64.decode(sKey)).readPublicKey();
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isBits(String type) {
|
private static boolean isBits(String type) {
|
||||||
try {
|
try {
|
||||||
Integer.parseInt(type);
|
Integer.parseInt(type);
|
||||||
return true;
|
return true;
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isType(KeyType type) {
|
private static boolean isType(KeyType type) {
|
||||||
return type != KeyType.UNKNOWN;
|
return type != KeyType.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isComment(String line) {
|
private static boolean isComment(String line) {
|
||||||
return line.isEmpty() || line.startsWith("#");
|
return line.isEmpty() || line.startsWith("#");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Marker getMarker(String line) {
|
public static Marker getMarker(String line) {
|
||||||
if (line.equals("@cert-authority")) return Marker.CA_CERT;
|
if (line.equals("@cert-authority")) return Marker.CA_CERT;
|
||||||
if (line.equals("@revoked")) return Marker.REVOKED;
|
if (line.equals("@revoked")) return Marker.REVOKED;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isHashed(String line) {
|
public static boolean isHashed(String line) {
|
||||||
return line.startsWith("|1|");
|
return line.startsWith("|1|");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface HostEntry {
|
public interface HostEntry {
|
||||||
boolean appliesTo(KeyType type, String host) throws IOException;
|
boolean appliesTo(KeyType type, String host)
|
||||||
boolean verify(PublicKey key) throws IOException;
|
throws IOException;
|
||||||
String getLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CommentEntry implements HostEntry {
|
boolean verify(PublicKey key)
|
||||||
private final String comment;
|
throws IOException;
|
||||||
|
|
||||||
public CommentEntry(String comment) {
|
String getLine();
|
||||||
this.comment = comment;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static class CommentEntry implements HostEntry {
|
||||||
public boolean appliesTo(KeyType type, String host) {
|
private final String comment;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public CommentEntry(String comment) {
|
||||||
public boolean verify(PublicKey key) {
|
this.comment = comment;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLine() {
|
public boolean appliesTo(KeyType type, String host) {
|
||||||
return comment;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static abstract class AbstractEntry implements HostEntry {
|
@Override
|
||||||
|
public boolean verify(PublicKey key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected final OpenSSHKnownHosts.Marker marker;
|
@Override
|
||||||
protected final KeyType type;
|
public String getLine() {
|
||||||
protected PublicKey key;
|
return comment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AbstractEntry(Marker marker, KeyType type, PublicKey key) {
|
public static abstract class AbstractEntry implements HostEntry {
|
||||||
this.marker = marker;
|
|
||||||
this.type = type;
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
protected final OpenSSHKnownHosts.Marker marker;
|
||||||
public boolean verify(PublicKey key) throws IOException {
|
protected final KeyType type;
|
||||||
return key.equals(this.key) && marker != Marker.REVOKED;
|
protected PublicKey key;
|
||||||
}
|
|
||||||
|
|
||||||
public String getLine() {
|
public AbstractEntry(Marker marker, KeyType type, PublicKey key) {
|
||||||
final StringBuilder line = new StringBuilder();
|
this.marker = marker;
|
||||||
|
this.type = type;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
if (marker != null) line.append(marker.getMarkerString()).append(" ");
|
@Override
|
||||||
|
public boolean verify(PublicKey key)
|
||||||
|
throws IOException {
|
||||||
|
return key.equals(this.key) && marker != Marker.REVOKED;
|
||||||
|
}
|
||||||
|
|
||||||
line.append(getHostPart());
|
public String getLine() {
|
||||||
line.append(" ").append(type.toString());
|
final StringBuilder line = new StringBuilder();
|
||||||
line.append(" ").append(getKeyString());
|
|
||||||
return line.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getKeyString() {
|
if (marker != null) line.append(marker.getMarkerString()).append(" ");
|
||||||
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer().putPublicKey(key);
|
|
||||||
return Base64.encodeBytes(buf.array(), buf.rpos(), buf.available());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract String getHostPart();
|
line.append(getHostPart());
|
||||||
}
|
line.append(" ").append(type.toString());
|
||||||
|
line.append(" ").append(getKeyString());
|
||||||
|
return line.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static class SimpleEntry extends AbstractEntry {
|
private String getKeyString() {
|
||||||
private List<String> hosts;
|
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer().putPublicKey(key);
|
||||||
private String hostnames;
|
return Base64.encodeBytes(buf.array(), buf.rpos(), buf.available());
|
||||||
|
}
|
||||||
|
|
||||||
public SimpleEntry(Marker marker, String hostnames, KeyType type, PublicKey key) {
|
protected abstract String getHostPart();
|
||||||
super(marker, type, key);
|
}
|
||||||
this.hostnames = hostnames;
|
|
||||||
hosts = Arrays.asList(hostnames.split(","));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public static class SimpleEntry extends AbstractEntry {
|
||||||
protected String getHostPart() {
|
private List<String> hosts;
|
||||||
return hostnames;
|
private String hostnames;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public SimpleEntry(Marker marker, String hostnames, KeyType type, PublicKey key) {
|
||||||
public boolean appliesTo(KeyType type, String host) throws IOException {
|
super(marker, type, key);
|
||||||
return type == this.type && hostnames.contains(host);
|
this.hostnames = hostnames;
|
||||||
}
|
hosts = Arrays.asList(hostnames.split(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HashedEntry extends AbstractEntry {
|
@Override
|
||||||
private final MAC sha1 = new HMACSHA1();
|
protected String getHostPart() {
|
||||||
|
return hostnames;
|
||||||
|
}
|
||||||
|
|
||||||
private String salt;
|
@Override
|
||||||
private byte[] saltyBytes;
|
public boolean appliesTo(KeyType type, String host)
|
||||||
|
throws IOException {
|
||||||
|
return type == this.type && hostnames.contains(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final String hashedHost;
|
public static class HashedEntry extends AbstractEntry {
|
||||||
|
private final MAC sha1 = new HMACSHA1();
|
||||||
|
|
||||||
public HashedEntry(Marker marker, String hash, KeyType type, PublicKey key) throws SSHException {
|
private String salt;
|
||||||
super(marker, type, key);
|
private byte[] saltyBytes;
|
||||||
this.hashedHost = hash;
|
|
||||||
{
|
|
||||||
final String[] hostParts = hashedHost.split("\\|");
|
|
||||||
if (hostParts.length != 4)
|
|
||||||
throw new SSHException("Unrecognized format for hashed hostname");
|
|
||||||
salt = hostParts[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private final String hashedHost;
|
||||||
public boolean appliesTo(KeyType type, String host) throws IOException {
|
|
||||||
return this.type == type && hashedHost.equals(hashHost(host));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String hashHost(String host) throws IOException {
|
public HashedEntry(Marker marker, String hash, KeyType type, PublicKey key)
|
||||||
sha1.init(getSaltyBytes());
|
throws SSHException {
|
||||||
return "|1|" + salt + "|" + Base64.encodeBytes(sha1.doFinal(host.getBytes(IOUtils.UTF8)));
|
super(marker, type, key);
|
||||||
}
|
this.hashedHost = hash;
|
||||||
|
{
|
||||||
|
final String[] hostParts = hashedHost.split("\\|");
|
||||||
|
if (hostParts.length != 4)
|
||||||
|
throw new SSHException("Unrecognized format for hashed hostname");
|
||||||
|
salt = hostParts[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] getSaltyBytes() throws IOException {
|
@Override
|
||||||
if (saltyBytes == null) {
|
public boolean appliesTo(KeyType type, String host)
|
||||||
saltyBytes = Base64.decode(salt);
|
throws IOException {
|
||||||
}
|
return this.type == type && hashedHost.equals(hashHost(host));
|
||||||
return saltyBytes;
|
}
|
||||||
}
|
|
||||||
|
private String hashHost(String host)
|
||||||
|
throws IOException {
|
||||||
|
sha1.init(getSaltyBytes());
|
||||||
|
return "|1|" + salt + "|" + Base64.encodeBytes(sha1.doFinal(host.getBytes(IOUtils.UTF8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getSaltyBytes()
|
||||||
|
throws IOException {
|
||||||
|
if (saltyBytes == null) {
|
||||||
|
saltyBytes = Base64.decode(salt);
|
||||||
|
}
|
||||||
|
return saltyBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLine() {
|
public String getLine() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getHostPart() {
|
protected String getHostPart() {
|
||||||
return hashedHost;
|
return hashedHost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Marker {
|
public enum Marker {
|
||||||
CA_CERT("@cert-authority"), REVOKED("@revoked");
|
CA_CERT("@cert-authority"), REVOKED("@revoked");
|
||||||
|
|
||||||
private final String sMarker;
|
private final String sMarker;
|
||||||
|
|
||||||
Marker(String sMarker) {
|
Marker(String sMarker) {
|
||||||
this.sMarker = sMarker;
|
this.sMarker = sMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMarkerString() {
|
public String getMarkerString() {
|
||||||
return sMarker;
|
return sMarker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(OpenSSHKnownHosts.class);
|
private static final Logger logger = LoggerFactory.getLogger(OpenSSHKnownHosts.class);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user