📄 knownhosts.java
字号:
while (true)
{
int len = fr.read(buff);
if (len < 0)
break;
cw.write(buff, 0, len);
}
fr.close();
initialize(cw.toCharArray());
}
private final boolean matchKeys(Object key1, Object key2)
{
if ((key1 instanceof RSAPublicKey) && (key2 instanceof RSAPublicKey))
{
RSAPublicKey savedRSAKey = (RSAPublicKey) key1;
RSAPublicKey remoteRSAKey = (RSAPublicKey) key2;
if (savedRSAKey.getE().equals(remoteRSAKey.getE()) == false)
return false;
if (savedRSAKey.getN().equals(remoteRSAKey.getN()) == false)
return false;
return true;
}
if ((key1 instanceof DSAPublicKey) && (key2 instanceof DSAPublicKey))
{
DSAPublicKey savedDSAKey = (DSAPublicKey) key1;
DSAPublicKey remoteDSAKey = (DSAPublicKey) key2;
if (savedDSAKey.getG().equals(remoteDSAKey.getG()) == false)
return false;
if (savedDSAKey.getP().equals(remoteDSAKey.getP()) == false)
return false;
if (savedDSAKey.getQ().equals(remoteDSAKey.getQ()) == false)
return false;
if (savedDSAKey.getY().equals(remoteDSAKey.getY()) == false)
return false;
return true;
}
return false;
}
private final boolean pseudoRegex(char[] pattern, int i, char[] match, int j)
{
/* This matching logic is equivalent to the one present in OpenSSH 4.1 */
while (true)
{
/* Are we at the end of the pattern? */
if (pattern.length == i)
return (match.length == j);
if (pattern[i] == '*')
{
i++;
if (pattern.length == i)
return true;
if ((pattern[i] != '*') && (pattern[i] != '?'))
{
while (true)
{
if ((pattern[i] == match[j]) && pseudoRegex(pattern, i + 1, match, j + 1))
return true;
j++;
if (match.length == j)
return false;
}
}
while (true)
{
if (pseudoRegex(pattern, i, match, j))
return true;
j++;
if (match.length == j)
return false;
}
}
if (match.length == j)
return false;
if ((pattern[i] != '?') && (pattern[i] != match[j]))
return false;
i++;
j++;
}
}
private String[] recommendHostkeyAlgorithms(String hostname)
{
String preferredAlgo = null;
Vector keys = getAllKeys(hostname);
for (int i = 0; i < keys.size(); i++)
{
String thisAlgo = null;
if (keys.elementAt(i) instanceof RSAPublicKey)
thisAlgo = "ssh-rsa";
else if (keys.elementAt(i) instanceof DSAPublicKey)
thisAlgo = "ssh-dss";
else
continue;
if (preferredAlgo != null)
{
/* If we find different key types, then return null */
if (preferredAlgo.compareTo(thisAlgo) != 0)
return null;
/* OK, we found the same algo again, optimize */
continue;
}
}
/* If we did not find anything that we know of, return null */
if (preferredAlgo == null)
return null;
/* Now put the preferred algo to the start of the array.
* You may ask yourself why we do it that way - basically, we could just
* return only the preferred algorithm: since we have a saved key of that
* type (sent earlier from the remote host), then that should work out.
* However, imagine that the server is (for whatever reasons) not offering
* that type of hostkey anymore (e.g., "ssh-rsa" was disabled and
* now "ssh-dss" is being used). If we then do not let the server send us
* a fresh key of the new type, then we shoot ourself into the foot:
* the connection cannot be established and hence the user cannot decide
* if he/she wants to accept the new key.
*/
if (preferredAlgo.equals("ssh-rsa"))
return new String[] { "ssh-rsa", "ssh-dss" };
return new String[] { "ssh-dss", "ssh-rsa" };
}
/**
* Checks the internal hostkey database for the given hostkey.
* If no matching key can be found, then the hostname is resolved to an IP address
* and the search is repeated using that IP address.
*
* @param hostname the server's hostname, will be matched with all hostname patterns
* @param serverHostKeyAlgorithm type of hostkey, either <code>ssh-rsa</code> or <code>ssh-dss</code>
* @param serverHostKey the key blob
* @return <ul>
* <li><code>HOSTKEY_IS_OK</code>: the given hostkey matches an entry for the given hostname</li>
* <li><code>HOSTKEY_IS_NEW</code>: no entries found for this hostname and this type of hostkey</li>
* <li><code>HOSTKEY_HAS_CHANGED</code>: hostname is known, but with another key of the same type
* (man-in-the-middle attack?)</li>
* </ul>
* @throws IOException if the supplied key blob cannot be parsed or does not match the given hostkey type.
*/
public int verifyHostkey(String hostname, String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException
{
Object remoteKey = null;
if ("ssh-rsa".equals(serverHostKeyAlgorithm))
{
remoteKey = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey);
}
else if ("ssh-dss".equals(serverHostKeyAlgorithm))
{
remoteKey = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey);
}
else
throw new IllegalArgumentException("Unknown hostkey type " + serverHostKeyAlgorithm);
int result = checkKey(hostname, remoteKey);
if (result == HOSTKEY_IS_OK)
return result;
InetAddress[] ipAdresses = null;
try
{
ipAdresses = InetAddress.getAllByName(hostname);
}
catch (UnknownHostException e)
{
return result;
}
for (int i = 0; i < ipAdresses.length; i++)
{
int newresult = checkKey(ipAdresses[i].getHostAddress(), remoteKey);
if (newresult == HOSTKEY_IS_OK)
return newresult;
if (newresult == HOSTKEY_HAS_CHANGED)
result = HOSTKEY_HAS_CHANGED;
}
return result;
}
/**
* Adds a single public key entry to the a known_hosts file.
* This method is designed to be used in a {@link ServerHostKeyVerifier}.
*
* @param knownHosts the file where the publickey entry will be appended.
* @param hostnames a list of hostname patterns - at least one most be specified. Check out the
* OpenSSH sshd man page for a description of the pattern matching algorithm.
* @param serverHostKeyAlgorithm as passed to the {@link ServerHostKeyVerifier}.
* @param serverHostKey as passed to the {@link ServerHostKeyVerifier}.
* @throws IOException
*/
public final static void addHostkeyToFile(File knownHosts, String[] hostnames, String serverHostKeyAlgorithm,
byte[] serverHostKey) throws IOException
{
if ((hostnames == null) || (hostnames.length == 0))
throw new IllegalArgumentException("Need at least one hostname specification");
if ((serverHostKeyAlgorithm == null) || (serverHostKey == null))
throw new IllegalArgumentException();
CharArrayWriter writer = new CharArrayWriter();
for (int i = 0; i < hostnames.length; i++)
{
if (i != 0)
writer.write(',');
writer.write(hostnames[i].toLowerCase());
}
writer.write(' ');
writer.write(serverHostKeyAlgorithm);
writer.write(' ');
writer.write(Base64.encode(serverHostKey));
writer.write("\n");
char[] entry = writer.toCharArray();
RandomAccessFile raf = new RandomAccessFile(knownHosts, "rw");
long len = raf.length();
if (len > 0)
{
raf.seek(len - 1);
int last = raf.read();
if (last != '\n')
raf.write('\n');
}
raf.write(new String(entry).getBytes());
raf.close();
}
/**
* Generates a "raw" fingerprint of a hostkey.
*
* @param type either "md5" or "sha1"
* @param keyType either "ssh-rsa" or "ssh-dss"
* @param hostkey the hostkey
* @return the raw fingerprint
*/
static final private byte[] rawFingerPrint(String type, String keyType, byte[] hostkey)
{
Digest dig = null;
if ("md5".equals(type))
{
dig = new MD5();
}
else if ("sha1".equals(type))
{
dig = new SHA1();
}
else
throw new IllegalArgumentException("Unknown hash type " + type);
if ("ssh-rsa".equals(keyType))
{
}
else if ("ssh-dss".equals(keyType))
{
}
else
throw new IllegalArgumentException("Unknown key type " + keyType);
if (hostkey == null)
throw new IllegalArgumentException("hostkey is null");
dig.update(hostkey);
byte[] res = new byte[dig.getDigestLength()];
dig.digest(res);
return res;
}
/**
* Convert a raw fingerprint to hex representation (XX:YY:ZZ...).
* @param fingerprint raw fingerprint
* @return the hex representation
*/
static final private String rawToHexFingerprint(byte[] fingerprint)
{
final char[] alpha = "0123456789abcdef".toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < fingerprint.length; i++)
{
if (i != 0)
sb.append(':');
int b = fingerprint[i] & 0xff;
sb.append(alpha[b >> 4]);
sb.append(alpha[b & 15]);
}
return sb.toString();
}
/**
* Convert a raw fingerprint to bubblebabble representation.
* @param raw raw fingerprint
* @return the bubblebabble representation
*/
static final private String rawToBubblebabbleFingerprint(byte[] raw)
{
final char[] v = "aeiouy".toCharArray();
final char[] c = "bcdfghklmnprstvzx".toCharArray();
StringBuffer sb = new StringBuffer();
int seed = 1;
int rounds = (raw.length / 2) + 1;
sb.append('x');
for (int i = 0; i < rounds; i++)
{
if (((i + 1) < rounds) || ((raw.length) % 2 != 0))
{
sb.append(v[(((raw[2 * i] >> 6) & 3) + seed) % 6]);
sb.append(c[(raw[2 * i] >> 2) & 15]);
sb.append(v[((raw[2 * i] & 3) + (seed / 6)) % 6]);
if ((i + 1) < rounds)
{
sb.append(c[(((raw[(2 * i) + 1])) >> 4) & 15]);
sb.append('-');
sb.append(c[(((raw[(2 * i) + 1]))) & 15]);
// As long as seed >= 0, seed will be >= 0 afterwards
seed = ((seed * 5) + (((raw[2 * i] & 0xff) * 7) + (raw[(2 * i) + 1] & 0xff))) % 36;
}
}
else
{
sb.append(v[seed % 6]); // seed >= 0, therefore index positive
sb.append('x');
sb.append(v[seed / 6]);
}
}
sb.append('x');
return sb.toString();
}
/**
* Convert a ssh2 key-blob into a human readable hex fingerprint.
* Generated fingerprints are identical to those generated by OpenSSH.
* <p>
* Example fingerprint: d0:cb:76:19:99:5a:03:fc:73:10:70:93:f2:44:63:47.
* @param keytype either "ssh-rsa" or "ssh-dss"
* @param publickey key blob
* @return Hex fingerprint
*/
public final static String createHexFingerprint(String keytype, byte[] publickey)
{
byte[] raw = rawFingerPrint("md5", keytype, publickey);
return rawToHexFingerprint(raw);
}
/**
* Convert a ssh2 key-blob into a human readable bubblebabble fingerprint.
* The used bubblebabble algorithm (taken from OpenSSH) generates fingerprints
* that are easier to remember for humans.
* <p>
* Example fingerprint: xofoc-bubuz-cazin-zufyl-pivuk-biduk-tacib-pybur-gonar-hotat-lyxux.
*
* @param keytype either "ssh-rsa" or "ssh-dss"
* @param publickey key data
* @return Bubblebabble fingerprint
*/
public final static String createBubblebabbleFingerprint(String keytype, byte[] publickey)
{
byte[] raw = rawFingerPrint("sha1", keytype, publickey);
return rawToBubblebabbleFingerprint(raw);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -