⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 knownhosts.java

📁 thinking in java4 src
💻 JAVA
📖 第 1 页 / 共 2 页
字号:

		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 + -