diff options
Diffstat (limited to 'src')
26 files changed, 611 insertions, 1856 deletions
| diff --git a/src/com/trilead/ssh2/AuthAgentCallback.java b/src/com/trilead/ssh2/AuthAgentCallback.java index c395198..7fe270b 100644 --- a/src/com/trilead/ssh2/AuthAgentCallback.java +++ b/src/com/trilead/ssh2/AuthAgentCallback.java @@ -1,5 +1,6 @@  package com.trilead.ssh2; +import java.security.KeyPair;  import java.util.Map;  /** @@ -24,7 +25,7 @@ public interface AuthAgentCallback {  	 * @param lifetime lifetime in seconds for key to be remembered  	 * @return success or failure  	 */ -	boolean addIdentity(Object key, String comment, boolean confirmUse, int lifetime); +	boolean addIdentity(KeyPair pair, String comment, boolean confirmUse, int lifetime);  	/**  	 * @param publicKey byte blob containing the OpenSSH-format encoded public key @@ -43,7 +44,7 @@ public interface AuthAgentCallback {  	 *         containing a DSA or RSA private key of  	 *         the user in Trilead object format.  	 */ -	Object getPrivateKey(byte[] publicKey); +	KeyPair getKeyPair(byte[] publicKey);  	/**  	 * @return diff --git a/src/com/trilead/ssh2/Connection.java b/src/com/trilead/ssh2/Connection.java index 98e5fdd..c1e8711 100644 --- a/src/com/trilead/ssh2/Connection.java +++ b/src/com/trilead/ssh2/Connection.java @@ -7,7 +7,10 @@ import java.io.FileReader;  import java.io.IOException;
  import java.net.InetSocketAddress;
  import java.net.SocketTimeoutException;
 +import java.security.KeyPair;
  import java.security.SecureRandom;
 +import java.security.Security;
 +import java.util.Set;
  import java.util.Vector;
  import com.trilead.ssh2.auth.AuthenticationManager;
 @@ -473,7 +476,7 @@ public class Connection  	 * @return whether the connection is now authenticated.
  	 * @throws IOException
  	 */
 -	public synchronized boolean authenticateWithPublicKey(String user, Object key)
 +	public synchronized boolean authenticateWithPublicKey(String user, KeyPair pair)
  			throws IOException
  	{
  		if (tm == null)
 @@ -491,10 +494,10 @@ public class Connection  		if (user == null)
  			throw new IllegalArgumentException("user argument is null");
 -		if (key == null)
 -			throw new IllegalArgumentException("Key argument is null");
 +		if (pair == null)
 +			throw new IllegalArgumentException("Key pair argument is null");
 -		authenticated = am.authenticatePublicKey(user, key, getOrCreateSecureRND());
 +		authenticated = am.authenticatePublicKey(user, pair, getOrCreateSecureRND());
  		return authenticated;
  	}
 diff --git a/src/com/trilead/ssh2/KnownHosts.java b/src/com/trilead/ssh2/KnownHosts.java index edca0a2..c68b852 100644 --- a/src/com/trilead/ssh2/KnownHosts.java +++ b/src/com/trilead/ssh2/KnownHosts.java @@ -11,19 +11,23 @@ import java.io.RandomAccessFile;  import java.io.UnsupportedEncodingException;
  import java.net.InetAddress;
  import java.net.UnknownHostException;
 +import java.security.InvalidKeyException;
 +import java.security.MessageDigest;
 +import java.security.NoSuchAlgorithmException;
 +import java.security.PublicKey;
  import java.security.SecureRandom;
 +import java.security.interfaces.DSAPublicKey;
 +import java.security.interfaces.RSAPublicKey;
  import java.util.Iterator;
  import java.util.LinkedList;
 +import java.util.Locale;
  import java.util.Vector;
 +import javax.crypto.Mac;
 +import javax.crypto.spec.SecretKeySpec;
 +
  import com.trilead.ssh2.crypto.Base64;
 -import com.trilead.ssh2.crypto.digest.Digest;
 -import com.trilead.ssh2.crypto.digest.HMAC;
 -import com.trilead.ssh2.crypto.digest.MD5;
 -import com.trilead.ssh2.crypto.digest.SHA1;
 -import com.trilead.ssh2.signature.DSAPublicKey;
  import com.trilead.ssh2.signature.DSASHA1Verify;
 -import com.trilead.ssh2.signature.RSAPublicKey;
  import com.trilead.ssh2.signature.RSASHA1Verify;
 @@ -52,16 +56,16 @@ public class KnownHosts  	private class KnownHostsEntry
  	{
  		String[] patterns;
 -		Object key;
 +		PublicKey key;
 -		KnownHostsEntry(String[] patterns, Object key)
 +		KnownHostsEntry(String[] patterns, PublicKey key)
  		{
  			this.patterns = patterns;
  			this.key = key;
  		}
  	}
 -	private LinkedList publicKeys = new LinkedList();
 +	private LinkedList<KnownHostsEntry> publicKeys = new LinkedList<KnownHostsEntry>();
  	public KnownHosts()
  	{
 @@ -140,13 +144,18 @@ public class KnownHosts  	/**
  	 * Generate the hashed representation of the given hostname. Useful for adding entries
  	 * with hashed hostnames to a known_hosts file. (see -H option of OpenSSH key-gen).
 -	 *  
 +	 *
  	 * @param hostname
  	 * @return the hashed representation, e.g., "|1|cDhrv7zwEUV3k71CEPHnhHZezhA=|Xo+2y6rUXo2OIWRAYhBOIijbJMA="
  	 */
  	public static final String createHashedHostname(String hostname)
  	{
 -		SHA1 sha1 = new SHA1();
 +		MessageDigest sha1;
 +		try {
 +			sha1 = MessageDigest.getInstance("SHA1");
 +		} catch (NoSuchAlgorithmException e) {
 +			throw new RuntimeException("VM doesn't support SHA1", e);
 +		}
  		byte[] salt = new byte[sha1.getDigestLength()];
 @@ -162,12 +171,17 @@ public class KnownHosts  	private static final byte[] hmacSha1Hash(byte[] salt, String hostname)
  	{
 -		SHA1 sha1 = new SHA1();
 -
 -		if (salt.length != sha1.getDigestLength())
 -			throw new IllegalArgumentException("Salt has wrong length (" + salt.length + ")");
 -
 -		HMAC hmac = new HMAC(sha1, salt, salt.length);
 +		Mac hmac;
 +		try {
 +			hmac = Mac.getInstance("HmacSHA1");
 +			if (salt.length != hmac.getMacLength())
 +				throw new IllegalArgumentException("Salt has wrong length (" + salt.length + ")");
 +			hmac.init(new SecretKeySpec(salt, "HmacSHA1"));
 +		} catch (NoSuchAlgorithmException e) {
 +			throw new RuntimeException("Unable to HMAC-SHA1", e);
 +		} catch (InvalidKeyException e) {
 +			throw new RuntimeException("Unable to create SecretKey", e);
 +		}
  		try
  		{
 @@ -178,12 +192,8 @@ public class KnownHosts  			 * Java implementations. But... you never know. */
  			hmac.update(hostname.getBytes());
  		}
 -		
 -		byte[] dig = new byte[hmac.getDigestLength()];
 -		hmac.digest(dig);
 -
 -		return dig;
 +		return hmac.doFinal();
  	}
  	private final boolean checkHashed(String entry, String hostname)
 @@ -212,10 +222,13 @@ public class KnownHosts  			return false;
  		}
 -		SHA1 sha1 = new SHA1();
 -
 -		if (salt.length != sha1.getDigestLength())
 -			return false;
 +		try {
 +			MessageDigest sha1 = MessageDigest.getInstance("SHA1");
 +			if (salt.length != sha1.getDigestLength())
 +				return false;
 +		} catch (NoSuchAlgorithmException e) {
 +			throw new RuntimeException("VM does not support SHA1", e);
 +		}
  		byte[] dig = hmacSha1Hash(salt, hostname);
 @@ -226,17 +239,17 @@ public class KnownHosts  		return true;
  	}
 -	private int checkKey(String remoteHostname, Object remoteKey)
 +	private int checkKey(String remoteHostname, PublicKey remoteKey)
  	{
  		int result = HOSTKEY_IS_NEW;
  		synchronized (publicKeys)
  		{
 -			Iterator i = publicKeys.iterator();
 -			
 +			Iterator<KnownHostsEntry> i = publicKeys.iterator();
 +
  			while (i.hasNext())
  			{
 -				KnownHostsEntry ke = (KnownHostsEntry) i.next();
 +				KnownHostsEntry ke = i.next();
  				if (hostnameMatches(ke.patterns, remoteHostname) == false)
  					continue;
 @@ -252,17 +265,17 @@ public class KnownHosts  		return result;
  	}
 -	private Vector getAllKeys(String hostname)
 +	private Vector<PublicKey> getAllKeys(String hostname)
  	{
 -		Vector keys = new Vector();
 +		Vector<PublicKey> keys = new Vector<PublicKey>();
  		synchronized (publicKeys)
  		{
 -			Iterator i = publicKeys.iterator();
 +			Iterator<KnownHostsEntry> i = publicKeys.iterator();
  			while (i.hasNext())
  			{
 -				KnownHostsEntry ke = (KnownHostsEntry) i.next();
 +				KnownHostsEntry ke = i.next();
  				if (hostnameMatches(ke.patterns, hostname) == false)
  					continue;
 @@ -320,7 +333,7 @@ public class KnownHosts  		boolean isMatch = false;
  		boolean negate = false;
 -		hostname = hostname.toLowerCase();
 +		hostname = hostname.toLowerCase(Locale.US);
  		for (int k = 0; k < hostpatterns.length; k++)
  		{
 @@ -362,7 +375,7 @@ public class KnownHosts  			}
  			else
  			{
 -				pattern = pattern.toLowerCase();
 +				pattern = pattern.toLowerCase(Locale.US);
  				if ((pattern.indexOf('?') != -1) || (pattern.indexOf('*') != -1))
  				{
 @@ -440,43 +453,9 @@ public class KnownHosts  		initialize(cw.toCharArray());
  	}
 -	private final boolean matchKeys(Object key1, Object key2)
 +	private final boolean matchKeys(PublicKey key1, PublicKey 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;
 +	    return key1.equals(key2);
  	}
  	private final boolean pseudoRegex(char[] pattern, int i, char[] match, int j)
 @@ -534,7 +513,7 @@ public class KnownHosts  	{
  		String preferredAlgo = null;
 -		Vector keys = getAllKeys(hostname);
 +		Vector<PublicKey> keys = getAllKeys(hostname);
  		for (int i = 0; i < keys.size(); i++)
  		{
 @@ -601,7 +580,7 @@ public class KnownHosts  	 */
  	public int verifyHostkey(String hostname, String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException
  	{
 -		Object remoteKey = null;
 +		PublicKey remoteKey = null;
  		if ("ssh-rsa".equals(serverHostKeyAlgorithm))
  		{
 @@ -707,18 +686,24 @@ public class KnownHosts  	 */
  	static final private byte[] rawFingerPrint(String type, String keyType, byte[] hostkey)
  	{
 -		Digest dig = null;
 +		MessageDigest dig = null;
 -		if ("md5".equals(type))
 -		{
 -			dig = new MD5();
 -		}
 -		else if ("sha1".equals(type))
 -		{
 -			dig = new SHA1();
 -		}
 -		else
 +		try {
 +			if ("md5".equals(type))
 +			{
 +				dig = MessageDigest.getInstance("MD5");
 +			}
 +			else if ("sha1".equals(type))
 +			{
 +				dig = MessageDigest.getInstance("SHA1");
 +			}
 +			else
 +			{
 +				throw new IllegalArgumentException("Unknown hash type " + type);
 +			}
 +		} catch (NoSuchAlgorithmException e) {
  			throw new IllegalArgumentException("Unknown hash type " + type);
 +		}
  		if ("ssh-rsa".equals(keyType))
  		{
 @@ -733,9 +718,7 @@ public class KnownHosts  			throw new IllegalArgumentException("hostkey is null");
  		dig.update(hostkey);
 -		byte[] res = new byte[dig.getDigestLength()];
 -		dig.digest(res);
 -		return res;
 +		return dig.digest();
  	}
  	/**
 diff --git a/src/com/trilead/ssh2/auth/AuthenticationManager.java b/src/com/trilead/ssh2/auth/AuthenticationManager.java index 43c226a..e1e416e 100644 --- a/src/com/trilead/ssh2/auth/AuthenticationManager.java +++ b/src/com/trilead/ssh2/auth/AuthenticationManager.java @@ -2,7 +2,13 @@  package com.trilead.ssh2.auth;
  import java.io.IOException;
 +import java.security.KeyPair;
 +import java.security.PrivateKey;
  import java.security.SecureRandom;
 +import java.security.interfaces.DSAPrivateKey;
 +import java.security.interfaces.DSAPublicKey;
 +import java.security.interfaces.RSAPrivateKey;
 +import java.security.interfaces.RSAPublicKey;
  import java.util.Vector;
  import com.trilead.ssh2.InteractiveCallback;
 @@ -19,12 +25,8 @@ import com.trilead.ssh2.packets.PacketUserauthRequestPassword;  import com.trilead.ssh2.packets.PacketUserauthRequestPublicKey;
  import com.trilead.ssh2.packets.Packets;
  import com.trilead.ssh2.packets.TypesWriter;
 -import com.trilead.ssh2.signature.DSAPrivateKey;
  import com.trilead.ssh2.signature.DSASHA1Verify;
 -import com.trilead.ssh2.signature.DSASignature;
 -import com.trilead.ssh2.signature.RSAPrivateKey;
  import com.trilead.ssh2.signature.RSASHA1Verify;
 -import com.trilead.ssh2.signature.RSASignature;
  import com.trilead.ssh2.transport.MessageHandler;
  import com.trilead.ssh2.transport.TransportManager;
 @@ -161,14 +163,16 @@ public class AuthenticationManager implements MessageHandler  	public boolean authenticatePublicKey(String user, char[] PEMPrivateKey, String password, SecureRandom rnd)
  			throws IOException
  	{
 -		Object key = PEMDecoder.decode(PEMPrivateKey, password);
 -		
 -		return authenticatePublicKey(user, key, rnd);
 +		KeyPair pair = PEMDecoder.decode(PEMPrivateKey, password);
 +
 +		return authenticatePublicKey(user, pair, rnd);
  	}
 -	
 -	public boolean authenticatePublicKey(String user, Object key, SecureRandom rnd)
 +
 +	public boolean authenticatePublicKey(String user, KeyPair pair, SecureRandom rnd)
  			throws IOException
  	{
 +		PrivateKey key = pair.getPrivate();
 +
  		try
  		{
  			initialize(user);
 @@ -180,7 +184,7 @@ public class AuthenticationManager implements MessageHandler  			{
  				DSAPrivateKey pk = (DSAPrivateKey) key;
 -				byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey(pk.getPublicKey());
 +				byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic());
  				TypesWriter tw = new TypesWriter();
 @@ -197,7 +201,7 @@ public class AuthenticationManager implements MessageHandler  				byte[] msg = tw.getBytes();
 -				DSASignature ds = DSASHA1Verify.generateSignature(msg, pk, rnd);
 +				byte[] ds = DSASHA1Verify.generateSignature(msg, pk, rnd);
  				byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds);
 @@ -209,7 +213,7 @@ public class AuthenticationManager implements MessageHandler  			{
  				RSAPrivateKey pk = (RSAPrivateKey) key;
 -				byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey(pk.getPublicKey());
 +				byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic());
  				TypesWriter tw = new TypesWriter();
  				{
 @@ -227,7 +231,7 @@ public class AuthenticationManager implements MessageHandler  				byte[] msg = tw.getBytes();
 -				RSASignature ds = RSASHA1Verify.generateSignature(msg, pk);
 +				byte[] ds = RSASHA1Verify.generateSignature(msg, pk);
  				byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds);
 diff --git a/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java b/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java index 57b9a5e..d3f10a3 100644 --- a/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java +++ b/src/com/trilead/ssh2/channel/AuthAgentForwardThread.java @@ -21,7 +21,20 @@ import java.io.IOException;  import java.io.InputStream;  import java.io.OutputStream;  import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey;  import java.security.SecureRandom; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec;  import java.util.Map;  import java.util.Map.Entry; @@ -29,12 +42,8 @@ import com.trilead.ssh2.AuthAgentCallback;  import com.trilead.ssh2.log.Logger;  import com.trilead.ssh2.packets.TypesReader;  import com.trilead.ssh2.packets.TypesWriter; -import com.trilead.ssh2.signature.DSAPrivateKey;  import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.DSASignature; -import com.trilead.ssh2.signature.RSAPrivateKey;  import com.trilead.ssh2.signature.RSASHA1Verify; -import com.trilead.ssh2.signature.RSASignature;  /**   * AuthAgentForwardThread. @@ -268,7 +277,7 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  			String type = tr.readString(); -			Object key; +			KeyPair pair;  			String comment;  			if (type.equals("ssh-rsa")) { @@ -280,7 +289,24 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  				tr.readMPINT(); // q  				comment = tr.readString(); -				key = new RSAPrivateKey(d, e, n); +				KeySpec pubSpec = new RSAPublicKeySpec(n, e); +				KeySpec privSpec = new RSAPrivateKeySpec(n, d); + +				PublicKey pubKey; +				PrivateKey privKey; +				try { +					KeyFactory kf = KeyFactory.getInstance("RSA"); +					pubKey = kf.generatePublic(pubSpec); +					privKey = kf.generatePrivate(privSpec); +				} catch (NoSuchAlgorithmException ex) { +					// TODO: log error +					return; +				} catch (InvalidKeySpecException ex) { +					// TODO: log error +					return; +				} + +				pair = new KeyPair(pubKey, privKey);  			} else if (type.equals("ssh-dss")) {  				BigInteger p = tr.readMPINT();  				BigInteger q = tr.readMPINT(); @@ -289,7 +315,24 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  				BigInteger x = tr.readMPINT();  				comment = tr.readString(); -				key = new DSAPrivateKey(p, q, g, y, x); +				KeySpec pubSpec = new DSAPublicKeySpec(y, p, q, g); +				KeySpec privSpec = new DSAPrivateKeySpec(x, p, q, g); + +				PublicKey pubKey; +				PrivateKey privKey; +				try { +					KeyFactory kf = KeyFactory.getInstance("DSA"); +					pubKey = kf.generatePublic(pubSpec); +					privKey = kf.generatePrivate(privSpec); +				} catch (NoSuchAlgorithmException ex) { +					// TODO: log error +					return; +				} catch (InvalidKeySpecException ex) { +					// TODO: log error +					return; +				} + +				pair = new KeyPair(pubKey, privKey);  			} else {  				os.write(SSH_AGENT_FAILURE);  				return; @@ -313,7 +356,7 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  				}  			} -			if (authAgent.addIdentity(key, comment, confirmUse, lifetime)) +			if (authAgent.addIdentity(pair, comment, confirmUse, lifetime))  				os.write(SSH_AGENT_SUCCESS);  			else  				os.write(SSH_AGENT_FAILURE); @@ -390,7 +433,7 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  			if (failWhenLocked())  				return; -			byte[] publicKey = tr.readByteString(); +			byte[] publicKeyBytes = tr.readByteString();  			byte[] challenge = tr.readByteString();  			int flags = tr.readUINT32(); @@ -401,22 +444,23 @@ public class AuthAgentForwardThread extends Thread implements IChannelWorkerThre  				return;  			} -			Object trileadKey = authAgent.getPrivateKey(publicKey); +			KeyPair pair = authAgent.getKeyPair(publicKeyBytes); -			if (trileadKey == null) { +			if (pair == null) {  				os.write(SSH_AGENT_FAILURE);  				return;  			}  			byte[] response; -			if (trileadKey instanceof RSAPrivateKey) { -				RSASignature signature = RSASHA1Verify.generateSignature(challenge, -						(RSAPrivateKey) trileadKey); +			PrivateKey privKey = pair.getPrivate(); +			if (privKey instanceof RSAPrivateKey) { +				byte[] signature = RSASHA1Verify.generateSignature(challenge, +						(RSAPrivateKey) privKey);  				response = RSASHA1Verify.encodeSSHRSASignature(signature); -			} else if (trileadKey instanceof DSAPrivateKey) { -				DSASignature signature = DSASHA1Verify.generateSignature(challenge, -						(DSAPrivateKey) trileadKey, new SecureRandom()); +			} else if (privKey instanceof DSAPrivateKey) { +				byte[] signature = DSASHA1Verify.generateSignature(challenge, +						(DSAPrivateKey) privKey, new SecureRandom());  				response = DSASHA1Verify.encodeSSHDSASignature(signature);  			} else {  				os.write(SSH_AGENT_FAILURE); diff --git a/src/com/trilead/ssh2/channel/ChannelManager.java b/src/com/trilead/ssh2/channel/ChannelManager.java index 630e0cc..432aef5 100644 --- a/src/com/trilead/ssh2/channel/ChannelManager.java +++ b/src/com/trilead/ssh2/channel/ChannelManager.java @@ -40,21 +40,21 @@ public class ChannelManager implements MessageHandler  {
  	private static final Logger log = Logger.getLogger(ChannelManager.class);
 -	private HashMap x11_magic_cookies = new HashMap();
 +	private HashMap<String, X11ServerData> x11_magic_cookies = new HashMap<String, X11ServerData>();
  	private TransportManager tm;
 -	private Vector channels = new Vector();
 +	private Vector<Channel> channels = new Vector<Channel>();
  	private int nextLocalChannel = 100;
  	private boolean shutdown = false;
  	private int globalSuccessCounter = 0;
  	private int globalFailedCounter = 0;
 -	private HashMap remoteForwardings = new HashMap();
 +	private HashMap<Integer, RemoteForwardingData> remoteForwardings = new HashMap<Integer, RemoteForwardingData>();
  	private AuthAgentCallback authAgent;
 -	private Vector listenerThreads = new Vector();
 +	private Vector<IChannelWorkerThread> listenerThreads = new Vector<IChannelWorkerThread>();
  	private boolean listenerThreadsAllowed = true;
 @@ -70,7 +70,7 @@ public class ChannelManager implements MessageHandler  		{
  			for (int i = 0; i < channels.size(); i++)
  			{
 -				Channel c = (Channel) channels.elementAt(i);
 +				Channel c = channels.elementAt(i);
  				if (c.localID == id)
  					return c;
  			}
 @@ -84,7 +84,7 @@ public class ChannelManager implements MessageHandler  		{
  			for (int i = 0; i < channels.size(); i++)
  			{
 -				Channel c = (Channel) channels.elementAt(i);
 +				Channel c = channels.elementAt(i);
  				if (c.localID == id)
  				{
  					channels.removeElementAt(i);
 @@ -223,16 +223,16 @@ public class ChannelManager implements MessageHandler  		if (log.isEnabled())
  			log.log(50, "Closing all X11 channels for the given fake cookie");
 -		Vector channel_copy;
 +		Vector<Channel> channel_copy;
  		synchronized (channels)
  		{
 -			channel_copy = (Vector) channels.clone();
 +			channel_copy = (Vector<Channel>) channels.clone();
  		}
  		for (int i = 0; i < channel_copy.size(); i++)
  		{
 -			Channel c = (Channel) channel_copy.elementAt(i);
 +			Channel c = channel_copy.elementAt(i);
  			synchronized (c)
  			{
 @@ -255,7 +255,7 @@ public class ChannelManager implements MessageHandler  		synchronized (x11_magic_cookies)
  		{
  			if (hexFakeCookie != null)
 -				return (X11ServerData) x11_magic_cookies.get(hexFakeCookie);
 +				return x11_magic_cookies.get(hexFakeCookie);
  		}
  		return null;
  	}
 @@ -265,16 +265,16 @@ public class ChannelManager implements MessageHandler  		if (log.isEnabled())
  			log.log(50, "Closing all channels");
 -		Vector channel_copy;
 +		Vector<Channel> channel_copy;
  		synchronized (channels)
  		{
 -			channel_copy = (Vector) channels.clone();
 +			channel_copy = (Vector<Channel>) channels.clone();
  		}
  		for (int i = 0; i < channel_copy.size(); i++)
  		{
 -			Channel c = (Channel) channel_copy.elementAt(i);
 +			Channel c = channel_copy.elementAt(i);
  			try
  			{
  				closeChannel(c, "Closing all channels", true);
 @@ -456,7 +456,7 @@ public class ChannelManager implements MessageHandler  		synchronized (remoteForwardings)
  		{
 -			Integer key = new Integer(bindPort);
 +			Integer key = Integer.valueOf(bindPort);
  			if (remoteForwardings.get(key) != null)
  			{
 @@ -500,7 +500,7 @@ public class ChannelManager implements MessageHandler  		synchronized (remoteForwardings)
  		{
 -			rfd = (RemoteForwardingData) remoteForwardings.get(new Integer(bindPort));
 +			rfd = remoteForwardings.get(Integer.valueOf(bindPort));
  			if (rfd == null)
  				throw new IOException("Sorry, there is no known remote forwarding for remote port " + bindPort);
 @@ -1268,7 +1268,7 @@ public class ChannelManager implements MessageHandler  			synchronized (remoteForwardings)
  			{
 -				rfd = (RemoteForwardingData) remoteForwardings.get(new Integer(remoteConnectedPort));
 +				rfd = remoteForwardings.get(Integer.valueOf(remoteConnectedPort));
  			}
  			if (rfd == null)
 @@ -1370,7 +1370,7 @@ public class ChannelManager implements MessageHandler  			synchronized (c)
  			{
 -				c.exit_status = new Integer(exit_status);
 +				c.exit_status = Integer.valueOf(exit_status);
  				c.notifyAll();
  			}
 @@ -1670,7 +1670,7 @@ public class ChannelManager implements MessageHandler  			{
  				for (int i = 0; i < listenerThreads.size(); i++)
  				{
 -					IChannelWorkerThread lat = (IChannelWorkerThread) listenerThreads.elementAt(i);
 +					IChannelWorkerThread lat = listenerThreads.elementAt(i);
  					lat.stopWorking();
  				}
  				listenerThreadsAllowed = false;
 @@ -1682,7 +1682,7 @@ public class ChannelManager implements MessageHandler  				for (int i = 0; i < channels.size(); i++)
  				{
 -					Channel c = (Channel) channels.elementAt(i);
 +					Channel c = channels.elementAt(i);
  					synchronized (c)
  					{
  						c.EOF = true;
 diff --git a/src/com/trilead/ssh2/crypto/PEMDecoder.java b/src/com/trilead/ssh2/crypto/PEMDecoder.java index 7d0a015..cf6be37 100644 --- a/src/com/trilead/ssh2/crypto/PEMDecoder.java +++ b/src/com/trilead/ssh2/crypto/PEMDecoder.java @@ -5,15 +5,25 @@ import java.io.BufferedReader;  import java.io.CharArrayReader;
  import java.io.IOException;
  import java.math.BigInteger;
 +import java.security.DigestException;
 +import java.security.KeyFactory;
 +import java.security.KeyPair;
 +import java.security.MessageDigest;
 +import java.security.NoSuchAlgorithmException;
 +import java.security.PrivateKey;
 +import java.security.PublicKey;
 +import java.security.spec.DSAPrivateKeySpec;
 +import java.security.spec.DSAPublicKeySpec;
 +import java.security.spec.InvalidKeySpecException;
 +import java.security.spec.RSAPrivateCrtKeySpec;
 +import java.security.spec.RSAPrivateKeySpec;
 +import java.security.spec.RSAPublicKeySpec;
  import com.trilead.ssh2.crypto.cipher.AES;
  import com.trilead.ssh2.crypto.cipher.BlockCipher;
  import com.trilead.ssh2.crypto.cipher.CBCMode;
  import com.trilead.ssh2.crypto.cipher.DES;
  import com.trilead.ssh2.crypto.cipher.DESede;
 -import com.trilead.ssh2.crypto.digest.MD5;
 -import com.trilead.ssh2.signature.DSAPrivateKey;
 -import com.trilead.ssh2.signature.RSAPrivateKey;
  /**
   * PEM Support.
 @@ -73,7 +83,12 @@ public class PEMDecoder  		if (salt.length < 8)
  			throw new IllegalArgumentException("Salt needs to be at least 8 bytes for key generation.");
 -		MD5 md5 = new MD5();
 +		MessageDigest md5;
 +		try {
 +			md5 = MessageDigest.getInstance("MD5");
 +		} catch (NoSuchAlgorithmException e) {
 +			throw new IllegalArgumentException("VM does not support MD5", e);
 +		}
  		byte[] key = new byte[keyLen];
  		byte[] tmp = new byte[md5.getDigestLength()];
 @@ -87,7 +102,13 @@ public class PEMDecoder  			int copy = (keyLen < tmp.length) ? keyLen : tmp.length;
 -			md5.digest(tmp, 0);
 +			try {
 +				md5.digest(tmp, 0, tmp.length);
 +			} catch (DigestException e) {
 +				IOException ex = new IOException("could not digest password");
 +				ex.initCause(e);
 +				throw ex;
 +			}
  			System.arraycopy(tmp, 0, key, key.length - keyLen, copy);
 @@ -308,7 +329,7 @@ public class PEMDecoder  		return false;
  	}
 -	public static Object decode(char[] pem, String password) throws IOException
 +	public static KeyPair decode(char[] pem, String password) throws IOException
  	{
  		PEMStructure ps = parsePEM(pem);
 @@ -345,7 +366,26 @@ public class PEMDecoder  			if (dr.available() != 0)
  				throw new IOException("Padding in DSA PRIVATE KEY DER stream.");
 -			return new DSAPrivateKey(p, q, g, y, x);
 +			DSAPrivateKeySpec privSpec = new DSAPrivateKeySpec(x, p, q, g);
 +			DSAPublicKeySpec pubSpec = new DSAPublicKeySpec(y, p, q, g);
 +
 +			PublicKey pubKey;
 +			PrivateKey privKey;
 +			try {
 +				KeyFactory kf = KeyFactory.getInstance("DSA");
 +				pubKey = kf.generatePublic(pubSpec);
 +				privKey = kf.generatePrivate(privSpec);
 +			} catch (NoSuchAlgorithmException e) {
 +				IOException ex = new IOException();
 +				ex.initCause(ex);
 +				throw ex;
 +			} catch (InvalidKeySpecException e) {
 +				IOException ex = new IOException();
 +				ex.initCause(ex);
 +				throw ex;
 +			}
 +
 +			return new KeyPair(pubKey, privKey);
  		}
  		if (ps.pemType == PEM_RSA_PRIVATE_KEY)
 @@ -367,8 +407,33 @@ public class PEMDecoder  			BigInteger n = dr.readInt();
  			BigInteger e = dr.readInt();
  			BigInteger d = dr.readInt();
 +			// TODO: is this right? +			BigInteger primeP = dr.readInt();
 +			BigInteger primeQ = dr.readInt();
 +			BigInteger expP = dr.readInt();
 +			BigInteger expQ = dr.readInt();
 +			BigInteger coeff = dr.readInt();
 +
 +			RSAPrivateKeySpec privSpec = new RSAPrivateCrtKeySpec(n, e, d, primeP, primeQ, expP, expQ, coeff);
 +			RSAPublicKeySpec pubSpec = new RSAPublicKeySpec(n, e);
 +
 +			PublicKey pubKey;
 +			PrivateKey privKey;
 +			try {
 +			KeyFactory kf = KeyFactory.getInstance("RSA");
 +			pubKey = kf.generatePublic(pubSpec);
 +			privKey = kf.generatePrivate(privSpec);
 +			} catch (NoSuchAlgorithmException ex) {
 +				IOException ioex = new IOException();
 +				ioex.initCause(ex);
 +				throw ioex;
 +			} catch (InvalidKeySpecException ex) {
 +				IOException ioex = new IOException("invalid keyspec");
 +				ioex.initCause(ex);
 +				throw ioex;
 +			}
 -			return new RSAPrivateKey(d, e, n);
 +			return new KeyPair(pubKey, privKey);
  		}
  		throw new IOException("PEM problem: it is of unknown type");
 diff --git a/src/com/trilead/ssh2/crypto/digest/Digest.java b/src/com/trilead/ssh2/crypto/digest/Digest.java deleted file mode 100644 index 6ed969c..0000000 --- a/src/com/trilead/ssh2/crypto/digest/Digest.java +++ /dev/null @@ -1,25 +0,0 @@ -
 -package com.trilead.ssh2.crypto.digest;
 -
 -/**
 - * Digest.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: Digest.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public interface Digest
 -{
 -	public int getDigestLength();
 -
 -	public void update(byte b);
 -
 -	public void update(byte[] b);
 -
 -	public void update(byte b[], int off, int len);
 -
 -	public void reset();
 -
 -	public void digest(byte[] out);
 -
 -	public void digest(byte[] out, int off);
 -}
 diff --git a/src/com/trilead/ssh2/crypto/digest/HMAC.java b/src/com/trilead/ssh2/crypto/digest/HMAC.java deleted file mode 100644 index 8d52758..0000000 --- a/src/com/trilead/ssh2/crypto/digest/HMAC.java +++ /dev/null @@ -1,95 +0,0 @@ -
 -package com.trilead.ssh2.crypto.digest;
 -
 -/**
 - * HMAC.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: HMAC.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public final class HMAC implements Digest
 -{
 -	Digest md;
 -	byte[] k_xor_ipad;
 -	byte[] k_xor_opad;
 -
 -	byte[] tmp;
 -
 -	int size;
 -
 -	public HMAC(Digest md, byte[] key, int size)
 -	{
 -		this.md = md;
 -		this.size = size;
 -
 -		tmp = new byte[md.getDigestLength()];
 -
 -		final int BLOCKSIZE = 64;
 -
 -		k_xor_ipad = new byte[BLOCKSIZE];
 -		k_xor_opad = new byte[BLOCKSIZE];
 -
 -		if (key.length > BLOCKSIZE)
 -		{
 -			md.reset();
 -			md.update(key);
 -			md.digest(tmp);
 -			key = tmp;
 -		}
 -
 -		System.arraycopy(key, 0, k_xor_ipad, 0, key.length);
 -		System.arraycopy(key, 0, k_xor_opad, 0, key.length);
 -
 -		for (int i = 0; i < BLOCKSIZE; i++)
 -		{
 -			k_xor_ipad[i] ^= 0x36;
 -			k_xor_opad[i] ^= 0x5C;
 -		}
 -		md.update(k_xor_ipad);
 -	}
 -
 -	public final int getDigestLength()
 -	{
 -		return size;
 -	}
 -
 -	public final void update(byte b)
 -	{
 -		md.update(b);
 -	}
 -
 -	public final void update(byte[] b)
 -	{
 -		md.update(b);
 -	}
 -
 -	public final void update(byte[] b, int off, int len)
 -	{
 -		md.update(b, off, len);
 -	}
 -
 -	public final void reset()
 -	{
 -		md.reset();
 -		md.update(k_xor_ipad);
 -	}
 -
 -	public final void digest(byte[] out)
 -	{
 -		digest(out, 0);
 -	}
 -
 -	public final void digest(byte[] out, int off)
 -	{
 -		md.digest(tmp);
 -
 -		md.update(k_xor_opad);
 -		md.update(tmp);
 -
 -		md.digest(tmp);
 -
 -		System.arraycopy(tmp, 0, out, off, size);
 -
 -		md.update(k_xor_ipad);
 -	}
 -}
 diff --git a/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java b/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java index df84952..30ffe0d 100644 --- a/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java +++ b/src/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java @@ -2,6 +2,9 @@  package com.trilead.ssh2.crypto.digest;
  import java.math.BigInteger;
 +import java.security.DigestException;
 +import java.security.MessageDigest;
 +import java.security.NoSuchAlgorithmException;
  /**
   * HashForSSH2Types.
 @@ -11,25 +14,24 @@ import java.math.BigInteger;   */
  public class HashForSSH2Types
  {
 -	Digest md;
 +	MessageDigest md;
 -	public HashForSSH2Types(Digest md)
 +	public HashForSSH2Types(MessageDigest md)
  	{
  		this.md = md;
  	}
  	public HashForSSH2Types(String type)
  	{
 -		if (type.equals("SHA1"))
 -		{
 -			md = new SHA1();
 +		try {
 +			if ("SHA1".equals(type) || "MD5".equals(type)) {
 +				md = MessageDigest.getInstance(type);
 +			} else {
 +				throw new IllegalArgumentException("Unknown algorithm " + type);
 +			}
 +		} catch (NoSuchAlgorithmException e) {
 +			throw new RuntimeException("Unsupported algorithm " + type);
  		}
 -		else if (type.equals("MD5"))
 -		{
 -			md = new MD5();
 -		}
 -		else
 -			throw new IllegalArgumentException("Unknown algorithm " + type);
  	}
  	public void updateByte(byte b)
 @@ -88,6 +90,11 @@ public class HashForSSH2Types  	public void getDigest(byte[] out, int off)
  	{
 -		md.digest(out, off);
 +		try {
 +			md.digest(out, off, out.length - off);
 +		} catch (DigestException e) {
 +			// TODO is this right?! +			throw new RuntimeException("Unable to digest", e);
 +		}
  	}
  }
 diff --git a/src/com/trilead/ssh2/crypto/digest/MAC.java b/src/com/trilead/ssh2/crypto/digest/MAC.java index 0433b63..8138e63 100644 --- a/src/com/trilead/ssh2/crypto/digest/MAC.java +++ b/src/com/trilead/ssh2/crypto/digest/MAC.java @@ -1,6 +1,13 @@  package com.trilead.ssh2.crypto.digest;
 +import java.security.InvalidKeyException;
 +import java.security.NoSuchAlgorithmException;
 +
 +import javax.crypto.Mac;
 +import javax.crypto.ShortBufferException;
 +import javax.crypto.spec.SecretKeySpec;
 +
  /**
   * MAC.
   * 
 @@ -9,14 +16,19 @@ package com.trilead.ssh2.crypto.digest;   */
  public final class MAC
  {
 -	Digest mac;
 -	int size;
 +	Mac mac;
 +	int outSize;
 +	int macSize;
 +	byte[] buffer;
 +
 +	/* Higher Priority First */
 +	private static final String[] MAC_LIST = {
 +		"hmac-sha1-96", "hmac-sha1", "hmac-md5-96", "hmac-md5"
 +	};
  	public final static String[] getMacList()
  	{
 -		/* Higher Priority First */
 -
 -		return new String[] { "hmac-sha1-96", "hmac-sha1", "hmac-md5-96", "hmac-md5" };
 +		return MAC_LIST;
  	}
  	public final static void checkMacList(String[] macs)
 @@ -40,26 +52,35 @@ public final class MAC  	public MAC(String type, byte[] key)
  	{
 -		if (type.equals("hmac-sha1"))
 -		{
 -			mac = new HMAC(new SHA1(), key, 20);
 +		try {
 +			if ("hmac-sha1".equals(type) || "hmac-sha1-96".equals(type))
 +			{
 +				mac = Mac.getInstance("HmacSHA1");
 +			}
 +			else if ("hmac-md5".equals(type) || "hmac-md5-96".equals(type))
 +			{
 +				mac = Mac.getInstance("HmacMD5");
 +			}
 +			else
 +				throw new IllegalArgumentException("Unkown algorithm " + type);
 +		} catch (NoSuchAlgorithmException e) {
 +			throw new IllegalArgumentException("Unknown algorithm " + type, e);
  		}
 -		else if (type.equals("hmac-sha1-96"))
 -		{
 -			mac = new HMAC(new SHA1(), key, 12);
 -		}
 -		else if (type.equals("hmac-md5"))
 -		{
 -			mac = new HMAC(new MD5(), key, 16);
 -		}
 -		else if (type.equals("hmac-md5-96"))
 -		{
 -			mac = new HMAC(new MD5(), key, 12);
 +
 +		macSize = mac.getMacLength();
 +		if (type.endsWith("-96")) {
 +			outSize = 12;
 +			buffer = new byte[macSize];
 +		} else {
 +			outSize = macSize;
 +			buffer = null;
  		}
 -		else
 -			throw new IllegalArgumentException("Unkown algorithm " + type);
 -		size = mac.getDigestLength();
 +		try {
 +			mac.init(new SecretKeySpec(key, type));
 +		} catch (InvalidKeyException e) {
 +			throw new IllegalArgumentException(e);
 +		}
  	}
  	public final void initMac(int seq)
 @@ -78,11 +99,20 @@ public final class MAC  	public final void getMac(byte[] out, int off)
  	{
 -		mac.digest(out, off);
 +		try {
 +			if (buffer != null) {
 +				mac.doFinal(buffer, 0);
 +				System.arraycopy(buffer, 0, out, off, out.length - off);
 +			} else {
 +				mac.doFinal(out, off);
 +			}
 +		} catch (ShortBufferException e) {
 +			throw new IllegalStateException(e);
 +		}
  	}
  	public final int size()
  	{
 -		return size;
 +		return outSize;
  	}
  }
 diff --git a/src/com/trilead/ssh2/crypto/digest/MD5.java b/src/com/trilead/ssh2/crypto/digest/MD5.java deleted file mode 100644 index 567f926..0000000 --- a/src/com/trilead/ssh2/crypto/digest/MD5.java +++ /dev/null @@ -1,268 +0,0 @@ -
 -package com.trilead.ssh2.crypto.digest;
 -
 -/**
 - * MD5. Based on the example code in RFC 1321. Optimized (...a little).
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: MD5.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -
 -/*
 - * The following disclaimer has been copied from RFC 1321:
 - * 
 - * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights
 - * reserved.
 - * 
 - * License to copy and use this software is granted provided that it is
 - * identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in
 - * all material mentioning or referencing this software or this function.
 - * 
 - * License is also granted to make and use derivative works provided that such
 - * works are identified as "derived from the RSA Data Security, Inc. MD5
 - * Message-Digest Algorithm" in all material mentioning or referencing the
 - * derived work.
 - * 
 - * RSA Data Security, Inc. makes no representations concerning either the
 - * merchantability of this software or the suitability of this software for any
 - * particular purpose. It is provided "as is" without express or implied
 - * warranty of any kind.
 - * 
 - * These notices must be retained in any copies of any part of this
 - * documentation and/or software.
 - * 
 - */
 -
 -public final class MD5 implements Digest
 -{
 -	private int state0, state1, state2, state3;
 -	private long count;
 -	private final byte[] block = new byte[64];
 -	private final int x[] = new int[16];
 -
 -	private static final byte[] padding = new byte[] { (byte) 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 -			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 -			0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 -
 -	public MD5()
 -	{
 -		reset();
 -	}
 -
 -	private static final int FF(int a, int b, int c, int d, int x, int s, int ac)
 -	{
 -		a += ((b & c) | ((~b) & d)) + x + ac;
 -		return ((a << s) | (a >>> (32 - s))) + b;
 -	}
 -
 -	private static final int GG(int a, int b, int c, int d, int x, int s, int ac)
 -	{
 -		a += ((b & d) | (c & (~d))) + x + ac;
 -		return ((a << s) | (a >>> (32 - s))) + b;
 -	}
 -
 -	private static final int HH(int a, int b, int c, int d, int x, int s, int ac)
 -	{
 -		a += (b ^ c ^ d) + x + ac;
 -		return ((a << s) | (a >>> (32 - s))) + b;
 -	}
 -
 -	private static final int II(int a, int b, int c, int d, int x, int s, int ac)
 -	{
 -		a += (c ^ (b | (~d))) + x + ac;
 -		return ((a << s) | (a >>> (32 - s))) + b;
 -	}
 -
 -	private static final void encode(byte[] dst, int dstoff, int word)
 -	{
 -		dst[dstoff] = (byte) (word);
 -		dst[dstoff + 1] = (byte) (word >> 8);
 -		dst[dstoff + 2] = (byte) (word >> 16);
 -		dst[dstoff + 3] = (byte) (word >> 24);
 -	}
 -
 -	private final void transform(byte[] src, int pos)
 -	{
 -		int a = state0;
 -		int b = state1;
 -		int c = state2;
 -		int d = state3;
 -
 -		for (int i = 0; i < 16; i++, pos += 4)
 -		{
 -			x[i] = (src[pos] & 0xff) | ((src[pos + 1] & 0xff) << 8) | ((src[pos + 2] & 0xff) << 16)
 -					| ((src[pos + 3] & 0xff) << 24);
 -		}
 -
 -		/* Round 1 */
 -
 -		a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */
 -		d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */
 -		c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */
 -		b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */
 -		a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */
 -		d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */
 -		c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */
 -		b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */
 -		a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */
 -		d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */
 -		c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
 -		b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
 -		a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
 -		d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
 -		c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
 -		b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
 -
 -		/* Round 2 */
 -		a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */
 -		d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */
 -		c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
 -		b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */
 -		a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */
 -		d = GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
 -		c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
 -		b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */
 -		a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */
 -		d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
 -		c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */
 -		b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */
 -		a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
 -		d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */
 -		c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */
 -		b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
 -
 -		/* Round 3 */
 -		a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */
 -		d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */
 -		c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
 -		b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
 -		a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */
 -		d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */
 -		c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */
 -		b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
 -		a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
 -		d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */
 -		c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */
 -		b = HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */
 -		a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */
 -		d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
 -		c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
 -		b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */
 -
 -		/* Round 4 */
 -		a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */
 -		d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */
 -		c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
 -		b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */
 -		a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
 -		d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */
 -		c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
 -		b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */
 -		a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */
 -		d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
 -		c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */
 -		b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
 -		a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */
 -		d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
 -		c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */
 -		b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */
 -
 -		state0 += a;
 -		state1 += b;
 -		state2 += c;
 -		state3 += d;
 -	}
 -
 -	public final void reset()
 -	{
 -		count = 0;
 -
 -		state0 = 0x67452301;
 -		state1 = 0xefcdab89;
 -		state2 = 0x98badcfe;
 -		state3 = 0x10325476;
 -
 -		/* Clear traces in memory... */
 -
 -		for (int i = 0; i < 16; i++)
 -			x[i] = 0;
 -	}
 -
 -	public final void update(byte b)
 -	{
 -		final int space = 64 - ((int) (count & 0x3f));
 -
 -		count++;
 -
 -		block[64 - space] = b;
 -
 -		if (space == 1)
 -			transform(block, 0);
 -	}
 -
 -	public final void update(byte[] buff, int pos, int len)
 -	{
 -		int space = 64 - ((int) (count & 0x3f));
 -
 -		count += len;
 -
 -		while (len > 0)
 -		{
 -			if (len < space)
 -			{
 -				System.arraycopy(buff, pos, block, 64 - space, len);
 -				break;
 -			}
 -
 -			if (space == 64)
 -			{
 -				transform(buff, pos);
 -			}
 -			else
 -			{
 -				System.arraycopy(buff, pos, block, 64 - space, space);
 -				transform(block, 0);
 -			}
 -
 -			pos += space;
 -			len -= space;
 -			space = 64;
 -		}
 -	}
 -
 -	public final void update(byte[] b)
 -	{
 -		update(b, 0, b.length);
 -	}
 -
 -	public final void digest(byte[] dst, int pos)
 -	{
 -		byte[] bits = new byte[8];
 -
 -		encode(bits, 0, (int) (count << 3));
 -		encode(bits, 4, (int) (count >> 29));
 -
 -		int idx = (int) count & 0x3f;
 -		int padLen = (idx < 56) ? (56 - idx) : (120 - idx);
 -
 -		update(padding, 0, padLen);
 -		update(bits, 0, 8);
 -
 -		encode(dst, pos, state0);
 -		encode(dst, pos + 4, state1);
 -		encode(dst, pos + 8, state2);
 -		encode(dst, pos + 12, state3);
 -
 -		reset();
 -	}
 -
 -	public final void digest(byte[] dst)
 -	{
 -		digest(dst, 0);
 -	}
 -
 -	public final int getDigestLength()
 -	{
 -		return 16;
 -	}
 -}
 diff --git a/src/com/trilead/ssh2/crypto/digest/SHA1.java b/src/com/trilead/ssh2/crypto/digest/SHA1.java deleted file mode 100644 index bba4cc6..0000000 --- a/src/com/trilead/ssh2/crypto/digest/SHA1.java +++ /dev/null @@ -1,664 +0,0 @@ -
 -package com.trilead.ssh2.crypto.digest;
 -
 -/**
 - * SHA-1 implementation based on FIPS PUB 180-1.
 - * Highly optimized.
 - * <p>
 - * (http://www.itl.nist.gov/fipspubs/fip180-1.htm)
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: SHA1.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public final class SHA1 implements Digest
 -{
 -	private int H0, H1, H2, H3, H4;
 -
 -	private final int[] w = new int[80];
 -	private int currentPos;
 -	private long currentLen;
 -
 -	public SHA1()
 -	{
 -		reset();
 -	}
 -
 -	public final int getDigestLength()
 -	{
 -		return 20;
 -	}
 -
 -	public final void reset()
 -	{
 -		H0 = 0x67452301;
 -		H1 = 0xEFCDAB89;
 -		H2 = 0x98BADCFE;
 -		H3 = 0x10325476;
 -		H4 = 0xC3D2E1F0;
 -
 -		currentPos = 0;
 -		currentLen = 0;
 -
 -		/* In case of complete paranoia, we should also wipe out the
 -		 * information contained in the w[] array */
 -	}
 -
 -	public final void update(byte b[])
 -	{
 -		update(b, 0, b.length);
 -	}
 -
 -	public final void update(byte b[], int off, int len)
 -	{
 -		if (len >= 4)
 -		{
 -			int idx = currentPos >> 2;
 -
 -			switch (currentPos & 3)
 -			{
 -			case 0:
 -				w[idx] = (((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8) | (b[off++] & 0xff));
 -				len -= 4;
 -				currentPos += 4;
 -				currentLen += 32;
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -				break;
 -			case 1:
 -				w[idx] = (w[idx] << 24) | (((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8) | (b[off++] & 0xff));
 -				len -= 3;
 -				currentPos += 3;
 -				currentLen += 24;
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -				break;
 -			case 2:
 -				w[idx] = (w[idx] << 16) | (((b[off++] & 0xff) << 8) | (b[off++] & 0xff));
 -				len -= 2;
 -				currentPos += 2;
 -				currentLen += 16;
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -				break;
 -			case 3:
 -				w[idx] = (w[idx] << 8) | (b[off++] & 0xff);
 -				len--;
 -				currentPos++;
 -				currentLen += 8;
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -				break;
 -			}
 -
 -			/* Now currentPos is a multiple of 4 - this is the place to be...*/
 -
 -			while (len >= 8)
 -			{
 -				w[currentPos >> 2] = ((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8)
 -						| (b[off++] & 0xff);
 -				currentPos += 4;
 -
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -
 -				w[currentPos >> 2] = ((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8)
 -						| (b[off++] & 0xff);
 -
 -				currentPos += 4;
 -
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -
 -				currentLen += 64;
 -				len -= 8;
 -			}
 -
 -			while (len < 0) //(len >= 4)
 -			{
 -				w[currentPos >> 2] = ((b[off++] & 0xff) << 24) | ((b[off++] & 0xff) << 16) | ((b[off++] & 0xff) << 8)
 -						| (b[off++] & 0xff);
 -				len -= 4;
 -				currentPos += 4;
 -				currentLen += 32;
 -				if (currentPos == 64)
 -				{
 -					perform();
 -					currentPos = 0;
 -				}
 -			}
 -		}
 -
 -		/* Remaining bytes (1-3) */
 -
 -		while (len > 0)
 -		{
 -			/* Here is room for further improvements */
 -			int idx = currentPos >> 2;
 -			w[idx] = (w[idx] << 8) | (b[off++] & 0xff);
 -
 -			currentLen += 8;
 -			currentPos++;
 -
 -			if (currentPos == 64)
 -			{
 -				perform();
 -				currentPos = 0;
 -			}
 -			len--;
 -		}
 -	}
 -
 -	public final void update(byte b)
 -	{
 -		int idx = currentPos >> 2;
 -		w[idx] = (w[idx] << 8) | (b & 0xff);
 -
 -		currentLen += 8;
 -		currentPos++;
 -
 -		if (currentPos == 64)
 -		{
 -			perform();
 -			currentPos = 0;
 -		}
 -	}
 -
 -	private final void putInt(byte[] b, int pos, int val)
 -	{
 -		b[pos] = (byte) (val >> 24);
 -		b[pos + 1] = (byte) (val >> 16);
 -		b[pos + 2] = (byte) (val >> 8);
 -		b[pos + 3] = (byte) val;
 -	}
 -
 -	public final void digest(byte[] out)
 -	{
 -		digest(out, 0);
 -	}
 -
 -	public final void digest(byte[] out, int off)
 -	{
 -		/* Pad with a '1' and 7-31 zero bits... */
 -
 -		int idx = currentPos >> 2;
 -		w[idx] = ((w[idx] << 8) | (0x80)) << ((3 - (currentPos & 3)) << 3);
 -
 -		currentPos = (currentPos & ~3) + 4;
 -
 -		if (currentPos == 64)
 -		{
 -			currentPos = 0;
 -			perform();
 -		}
 -		else if (currentPos == 60)
 -		{
 -			currentPos = 0;
 -			w[15] = 0;
 -			perform();
 -		}
 -
 -		/* Now currentPos is a multiple of 4 and we can do the remaining
 -		 * padding much more efficiently, furthermore we are sure
 -		 * that currentPos <= 56.
 -		 */
 -
 -		for (int i = currentPos >> 2; i < 14; i++)
 -			w[i] = 0;
 -
 -		w[14] = (int) (currentLen >> 32);
 -		w[15] = (int) currentLen;
 -
 -		perform();
 -
 -		putInt(out, off, H0);
 -		putInt(out, off + 4, H1);
 -		putInt(out, off + 8, H2);
 -		putInt(out, off + 12, H3);
 -		putInt(out, off + 16, H4);
 -
 -		reset();
 -	}
 -
 -	private final void perform()
 -	{
 -		for (int t = 16; t < 80; t++)
 -		{
 -			int x = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
 -			w[t] = ((x << 1) | (x >>> 31));
 -		}
 -
 -		int A = H0;
 -		int B = H1;
 -		int C = H2;
 -		int D = H3;
 -		int E = H4;
 -
 -		/* Here we use variable substitution and loop unrolling
 -		 * 
 -		 * === Original step:
 -		 * 
 -		 * T = s5(A) + f(B,C,D) + E + w[0] + K;
 -		 * E = D; D = C; C = s30(B); B = A; A = T;
 -		 * 
 -		 * === Rewritten step:
 -		 * 
 -		 * T = s5(A + f(B,C,D) + E + w[0] + K;
 -		 * B = s30(B);
 -		 * E = D; D = C; C = B; B = A; A = T;
 -		 * 
 -		 * === Let's rewrite things, introducing new variables:
 -		 * 
 -		 * E0 = E; D0 = D; C0 = C; B0 = B; A0 = A;
 -		 * 
 -		 * T = s5(A0) + f(B0,C0,D0) + E0 + w[0] + K;
 -		 * B0 = s30(B0);
 -		 * E1 = D0; D1 = C0; C1 = B0; B1 = A0; A1 = T;
 -		 * 
 -		 * T = s5(A1) + f(B1,C1,D1) + E1 + w[1] + K;
 -		 * B1 = s30(B1);
 -		 * E2 = D1; D2 = C1; C2 = B1; B2 = A1; A2 = T;
 -		 * 
 -		 * E = E2; D = E2; C = C2; B = B2; A = A2;
 -		 * 
 -		 * === No need for 'T', we can write into 'Ex' instead since
 -		 * after the calculation of 'T' nobody is interested
 -		 * in 'Ex' anymore. 
 -		 * 
 -		 * E0 = E; D0 = D; C0 = C; B0 = B; A0 = A;
 -		 * 
 -		 * E0 = E0 + s5(A0) + f(B0,C0,D0) + w[0] + K;
 -		 * B0 = s30(B0);
 -		 * E1 = D0; D1 = C0; C1 = B0; B1 = A0; A1 = E0;
 -		 * 
 -		 * E1 = E1 + s5(A1) + f(B1,C1,D1) + w[1] + K;
 -		 * B1 = s30(B1);
 -		 * E2 = D1; D2 = C1; C2 = B1; B2 = A1; A2 = E1;
 -		 * 
 -		 * E = Ex; D = Ex; C = Cx; B = Bx; A = Ax;
 -		 * 
 -		 * === Further optimization: get rid of the swap operations
 -		 * Idea: instead of swapping the variables, swap the names of
 -		 * the used variables in the next step:
 -		 * 
 -		 * E0 = E; D0 = d; C0 = C; B0 = B; A0 = A;
 -		 * 
 -		 * E0 = E0 + s5(A0) + f(B0,C0,D0) + w[0] + K;
 -		 * B0 = s30(B0);
 -		 * // E1 = D0; D1 = C0; C1 = B0; B1 = A0; A1 = E0;
 -		 * 
 -		 * D0 = D0 + s5(E0) + f(A0,B0,C0) + w[1] + K;
 -		 * A0 = s30(A0);
 -		 * E2 = C0; D2 = B0; C2 = A0; B2 = E0; A2 = D0;
 -		 * 
 -		 * E = E2; D = D2; C = C2; B = B2; A = A2;
 -		 * 
 -		 * === OK, let's do this several times, also, directly
 -		 * use A (instead of A0) and B,C,D,E.
 -		 * 
 -		 * E = E + s5(A) + f(B,C,D) + w[0] + K;
 -		 * B = s30(B);
 -		 * // E1 = D; D1 = C; C1 = B; B1 = A; A1 = E;
 -		 * 
 -		 * D = D + s5(E) + f(A,B,C) + w[1] + K;
 -		 * A = s30(A);
 -		 * // E2 = C; D2 = B; C2 = A; B2 = E; A2 = D;
 -		 * 
 -		 * C = C + s5(D) + f(E,A,B) + w[2] + K;
 -		 * E = s30(E);
 -		 * // E3 = B; D3 = A; C3 = E; B3 = D; A3 = C;
 -		 * 
 -		 * B = B + s5(C) + f(D,E,A) + w[3] + K;
 -		 * D = s30(D);
 -		 * // E4 = A; D4 = E; C4 = D; B4 = C; A4 = B;
 -		 * 
 -		 * A = A + s5(B) + f(C,D,E) + w[4] + K;
 -		 * C = s30(C);
 -		 * // E5 = E; D5 = D; C5 = C; B5 = B; A5 = A;
 -		 * 
 -		 * //E = E5; D = D5; C = C5; B = B5; A = A5;
 -		 * 
 -		 * === Very nice, after 5 steps each variable
 -		 * has the same contents as after 5 steps with
 -		 * the original algorithm!
 -		 * 
 -		 * We therefore can easily unroll each interval,
 -		 * as the number of steps in each interval is a
 -		 * multiple of 5 (20 steps per interval).
 -		 */
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | ((~B) & D)) + w[0] + 0x5A827999;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | ((~A) & C)) + w[1] + 0x5A827999;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | ((~E) & B)) + w[2] + 0x5A827999;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | ((~D) & A)) + w[3] + 0x5A827999;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | ((~C) & E)) + w[4] + 0x5A827999;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | ((~B) & D)) + w[5] + 0x5A827999;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | ((~A) & C)) + w[6] + 0x5A827999;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | ((~E) & B)) + w[7] + 0x5A827999;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | ((~D) & A)) + w[8] + 0x5A827999;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | ((~C) & E)) + w[9] + 0x5A827999;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | ((~B) & D)) + w[10] + 0x5A827999;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | ((~A) & C)) + w[11] + 0x5A827999;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | ((~E) & B)) + w[12] + 0x5A827999;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | ((~D) & A)) + w[13] + 0x5A827999;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | ((~C) & E)) + w[14] + 0x5A827999;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | ((~B) & D)) + w[15] + 0x5A827999;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | ((~A) & C)) + w[16] + 0x5A827999;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | ((~E) & B)) + w[17] + 0x5A827999;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | ((~D) & A)) + w[18] + 0x5A827999;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | ((~C) & E)) + w[19] + 0x5A827999;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[20] + 0x6ED9EBA1;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[21] + 0x6ED9EBA1;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[22] + 0x6ED9EBA1;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[23] + 0x6ED9EBA1;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[24] + 0x6ED9EBA1;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[25] + 0x6ED9EBA1;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[26] + 0x6ED9EBA1;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[27] + 0x6ED9EBA1;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[28] + 0x6ED9EBA1;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[29] + 0x6ED9EBA1;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[30] + 0x6ED9EBA1;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[31] + 0x6ED9EBA1;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[32] + 0x6ED9EBA1;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[33] + 0x6ED9EBA1;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[34] + 0x6ED9EBA1;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[35] + 0x6ED9EBA1;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[36] + 0x6ED9EBA1;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[37] + 0x6ED9EBA1;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[38] + 0x6ED9EBA1;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[39] + 0x6ED9EBA1;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | (B & D) | (C & D)) + w[40] + 0x8F1BBCDC;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | (A & C) | (B & C)) + w[41] + 0x8F1BBCDC;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | (E & B) | (A & B)) + w[42] + 0x8F1BBCDC;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | (D & A) | (E & A)) + w[43] + 0x8F1BBCDC;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | (C & E) | (D & E)) + w[44] + 0x8F1BBCDC;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | (B & D) | (C & D)) + w[45] + 0x8F1BBCDC;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | (A & C) | (B & C)) + w[46] + 0x8F1BBCDC;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | (E & B) | (A & B)) + w[47] + 0x8F1BBCDC;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | (D & A) | (E & A)) + w[48] + 0x8F1BBCDC;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | (C & E) | (D & E)) + w[49] + 0x8F1BBCDC;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + ((B & C) | (B & D) | (C & D)) + w[50] + 0x8F1BBCDC;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | (A & C) | (B & C)) + w[51] + 0x8F1BBCDC;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | (E & B) | (A & B)) + w[52] + 0x8F1BBCDC;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | (D & A) | (E & A)) + w[53] + 0x8F1BBCDC;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | (C & E) | (D & E)) + w[54] + 0x8F1BBCDC;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E = E + ((A << 5) | (A >>> 27)) + ((B & C) | (B & D) | (C & D)) + w[55] + 0x8F1BBCDC;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + ((A & B) | (A & C) | (B & C)) + w[56] + 0x8F1BBCDC;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + ((E & A) | (E & B) | (A & B)) + w[57] + 0x8F1BBCDC;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + ((D & E) | (D & A) | (E & A)) + w[58] + 0x8F1BBCDC;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + ((C & D) | (C & E) | (D & E)) + w[59] + 0x8F1BBCDC;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[60] + 0xCA62C1D6;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[61] + 0xCA62C1D6;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[62] + 0xCA62C1D6;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[63] + 0xCA62C1D6;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[64] + 0xCA62C1D6;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[65] + 0xCA62C1D6;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[66] + 0xCA62C1D6;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[67] + 0xCA62C1D6;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[68] + 0xCA62C1D6;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[69] + 0xCA62C1D6;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[70] + 0xCA62C1D6;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[71] + 0xCA62C1D6;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[72] + 0xCA62C1D6;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[73] + 0xCA62C1D6;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[74] + 0xCA62C1D6;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		E += ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + w[75] + 0xCA62C1D6;
 -		B = ((B << 30) | (B >>> 2));
 -
 -		D += ((E << 5) | (E >>> 27)) + (A ^ B ^ C) + w[76] + 0xCA62C1D6;
 -		A = ((A << 30) | (A >>> 2));
 -
 -		C += ((D << 5) | (D >>> 27)) + (E ^ A ^ B) + w[77] + 0xCA62C1D6;
 -		E = ((E << 30) | (E >>> 2));
 -
 -		B += ((C << 5) | (C >>> 27)) + (D ^ E ^ A) + w[78] + 0xCA62C1D6;
 -		D = ((D << 30) | (D >>> 2));
 -
 -		A += ((B << 5) | (B >>> 27)) + (C ^ D ^ E) + w[79] + 0xCA62C1D6;
 -		C = ((C << 30) | (C >>> 2));
 -
 -		H0 += A;
 -		H1 += B;
 -		H2 += C;
 -		H3 += D;
 -		H4 += E;
 -
 -		// debug(80, H0, H1, H2, H3, H4);
 -	}
 -
 -	private static final String toHexString(byte[] b)
 -	{
 -		final String hexChar = "0123456789ABCDEF";
 -
 -		StringBuffer sb = new StringBuffer();
 -		for (int i = 0; i < b.length; i++)
 -		{
 -			sb.append(hexChar.charAt((b[i] >> 4) & 0x0f));
 -			sb.append(hexChar.charAt(b[i] & 0x0f));
 -		}
 -		return sb.toString();
 -	}
 -
 -	public static void main(String[] args)
 -	{
 -		SHA1 sha = new SHA1();
 -
 -		byte[] dig1 = new byte[20];
 -		byte[] dig2 = new byte[20];
 -		byte[] dig3 = new byte[20];
 -
 -		/*
 -		 * We do not specify a charset name for getBytes(), since we assume that
 -		 * the JVM's default encoder maps the _used_ ASCII characters exactly as
 -		 * getBytes("US-ASCII") would do. (Ah, yes, too lazy to catch the
 -		 * exception that can be thrown by getBytes("US-ASCII")). Note: This has
 -		 * no effect on the SHA-1 implementation, this is just for the following
 -		 * test code.
 -		 */
 -
 -		sha.update("abc".getBytes());
 -		sha.digest(dig1);
 -
 -		sha.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".getBytes());
 -		sha.digest(dig2);
 -
 -		for (int i = 0; i < 1000000; i++)
 -			sha.update((byte) 'a');
 -		sha.digest(dig3);
 -
 -		String dig1_res = toHexString(dig1);
 -		String dig2_res = toHexString(dig2);
 -		String dig3_res = toHexString(dig3);
 -
 -		String dig1_ref = "A9993E364706816ABA3E25717850C26C9CD0D89D";
 -		String dig2_ref = "84983E441C3BD26EBAAE4AA1F95129E5E54670F1";
 -		String dig3_ref = "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F";
 -
 -		if (dig1_res.equals(dig1_ref))
 -			System.out.println("SHA-1 Test 1 OK.");
 -		else
 -			System.out.println("SHA-1 Test 1 FAILED.");
 -
 -		if (dig2_res.equals(dig2_ref))
 -			System.out.println("SHA-1 Test 2 OK.");
 -		else
 -			System.out.println("SHA-1 Test 2 FAILED.");
 -
 -		if (dig3_res.equals(dig3_ref))
 -			System.out.println("SHA-1 Test 3 OK.");
 -		else
 -			System.out.println("SHA-1 Test 3 FAILED.");
 -
 -		if (dig3_res.equals(dig3_ref))
 -			System.out.println("SHA-1 Test 3 OK.");
 -		else
 -			System.out.println("SHA-1 Test 3 FAILED.");
 -	}
 -}
 diff --git a/src/com/trilead/ssh2/signature/DSAPrivateKey.java b/src/com/trilead/ssh2/signature/DSAPrivateKey.java deleted file mode 100644 index d2a63ae..0000000 --- a/src/com/trilead/ssh2/signature/DSAPrivateKey.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.trilead.ssh2.signature;
 -
 -import java.math.BigInteger;
 -
 -/**
 - * DSAPrivateKey.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: DSAPrivateKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public class DSAPrivateKey
 -{
 -	private BigInteger p;
 -	private BigInteger q;
 -	private BigInteger g;
 -	private BigInteger x;
 -	private BigInteger y;
 -
 -	public DSAPrivateKey(BigInteger p, BigInteger q, BigInteger g,
 -			BigInteger y, BigInteger x)
 -	{
 -		this.p = p;
 -		this.q = q;
 -		this.g = g;
 -		this.y = y;
 -		this.x = x;
 -	}
 -
 -	public BigInteger getP()
 -	{
 -		return p;
 -	}
 -
 -	public BigInteger getQ()
 -	{
 -		return q;
 -	}
 -	
 -	public BigInteger getG()
 -	{
 -		return g;
 -	}
 -
 -	public BigInteger getY()
 -	{
 -		return y;
 -	}
 -	
 -	public BigInteger getX()
 -	{
 -		return x;
 -	}
 -	
 -	public DSAPublicKey getPublicKey()
 -	{
 -		return new DSAPublicKey(p, q, g, y);
 -	}
 -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/signature/DSAPublicKey.java b/src/com/trilead/ssh2/signature/DSAPublicKey.java deleted file mode 100644 index f8351ff..0000000 --- a/src/com/trilead/ssh2/signature/DSAPublicKey.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.trilead.ssh2.signature;
 -
 -import java.math.BigInteger;
 -
 -/**
 - * DSAPublicKey.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: DSAPublicKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public class DSAPublicKey
 -{
 -	private BigInteger p;
 -	private BigInteger q;
 -	private BigInteger g;
 -	private BigInteger y;
 -
 -	public DSAPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y)
 -	{
 -		this.p = p;
 -		this.q = q;
 -		this.g = g;
 -		this.y = y;
 -	}
 -
 -	public BigInteger getP()
 -	{
 -		return p;
 -	}
 -
 -	public BigInteger getQ()
 -	{
 -		return q;
 -	}
 -
 -	public BigInteger getG()
 -	{
 -		return g;
 -	}
 -
 -	public BigInteger getY()
 -	{
 -		return y;
 -	}
 -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/signature/DSASHA1Verify.java b/src/com/trilead/ssh2/signature/DSASHA1Verify.java index c838ebd..357d66e 100644 --- a/src/com/trilead/ssh2/signature/DSASHA1Verify.java +++ b/src/com/trilead/ssh2/signature/DSASHA1Verify.java @@ -3,9 +3,19 @@ package com.trilead.ssh2.signature;  import java.io.IOException;
  import java.math.BigInteger;
 +import java.security.InvalidKeyException;
 +import java.security.KeyFactory;
 +import java.security.NoSuchAlgorithmException;
  import java.security.SecureRandom;
 +import java.security.Signature;
 +import java.security.SignatureException;
 +import java.security.interfaces.DSAParams;
 +import java.security.interfaces.DSAPrivateKey;
 +import java.security.interfaces.DSAPublicKey;
 +import java.security.spec.DSAPublicKeySpec;
 +import java.security.spec.InvalidKeySpecException;
 +import java.security.spec.KeySpec;
 -import com.trilead.ssh2.crypto.digest.SHA1;
  import com.trilead.ssh2.log.Logger;
  import com.trilead.ssh2.packets.TypesReader;
  import com.trilead.ssh2.packets.TypesWriter;
 @@ -38,7 +48,20 @@ public class DSASHA1Verify  		if (tr.remain() != 0)
  			throw new IOException("Padding in DSA public key!");
 -		return new DSAPublicKey(p, q, g, y);
 +		try {
 +			KeyFactory kf = KeyFactory.getInstance("DSA");
 +
 +			KeySpec ks = new DSAPublicKeySpec(y, p, q, g);
 +			return (DSAPublicKey) kf.generatePublic(ks);
 +		} catch (NoSuchAlgorithmException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (InvalidKeySpecException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		}
  	}
  	public static byte[] encodeSSHDSAPublicKey(DSAPublicKey pk) throws IOException
 @@ -46,25 +69,47 @@ public class DSASHA1Verify  		TypesWriter tw = new TypesWriter();
  		tw.writeString("ssh-dss");
 -		tw.writeMPInt(pk.getP());
 -		tw.writeMPInt(pk.getQ());
 -		tw.writeMPInt(pk.getG());
 +
 +		DSAParams params = pk.getParams();
 +		tw.writeMPInt(params.getP());
 +		tw.writeMPInt(params.getQ());
 +		tw.writeMPInt(params.getG());
  		tw.writeMPInt(pk.getY());
  		return tw.getBytes();
  	}
 -	public static byte[] encodeSSHDSASignature(DSASignature ds)
 +	/**
 +	 * Convert from Java's signature ASN.1 encoding to the SSH spec.
 +	 * <p>
 +	 * Java ASN.1 encoding:
 +	 * <pre>
 +	 * SEQUENCE ::= {
 +	 *    r INTEGER,
 +	 *    s INTEGER
 +	 * }
 +	 * </pre>
 +	 */
 +	public static byte[] encodeSSHDSASignature(byte[] ds)
  	{
  		TypesWriter tw = new TypesWriter();
  		tw.writeString("ssh-dss");
 -		byte[] r = ds.getR().toByteArray();
 -		byte[] s = ds.getS().toByteArray();
 +		int len, index;
 -		byte[] a40 = new byte[40];
 +		index = 3;
 +		len = ds[index++] & 0xff;
 +		byte[] r = new byte[len];
 +		System.arraycopy(ds, index, r, 0, r.length);
 +		index = index + len + 1;
 +		len = ds[index++] & 0xff;
 +		byte[] s = new byte[len];
 +		System.arraycopy(ds, index, s, 0, s.length);
 +
 +		byte[] a40 = new byte[40];
 +  		/* Patch (unsigned) r and s into the target array. */
  		int r_copylen = (r.length < 20) ? r.length : 20;
 @@ -78,22 +123,21 @@ public class DSASHA1Verify  		return tw.getBytes();
  	}
 -	public static DSASignature decodeSSHDSASignature(byte[] sig) throws IOException
 +	public static byte[] decodeSSHDSASignature(byte[] sig) throws IOException
  	{
  		byte[] rsArray = null;
  		if (sig.length == 40)
  		{
  			/* OK, another broken SSH server. */
 -			rsArray = sig;	
 +			rsArray = sig;
  		}
  		else
  		{
 -			/* Hopefully a server obeing the standard... */
 +			/* Hopefully a server obeying the standard... */
  			TypesReader tr = new TypesReader(sig);
  			String sig_format = tr.readString();
 -
  			if (sig_format.equals("ssh-dss") == false)
  				throw new IOException("Peer sent wrong signature format");
 @@ -106,105 +150,106 @@ public class DSASHA1Verify  				throw new IOException("Padding in DSA signature!");
  		}
 -		/* Remember, s and r are unsigned ints. */
 -
 -		byte[] tmp = new byte[20];
 -
 -		System.arraycopy(rsArray, 0, tmp, 0, 20);
 -		BigInteger r = new BigInteger(1, tmp);
 -
 -		System.arraycopy(rsArray, 20, tmp, 0, 20);
 -		BigInteger s = new BigInteger(1, tmp);
 -
 -		if (log.isEnabled())
 -		{
 -			log.log(30, "decoded ssh-dss signature: first bytes r(" + ((rsArray[0]) & 0xff) + "), s("
 -					+ ((rsArray[20]) & 0xff) + ")");
 +		int i = 0;
 +		int j = 0;
 +		byte[] tmp;
 +
 +		if (rsArray[0] == 0 && rsArray[1] == 0 && rsArray[2] == 0) {
 +			j = ((rsArray[i++] << 24) & 0xff000000) | ((rsArray[i++] << 16) & 0x00ff0000)
 +					| ((rsArray[i++] << 8) & 0x0000ff00) | ((rsArray[i++]) & 0x000000ff);
 +			i += j;
 +			j = ((rsArray[i++] << 24) & 0xff000000) | ((rsArray[i++] << 16) & 0x00ff0000)
 +					| ((rsArray[i++] << 8) & 0x0000ff00) | ((rsArray[i++]) & 0x000000ff);
 +			tmp = new byte[j];
 +			System.arraycopy(rsArray, i, tmp, 0, j);
 +			rsArray = tmp;
  		}
 -		return new DSASignature(r, s);
 -	}
 -
 -	public static boolean verifySignature(byte[] message, DSASignature ds, DSAPublicKey dpk) throws IOException
 -	{
 -		/* Inspired by Bouncycastle's DSASigner class */
 -
 -		SHA1 md = new SHA1();
 -		md.update(message);
 -		byte[] sha_message = new byte[md.getDigestLength()];
 -		md.digest(sha_message);
 +		/* ASN.1 */
 +		int frst = ((rsArray[0] & 0x80) != 0 ? 1 : 0);
 +		int scnd = ((rsArray[20] & 0x80) != 0 ? 1 : 0);
 -		BigInteger m = new BigInteger(1, sha_message);
 +		/* Calculate output length */
 +		int length = rsArray.length + 6 + frst + scnd;
 +		tmp = new byte[length];
 -		BigInteger r = ds.getR();
 -		BigInteger s = ds.getS();
 +		/* DER-encoding to match Java */
 +		tmp[0] = (byte) 0x30;
 -		BigInteger g = dpk.getG();
 -		BigInteger p = dpk.getP();
 -		BigInteger q = dpk.getQ();
 -		BigInteger y = dpk.getY();
 -
 -		BigInteger zero = BigInteger.ZERO;
 +			if (rsArray.length != 40)
 +				throw new IOException("Peer sent corrupt signature");
 +		/* Calculate length */
 +		tmp[1] = (byte) 0x2c;
 +		tmp[1] += frst;
 +		tmp[1] += scnd;
 -		if (log.isEnabled())
 -		{
 -			log.log(60, "ssh-dss signature: m: " + m.toString(16));
 -			log.log(60, "ssh-dss signature: r: " + r.toString(16));
 -			log.log(60, "ssh-dss signature: s: " + s.toString(16));
 -			log.log(60, "ssh-dss signature: g: " + g.toString(16));
 -			log.log(60, "ssh-dss signature: p: " + p.toString(16));
 -			log.log(60, "ssh-dss signature: q: " + q.toString(16));
 -			log.log(60, "ssh-dss signature: y: " + y.toString(16));
 -		}
 +		/* First item */
 +		tmp[2] = (byte) 0x02;
 -		if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0)
 -		{
 -			log.log(20, "ssh-dss signature: zero.compareTo(r) >= 0 || q.compareTo(r) <= 0");
 -			return false;
 -		}
 +		/* First item length */
 +		tmp[3] = (byte) 0x14;
 +		tmp[3] += frst;
 -		if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0)
 -		{
 -			log.log(20, "ssh-dss signature: zero.compareTo(s) >= 0 || q.compareTo(s) <= 0");
 -			return false;
 -		}
 +		/* Copy in the data for first item */
 +		System.arraycopy(rsArray, 0, tmp, 4 + frst, 20);
 -		BigInteger w = s.modInverse(q);
 +		/* Second item */
 +		tmp[4 + tmp[3]] = (byte) 0x02;
 -		BigInteger u1 = m.multiply(w).mod(q);
 -		BigInteger u2 = r.multiply(w).mod(q);
 +		/* Second item length */
 +		tmp[5 + tmp[3]] = (byte) 0x14;
 +		tmp[5 + tmp[3]] += scnd;
 -		u1 = g.modPow(u1, p);
 -		u2 = y.modPow(u2, p);
 +		/* Copy in the data for the second item */
 +		System.arraycopy(rsArray, 20, tmp, 6 + tmp[3] + scnd, 20);
 -		BigInteger v = u1.multiply(u2).mod(p).mod(q);
 +		/* Swap buffers */
 +		rsArray = tmp;
 -		return v.equals(r);
 +		return rsArray;
  	}
 -	public static DSASignature generateSignature(byte[] message, DSAPrivateKey pk, SecureRandom rnd)
 +	public static boolean verifySignature(byte[] message, byte[] ds, DSAPublicKey dpk) throws IOException
  	{
 -		SHA1 md = new SHA1();
 -		md.update(message);
 -		byte[] sha_message = new byte[md.getDigestLength()];
 -		md.digest(sha_message);
 -
 -		BigInteger m = new BigInteger(1, sha_message);
 -		BigInteger k;
 -		int qBitLength = pk.getQ().bitLength();
 -
 -		do
 -		{
 -			k = new BigInteger(qBitLength, rnd);
 +		try {
 +			Signature s = Signature.getInstance("SHA1withDSA");
 +			s.initVerify(dpk);
 +			s.update(message);
 +			return s.verify(ds);
 +		} catch (NoSuchAlgorithmException e) {
 +			IOException ex = new IOException("No such algorithm");
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (InvalidKeyException e) {
 +			IOException ex = new IOException("No such algorithm");
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (SignatureException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
  		}
 -		while (k.compareTo(pk.getQ()) >= 0);
 -
 -		BigInteger r = pk.getG().modPow(k, pk.getP()).mod(pk.getQ());
 -
 -		k = k.modInverse(pk.getQ()).multiply(m.add((pk).getX().multiply(r)));
 -
 -		BigInteger s = k.mod(pk.getQ());
 +	}
 -		return new DSASignature(r, s);
 +	public static byte[] generateSignature(byte[] message, DSAPrivateKey pk, SecureRandom rnd) throws IOException
 +	{
 +		try {
 +			Signature s = Signature.getInstance("SHA1withDSA");
 +			s.initSign(pk);
 +			s.update(message);
 +			return s.sign();
 +		} catch (NoSuchAlgorithmException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (InvalidKeyException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (SignatureException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		}
  	}
  }
 diff --git a/src/com/trilead/ssh2/signature/DSASignature.java b/src/com/trilead/ssh2/signature/DSASignature.java deleted file mode 100644 index eff84cd..0000000 --- a/src/com/trilead/ssh2/signature/DSASignature.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.trilead.ssh2.signature;
 -
 -import java.math.BigInteger;
 -
 -/**
 - * DSASignature.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: DSASignature.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public class DSASignature
 -{
 -	private BigInteger r;
 -	private BigInteger s;
 -
 -	public DSASignature(BigInteger r, BigInteger s)
 -	{
 -		this.r = r;
 -		this.s = s;
 -	}
 -
 -	public BigInteger getR()
 -	{
 -		return r;
 -	}
 -
 -	public BigInteger getS()
 -	{
 -		return s;
 -	}
 -}
 diff --git a/src/com/trilead/ssh2/signature/RSAPrivateKey.java b/src/com/trilead/ssh2/signature/RSAPrivateKey.java deleted file mode 100644 index 5d5e606..0000000 --- a/src/com/trilead/ssh2/signature/RSAPrivateKey.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.trilead.ssh2.signature;
 -
 -import java.math.BigInteger;
 -
 -/**
 - * RSAPrivateKey.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: RSAPrivateKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public class RSAPrivateKey
 -{
 -	private BigInteger d;
 -	private BigInteger e;
 -	private BigInteger n;
 -
 -	public RSAPrivateKey(BigInteger d, BigInteger e, BigInteger n)
 -	{
 -		this.d = d;
 -		this.e = e;
 -		this.n = n;
 -	}
 -
 -	public BigInteger getD()
 -	{
 -		return d;
 -	}
 -	
 -	public BigInteger getE()
 -	{
 -		return e;
 -	}
 -
 -	public BigInteger getN()
 -	{
 -		return n;
 -	}
 -	
 -	public RSAPublicKey getPublicKey()
 -	{
 -		return new RSAPublicKey(e, n);
 -	}
 -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/signature/RSAPublicKey.java b/src/com/trilead/ssh2/signature/RSAPublicKey.java deleted file mode 100644 index e7e6611..0000000 --- a/src/com/trilead/ssh2/signature/RSAPublicKey.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.trilead.ssh2.signature;
 -
 -import java.math.BigInteger;
 -
 -/**
 - * RSAPublicKey.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: RSAPublicKey.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -public class RSAPublicKey
 -{
 -	BigInteger e;
 -	BigInteger n;
 -
 -	public RSAPublicKey(BigInteger e, BigInteger n)
 -	{
 -		this.e = e;
 -		this.n = n;
 -	}
 -
 -	public BigInteger getE()
 -	{
 -		return e;
 -	}
 -
 -	public BigInteger getN()
 -	{
 -		return n;
 -	}
 -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/signature/RSASHA1Verify.java b/src/com/trilead/ssh2/signature/RSASHA1Verify.java index 8a0f07a..9b5c18e 100644 --- a/src/com/trilead/ssh2/signature/RSASHA1Verify.java +++ b/src/com/trilead/ssh2/signature/RSASHA1Verify.java @@ -3,9 +3,17 @@ package com.trilead.ssh2.signature;  import java.io.IOException;
  import java.math.BigInteger;
 +import java.security.InvalidKeyException;
 +import java.security.KeyFactory;
 +import java.security.NoSuchAlgorithmException;
 +import java.security.Signature;
 +import java.security.SignatureException;
 +import java.security.interfaces.RSAPrivateKey;
 +import java.security.interfaces.RSAPublicKey;
 +import java.security.spec.InvalidKeySpecException;
 +import java.security.spec.KeySpec;
 +import java.security.spec.RSAPublicKeySpec;
 -import com.trilead.ssh2.crypto.SimpleDERReader;
 -import com.trilead.ssh2.crypto.digest.SHA1;
  import com.trilead.ssh2.log.Logger;
  import com.trilead.ssh2.packets.TypesReader;
  import com.trilead.ssh2.packets.TypesWriter;
 @@ -36,7 +44,20 @@ public class RSASHA1Verify  		if (tr.remain() != 0)
  			throw new IOException("Padding in RSA public key!");
 -		return new RSAPublicKey(e, n);
 +		KeySpec keySpec = new RSAPublicKeySpec(n, e);
 +
 +		try {
 +			KeyFactory kf = KeyFactory.getInstance("RSA");
 +			return (RSAPublicKey) kf.generatePublic(keySpec);
 +		} catch (NoSuchAlgorithmException nsae) {
 +			IOException ioe = new IOException("No RSA KeyFactory available");
 +			ioe.initCause(nsae);
 +			throw ioe;
 +		} catch (InvalidKeySpecException ikse) {
 +			IOException ioe = new IOException("No RSA KeyFactory available");
 +			ioe.initCause(ikse);
 +			throw ioe;
 +		}
  	}
  	public static byte[] encodeSSHRSAPublicKey(RSAPublicKey pk) throws IOException
 @@ -44,13 +65,13 @@ public class RSASHA1Verify  		TypesWriter tw = new TypesWriter();
  		tw.writeString("ssh-rsa");
 -		tw.writeMPInt(pk.getE());
 -		tw.writeMPInt(pk.getN());
 +		tw.writeMPInt(pk.getPublicExponent());
 +		tw.writeMPInt(pk.getModulus());
  		return tw.getBytes();
  	}
 -	public static RSASignature decodeSSHRSASignature(byte[] sig) throws IOException
 +	public static byte[] decodeSSHRSASignature(byte[] sig) throws IOException
  	{
  		TypesReader tr = new TypesReader(sig);
 @@ -77,10 +98,22 @@ public class RSASHA1Verify  		if (tr.remain() != 0)
  			throw new IOException("Padding in RSA signature!");
 -		return new RSASignature(new BigInteger(1, s));
 +		if (s[0] == 0 && s[1] == 0 && s[2] == 0) {
 +			int i = 0;
 +			int j = ((s[i++] << 24) & 0xff000000) | ((s[i++] << 16) & 0x00ff0000)
 +					| ((s[i++] << 8) & 0x0000ff00) | ((s[i++]) & 0x000000ff);
 +			i += j;
 +			j = ((s[i++] << 24) & 0xff000000) | ((s[i++] << 16) & 0x00ff0000)
 +					| ((s[i++] << 8) & 0x0000ff00) | ((s[i++]) & 0x000000ff);
 +			byte[] tmp = new byte[j];
 +			System.arraycopy(s, i, tmp, 0, j);
 +			sig = tmp;
 +		}
 +
 +		return s;
  	}
 -	public static byte[] encodeSSHRSASignature(RSASignature sig) throws IOException
 +	public static byte[] encodeSSHRSASignature(byte[] s) throws IOException
  	{
  		TypesWriter tw = new TypesWriter();
 @@ -91,8 +124,6 @@ public class RSASHA1Verify  		 * network byte order)."
  		 */
 -		byte[] s = sig.getS().toByteArray();
 -
  		/* Remove first zero sign byte, if present */
  		if ((s.length > 1) && (s[0] == 0x00))
 @@ -103,183 +134,47 @@ public class RSASHA1Verify  		return tw.getBytes();
  	}
 -	public static RSASignature generateSignature(byte[] message, RSAPrivateKey pk) throws IOException
 +	public static byte[] generateSignature(byte[] message, RSAPrivateKey pk) throws IOException
  	{
 -		SHA1 md = new SHA1();
 -		md.update(message);
 -		byte[] sha_message = new byte[md.getDigestLength()];
 -		md.digest(sha_message);
 -
 -		byte[] der_header = new byte[] { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00,
 -				0x04, 0x14 };
 -
 -		int rsa_block_len = (pk.getN().bitLength() + 7) / 8;
 -
 -		int num_pad = rsa_block_len - (2 + der_header.length + sha_message.length) - 1;
 -
 -		if (num_pad < 8)
 -			throw new IOException("Cannot sign with RSA, message too long");
 -
 -		byte[] sig = new byte[der_header.length + sha_message.length + 2 + num_pad];
 -
 -		sig[0] = 0x01;
 -
 -		for (int i = 0; i < num_pad; i++)
 -		{
 -			sig[i + 1] = (byte) 0xff;
 +		try {
 +			Signature s = Signature.getInstance("SHA1withRSA");
 +			s.initSign(pk);
 +			s.update(message);
 +			return s.sign();
 +		} catch (NoSuchAlgorithmException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (InvalidKeyException e) {
 +			IOException ex =  new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (SignatureException e) {
 +			IOException ex =  new IOException();
 +			ex.initCause(e);
 +			throw ex;
  		}
 -
 -		sig[num_pad + 1] = 0x00;
 -
 -		System.arraycopy(der_header, 0, sig, 2 + num_pad, der_header.length);
 -		System.arraycopy(sha_message, 0, sig, 2 + num_pad + der_header.length, sha_message.length);
 -
 -		BigInteger m = new BigInteger(1, sig);
 -
 -		BigInteger s = m.modPow(pk.getD(), pk.getN());
 -
 -		return new RSASignature(s);
  	}
 -	public static boolean verifySignature(byte[] message, RSASignature ds, RSAPublicKey dpk) throws IOException
 +	public static boolean verifySignature(byte[] message, byte[] ds, RSAPublicKey dpk) throws IOException
  	{
 -		SHA1 md = new SHA1();
 -		md.update(message);
 -		byte[] sha_message = new byte[md.getDigestLength()];
 -		md.digest(sha_message);
 -
 -		BigInteger n = dpk.getN();
 -		BigInteger e = dpk.getE();
 -		BigInteger s = ds.getS();
 -
 -		if (n.compareTo(s) <= 0)
 -		{
 -			log.log(20, "ssh-rsa signature: n.compareTo(s) <= 0");
 -			return false;
 -		}
 -
 -		int rsa_block_len = (n.bitLength() + 7) / 8;
 -
 -		/* And now the show begins */
 -
 -		if (rsa_block_len < 1)
 -		{
 -			log.log(20, "ssh-rsa signature: rsa_block_len < 1");
 -			return false;
 -		}
 -
 -		byte[] v = s.modPow(e, n).toByteArray();
 -
 -		int startpos = 0;
 -
 -		if ((v.length > 0) && (v[0] == 0x00))
 -			startpos++;
 -
 -		if ((v.length - startpos) != (rsa_block_len - 1))
 -		{
 -			log.log(20, "ssh-rsa signature: (v.length - startpos) != (rsa_block_len - 1)");
 -			return false;
 -		}
 -
 -		if (v[startpos] != 0x01)
 -		{
 -			log.log(20, "ssh-rsa signature: v[startpos] != 0x01");
 -			return false;
 -		}
 -
 -		int pos = startpos + 1;
 -
 -		while (true)
 -		{
 -			if (pos >= v.length)
 -			{
 -				log.log(20, "ssh-rsa signature: pos >= v.length");
 -				return false;
 -			}
 -			if (v[pos] == 0x00)
 -				break;
 -			if (v[pos] != (byte) 0xff)
 -			{
 -				log.log(20, "ssh-rsa signature: v[pos] != (byte) 0xff");
 -				return false;
 -			}
 -			pos++;
 -		}
 -
 -		int num_pad = pos - (startpos + 1);
 -
 -		if (num_pad < 8)
 -		{
 -			log.log(20, "ssh-rsa signature: num_pad < 8");
 -			return false;
 -		}
 -
 -		pos++;
 -
 -		if (pos >= v.length)
 -		{
 -			log.log(20, "ssh-rsa signature: pos >= v.length");
 -			return false;
 -		}
 -
 -		SimpleDERReader dr = new SimpleDERReader(v, pos, v.length - pos);
 -
 -		byte[] seq = dr.readSequenceAsByteArray();
 -
 -		if (dr.available() != 0)
 -		{
 -			log.log(20, "ssh-rsa signature: dr.available() != 0");
 -			return false;
 -		}
 -
 -		dr.resetInput(seq);
 -
 -		/* Read digestAlgorithm */
 -
 -		byte digestAlgorithm[] = dr.readSequenceAsByteArray();
 -
 -		/* Inspired by RFC 3347, however, ignoring the comment regarding old BER based implementations */
 -
 -		if ((digestAlgorithm.length < 8) || (digestAlgorithm.length > 9))
 -		{
 -			log.log(20, "ssh-rsa signature: (digestAlgorithm.length < 8) || (digestAlgorithm.length > 9)");
 -			return false;
 -		}
 -
 -		byte[] digestAlgorithm_sha1 = new byte[] { 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00 };
 -
 -		for (int i = 0; i < digestAlgorithm.length; i++)
 -		{
 -			if (digestAlgorithm[i] != digestAlgorithm_sha1[i])
 -			{
 -				log.log(20, "ssh-rsa signature: digestAlgorithm[i] != digestAlgorithm_sha1[i]");
 -				return false;
 -			}
 -		}
 -
 -		byte[] digest = dr.readOctetString();
 -
 -		if (dr.available() != 0)
 -		{
 -			log.log(20, "ssh-rsa signature: dr.available() != 0 (II)");
 -			return false;
 -		}
 -			
 -		if (digest.length != sha_message.length)
 -		{
 -			log.log(20, "ssh-rsa signature: digest.length != sha_message.length");
 -			return false;
 +		try {
 +			Signature s = Signature.getInstance("SHA1withRSA");
 +			s.initVerify(dpk);
 +			s.update(message);
 +			return s.verify(ds);
 +		} catch (NoSuchAlgorithmException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (InvalidKeyException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
 +		} catch (SignatureException e) {
 +			IOException ex = new IOException();
 +			ex.initCause(e);
 +			throw ex;
  		}
 -
 -		for (int i = 0; i < sha_message.length; i++)
 -		{
 -			if (sha_message[i] != digest[i])
 -			{
 -				log.log(20, "ssh-rsa signature: sha_message[i] != digest[i]");
 -				return false;
 -			}
 -		}
 -
 -		return true;
  	}
  }
 diff --git a/src/com/trilead/ssh2/signature/RSASignature.java b/src/com/trilead/ssh2/signature/RSASignature.java deleted file mode 100644 index e04e7ee..0000000 --- a/src/com/trilead/ssh2/signature/RSASignature.java +++ /dev/null @@ -1,27 +0,0 @@ -
 -package com.trilead.ssh2.signature;
 -
 -import java.math.BigInteger;
 -
 -
 -/**
 - * RSASignature.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: RSASignature.java,v 1.1 2007/10/15 12:49:57 cplattne Exp $
 - */
 -
 -public class RSASignature
 -{
 -	BigInteger s;
 -
 -	public BigInteger getS()
 -	{
 -		return s;
 -	}
 -
 -	public RSASignature(BigInteger s)
 -	{
 -		this.s = s;
 -	}
 -}
\ No newline at end of file diff --git a/src/com/trilead/ssh2/transport/KexManager.java b/src/com/trilead/ssh2/transport/KexManager.java index 476d93f..43a5267 100644 --- a/src/com/trilead/ssh2/transport/KexManager.java +++ b/src/com/trilead/ssh2/transport/KexManager.java @@ -3,6 +3,8 @@ package com.trilead.ssh2.transport;  import java.io.IOException;
  import java.security.SecureRandom;
 +import java.security.interfaces.DSAPublicKey;
 +import java.security.interfaces.RSAPublicKey;
  import com.trilead.ssh2.ConnectionInfo;
  import com.trilead.ssh2.DHGexParameters;
 @@ -27,12 +29,8 @@ import com.trilead.ssh2.packets.PacketKexDhGexRequestOld;  import com.trilead.ssh2.packets.PacketKexInit;
  import com.trilead.ssh2.packets.PacketNewKeys;
  import com.trilead.ssh2.packets.Packets;
 -import com.trilead.ssh2.signature.DSAPublicKey;
  import com.trilead.ssh2.signature.DSASHA1Verify;
 -import com.trilead.ssh2.signature.DSASignature;
 -import com.trilead.ssh2.signature.RSAPublicKey;
  import com.trilead.ssh2.signature.RSASHA1Verify;
 -import com.trilead.ssh2.signature.RSASignature;
  /**
 @@ -348,7 +346,7 @@ public class KexManager  	{
  		if (kxs.np.server_host_key_algo.equals("ssh-rsa"))
  		{
 -			RSASignature rs = RSASHA1Verify.decodeSSHRSASignature(sig);
 +			byte[] rs = RSASHA1Verify.decodeSSHRSASignature(sig);
  			RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(hostkey);
  			log.log(50, "Verifying ssh-rsa signature");
 @@ -358,7 +356,7 @@ public class KexManager  		if (kxs.np.server_host_key_algo.equals("ssh-dss"))
  		{
 -			DSASignature ds = DSASHA1Verify.decodeSSHDSASignature(sig);
 +			byte[] ds = DSASHA1Verify.decodeSSHDSASignature(sig);
  			DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(hostkey);
  			log.log(50, "Verifying ssh-dss signature");
 diff --git a/src/org/connectbot/PubkeyListActivity.java b/src/org/connectbot/PubkeyListActivity.java index 9bb19f1..4c97b71 100644 --- a/src/org/connectbot/PubkeyListActivity.java +++ b/src/org/connectbot/PubkeyListActivity.java @@ -257,43 +257,41 @@ public class PubkeyListActivity extends ListActivity implements EventListener {  		}  	} -	protected void handleAddKey(PubkeyBean pubkey, String password) { -		Object trileadKey = null; -		if(PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType())) { +	protected void handleAddKey(PubkeyBean keybean, String password) { +		KeyPair pair = null; +		if(PubkeyDatabase.KEY_TYPE_IMPORTED.equals(keybean.getType())) {  			// load specific key using pem format  			try { -				trileadKey = PEMDecoder.decode(new String(pubkey.getPrivateKey()).toCharArray(), password); +				pair = PEMDecoder.decode(new String(keybean.getPrivateKey()).toCharArray(), password);  			} catch(Exception e) { -				String message = getResources().getString(R.string.pubkey_failed_add, pubkey.getNickname()); +				String message = getResources().getString(R.string.pubkey_failed_add, keybean.getNickname());  				Log.e(TAG, message, e);  				Toast.makeText(PubkeyListActivity.this, message, Toast.LENGTH_LONG);  			} -  		} else {  			// load using internal generated format -			PrivateKey privKey = null; -			PublicKey pubKey = null;  			try { -				privKey = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType(), password); -				pubKey = pubkey.getPublicKey(); +				PrivateKey privKey = PubkeyUtils.decodePrivate(keybean.getPrivateKey(), keybean.getType(), password); +				PublicKey pubKey = keybean.getPublicKey(); +				Log.d(TAG, "Unlocked key " + PubkeyUtils.formatKey(pubKey)); + +				pair = new KeyPair(pubKey, privKey);  			} catch (Exception e) { -				String message = getResources().getString(R.string.pubkey_failed_add, pubkey.getNickname()); +				String message = getResources().getString(R.string.pubkey_failed_add, keybean.getNickname());  				Log.e(TAG, message, e);  				Toast.makeText(PubkeyListActivity.this, message, Toast.LENGTH_LONG);  				return;  			} - -			// convert key to trilead format -			trileadKey = PubkeyUtils.convertToTrilead(privKey, pubKey); -			Log.d(TAG, "Unlocked key " + PubkeyUtils.formatKey(pubKey));  		} -		if(trileadKey == null) return; +		if (pair == null) { +		    return; +		} -		Log.d(TAG, String.format("Unlocked key '%s'", pubkey.getNickname())); +		Log.d(TAG, String.format("Unlocked key '%s'", keybean.getNickname()));  		// save this key in memory -		bound.addKey(pubkey, trileadKey, true); +		bound.addKey(keybean, pair, true);  		updateHandler.sendEmptyMessage(-1);  	} diff --git a/src/org/connectbot/service/TerminalManager.java b/src/org/connectbot/service/TerminalManager.java index b81c373..cc4392a 100644 --- a/src/org/connectbot/service/TerminalManager.java +++ b/src/org/connectbot/service/TerminalManager.java @@ -19,6 +19,7 @@ package org.connectbot.service;  import java.io.IOException;  import java.lang.ref.WeakReference; +import java.security.KeyPair;  import java.security.PrivateKey;  import java.security.PublicKey;  import java.util.Arrays; @@ -138,9 +139,9 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen  			try {  				PrivateKey privKey = PubkeyUtils.decodePrivate(pubkey.getPrivateKey(), pubkey.getType());  				PublicKey pubKey = pubkey.getPublicKey(); -				Object trileadKey = PubkeyUtils.convertToTrilead(privKey, pubKey); +				KeyPair pair = new KeyPair(pubKey, privKey); -				addKey(pubkey, trileadKey); +				addKey(pubkey, pair);  			} catch (Exception e) {  				Log.d(TAG, String.format("Problem adding key '%s' to in-memory cache", pubkey.getNickname()), e);  			} @@ -359,21 +360,21 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen  		return loadedKeypairs.containsKey(nickname);  	} -	public void addKey(PubkeyBean pubkey, Object trileadKey) { -		addKey(pubkey, trileadKey, false); +	public void addKey(PubkeyBean pubkey, KeyPair pair) { +		addKey(pubkey, pair, false);  	} -	public void addKey(PubkeyBean pubkey, Object trileadKey, boolean force) { +	public void addKey(PubkeyBean pubkey, KeyPair pair, boolean force) {  		if (!savingKeys && !force)  			return;  		removeKey(pubkey.getNickname()); -		byte[] sshPubKey = PubkeyUtils.extractOpenSSHPublic(trileadKey); +		byte[] sshPubKey = PubkeyUtils.extractOpenSSHPublic(pair);  		KeyHolder keyHolder = new KeyHolder();  		keyHolder.bean = pubkey; -		keyHolder.trileadKey = trileadKey; +		keyHolder.pair = pair;  		keyHolder.openSSHPubkey = sshPubKey;  		loadedKeypairs.put(pubkey.getNickname(), keyHolder); @@ -413,18 +414,18 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen  			return false;  	} -	public Object getKey(String nickname) { +	public KeyPair getKey(String nickname) {  		if (loadedKeypairs.containsKey(nickname)) {  			KeyHolder keyHolder = loadedKeypairs.get(nickname); -			return keyHolder.trileadKey; +			return keyHolder.pair;  		} else  			return null;  	} -	public Object getKey(byte[] publicKey) { +	public KeyPair getKey(byte[] publicKey) {  		for (KeyHolder keyHolder : loadedKeypairs.values()) {  			if (Arrays.equals(keyHolder.openSSHPubkey, publicKey)) -				return keyHolder.trileadKey; +				return keyHolder.pair;  		}  		return null;  	} @@ -644,7 +645,7 @@ public class TerminalManager extends Service implements BridgeDisconnectedListen  	public static class KeyHolder {  		public PubkeyBean bean; -		public Object trileadKey; +		public KeyPair pair;  		public byte[] openSSHPubkey;  	} diff --git a/src/org/connectbot/transport/SSH.java b/src/org/connectbot/transport/SSH.java index 213cbcd..449016b 100644 --- a/src/org/connectbot/transport/SSH.java +++ b/src/org/connectbot/transport/SSH.java @@ -22,14 +22,20 @@ import java.io.InputStream;  import java.io.OutputStream;  import java.net.InetAddress;  import java.net.InetSocketAddress; +import java.security.KeyPair;  import java.security.NoSuchAlgorithmException;  import java.security.PrivateKey;  import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey;  import java.security.spec.InvalidKeySpecException;  import java.util.Arrays;  import java.util.HashMap;  import java.util.LinkedList;  import java.util.List; +import java.util.Locale;  import java.util.Map;  import java.util.Map.Entry;  import java.util.regex.Matcher; @@ -62,11 +68,7 @@ import com.trilead.ssh2.LocalPortForwarder;  import com.trilead.ssh2.ServerHostKeyVerifier;  import com.trilead.ssh2.Session;  import com.trilead.ssh2.crypto.PEMDecoder; -import com.trilead.ssh2.signature.DSAPrivateKey; -import com.trilead.ssh2.signature.DSAPublicKey;  import com.trilead.ssh2.signature.DSASHA1Verify; -import com.trilead.ssh2.signature.RSAPrivateKey; -import com.trilead.ssh2.signature.RSAPublicKey;  import com.trilead.ssh2.signature.RSASHA1Verify;  /** @@ -141,7 +143,7 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  			KnownHosts hosts = manager.hostdb.getKnownHosts();  			Boolean result; -			String matchName = String.format("%s:%d", hostname, port); +			String matchName = String.format(Locale.US, "%s:%d", hostname, port);  			String fingerprint = KnownHosts.createHexFingerprint(serverHostKeyAlgorithm, serverHostKey); @@ -234,7 +236,7 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  							continue;  						if (this.tryPublicKey(host.getUsername(), entry.getKey(), -								entry.getValue().trileadKey)) { +								entry.getValue().pair)) {  							finishConnection();  							break;  						} @@ -293,7 +295,8 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  	 * @throws IOException  	 */  	private boolean tryPublicKey(PubkeyBean pubkey) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { -		Object trileadKey = null; +		KeyPair pair = null; +  		if(manager.isKeyLoaded(pubkey.getNickname())) {  			// load this key from memory if its already there  			Log.d(TAG, String.format("Found unlocked key '%s' already in-memory", pubkey.getNickname())); @@ -303,7 +306,7 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  					return false;  			} -			trileadKey = manager.getKey(pubkey.getNickname()); +			pair = manager.getKey(pubkey.getNickname());  		} else {  			// otherwise load key from database and prompt for password as needed  			String password = null; @@ -318,7 +321,7 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  			if(PubkeyDatabase.KEY_TYPE_IMPORTED.equals(pubkey.getType())) {  				// load specific key using pem format -				trileadKey = PEMDecoder.decode(new String(pubkey.getPrivateKey()).toCharArray(), password); +				pair = PEMDecoder.decode(new String(pubkey.getPrivateKey()).toCharArray(), password);  			} else {  				// load using internal generated format  				PrivateKey privKey; @@ -335,22 +338,22 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  				PublicKey pubKey = pubkey.getPublicKey();  				// convert key to trilead format -				trileadKey = PubkeyUtils.convertToTrilead(privKey, pubKey); +				pair = new KeyPair(pubKey, privKey);  				Log.d(TAG, "Unlocked key " + PubkeyUtils.formatKey(pubKey));  			}  			Log.d(TAG, String.format("Unlocked key '%s'", pubkey.getNickname()));  			// save this key in memory -			manager.addKey(pubkey, trileadKey); +			manager.addKey(pubkey, pair);  		} -		return tryPublicKey(host.getUsername(), pubkey.getNickname(), trileadKey); +		return tryPublicKey(host.getUsername(), pubkey.getNickname(), pair);  	} -	private boolean tryPublicKey(String username, String keyNickname, Object trileadKey) throws IOException { +	private boolean tryPublicKey(String username, String keyNickname, KeyPair pair) throws IOException {  		//bridge.outputLine(String.format("Attempting 'publickey' with key '%s' [%s]...", keyNickname, trileadKey.toString())); -		boolean success = connection.authenticateWithPublicKey(username, trileadKey); +		boolean success = connection.authenticateWithPublicKey(username, pair);  		if(!success)  			bridge.outputLine(manager.res.getString(R.string.terminal_auth_pubkey_fail, keyNickname));  		return success; @@ -739,9 +742,9 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  	@Override  	public String getDefaultNickname(String username, String hostname, int port) {  		if (port == DEFAULT_PORT) { -			return String.format("%s@%s", username, hostname); +			return String.format(Locale.US, "%s@%s", username, hostname);  		} else { -			return String.format("%s@%s:%d", username, hostname, port); +			return String.format(Locale.US, "%s@%s:%d", username, hostname, port);  		}  	} @@ -858,14 +861,15 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  		Map<String,byte[]> pubKeys = new HashMap<String,byte[]>(manager.loadedKeypairs.size());  		for (Entry<String,KeyHolder> entry : manager.loadedKeypairs.entrySet()) { -			Object trileadKey = entry.getValue().trileadKey; +			KeyPair pair = entry.getValue().pair;  			try { -				if (trileadKey instanceof RSAPrivateKey) { -					RSAPublicKey pubkey = ((RSAPrivateKey) trileadKey).getPublicKey(); +				PrivateKey privKey = pair.getPrivate(); +				if (privKey instanceof RSAPrivateKey) { +					RSAPublicKey pubkey = (RSAPublicKey) pair.getPublic();  					pubKeys.put(entry.getKey(), RSASHA1Verify.encodeSSHRSAPublicKey(pubkey)); -				} else if (trileadKey instanceof DSAPrivateKey) { -					DSAPublicKey pubkey = ((DSAPrivateKey) trileadKey).getPublicKey(); +				} else if (privKey instanceof DSAPrivateKey) { +					DSAPublicKey pubkey = (DSAPublicKey) pair.getPublic();  					pubKeys.put(entry.getKey(), DSASHA1Verify.encodeSSHDSAPublicKey(pubkey));  				} else  					continue; @@ -877,7 +881,7 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  		return pubKeys;  	} -	public Object getPrivateKey(byte[] publicKey) { +	public KeyPair getKeyPair(byte[] publicKey) {  		String nickname = manager.getKeyNickname(publicKey);  		if (nickname == null) @@ -901,13 +905,13 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC  		return result;  	} -	public boolean addIdentity(Object key, String comment, boolean confirmUse, int lifetime) { +	public boolean addIdentity(KeyPair pair, String comment, boolean confirmUse, int lifetime) {  		PubkeyBean pubkey = new PubkeyBean();  //		pubkey.setType(PubkeyDatabase.KEY_TYPE_IMPORTED);  		pubkey.setNickname(comment);  		pubkey.setConfirmUse(confirmUse);  		pubkey.setLifetime(lifetime); -		manager.addKey(pubkey, key); +		manager.addKey(pubkey, pair);  		return true;  	} diff --git a/src/org/connectbot/util/PubkeyUtils.java b/src/org/connectbot/util/PubkeyUtils.java index 029cb0c..57326b6 100644 --- a/src/org/connectbot/util/PubkeyUtils.java +++ b/src/org/connectbot/util/PubkeyUtils.java @@ -192,40 +192,6 @@ public class PubkeyUtils {  	}  	/* -	 * Trilead compatibility methods -	 */ - -	public static Object convertToTrilead(PublicKey pk) { -		if (pk instanceof RSAPublicKey) { -			return new com.trilead.ssh2.signature.RSAPublicKey( -					((RSAPublicKey) pk).getPublicExponent(), -					((RSAPublicKey) pk).getModulus()); -		} else if (pk instanceof DSAPublicKey) { -			DSAParams dp = ((DSAPublicKey) pk).getParams(); -			return new com.trilead.ssh2.signature.DSAPublicKey( -						dp.getP(), dp.getQ(), dp.getG(), ((DSAPublicKey) pk).getY()); -		} - -		throw new IllegalArgumentException("PublicKey is not RSA or DSA format"); -	} - -	public static Object convertToTrilead(PrivateKey priv, PublicKey pub) { -		if (priv instanceof RSAPrivateKey) { -			return new com.trilead.ssh2.signature.RSAPrivateKey( -					((RSAPrivateKey) priv).getPrivateExponent(), -					((RSAPublicKey) pub).getPublicExponent(), -					((RSAPrivateKey) priv).getModulus()); -		} else if (priv instanceof DSAPrivateKey) { -			DSAParams dp = ((DSAPrivateKey) priv).getParams(); -			return new com.trilead.ssh2.signature.DSAPrivateKey( -						dp.getP(), dp.getQ(), dp.getG(), ((DSAPublicKey) pub).getY(), -						((DSAPrivateKey) priv).getX()); -		} - -		throw new IllegalArgumentException("Key is not RSA or DSA format"); -	} - -	/*  	 * OpenSSH compatibility methods  	 */ @@ -236,13 +202,11 @@ public class PubkeyUtils {  		if (pk instanceof RSAPublicKey) {  			String data = "ssh-rsa "; -			data += String.valueOf(Base64.encode(RSASHA1Verify.encodeSSHRSAPublicKey( -					(com.trilead.ssh2.signature.RSAPublicKey)convertToTrilead(pk)))); +			data += String.valueOf(Base64.encode(RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pk)));  			return data + " " + nickname;  		} else if (pk instanceof DSAPublicKey) {  			String data = "ssh-dss "; -			data += String.valueOf(Base64.encode(DSASHA1Verify.encodeSSHDSAPublicKey( -					(com.trilead.ssh2.signature.DSAPublicKey)convertToTrilead(pk)))); +			data += String.valueOf(Base64.encode(DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pk)));  			return data + " " + nickname;  		} @@ -257,16 +221,16 @@ public class PubkeyUtils {  	 * @param trileadKey  	 * @return OpenSSH-encoded pubkey  	 */ -	public static byte[] extractOpenSSHPublic(Object trileadKey) { +	public static byte[] extractOpenSSHPublic(KeyPair pair) {  		try { -			if (trileadKey instanceof com.trilead.ssh2.signature.RSAPrivateKey) -				return RSASHA1Verify.encodeSSHRSAPublicKey( -						((com.trilead.ssh2.signature.RSAPrivateKey) trileadKey).getPublicKey()); -			else if (trileadKey instanceof com.trilead.ssh2.signature.DSAPrivateKey) -				return DSASHA1Verify.encodeSSHDSAPublicKey( -						((com.trilead.ssh2.signature.DSAPrivateKey) trileadKey).getPublicKey()); -			else +			PublicKey pubKey = pair.getPublic(); +			if (pubKey instanceof RSAPublicKey) { +				return RSASHA1Verify.encodeSSHRSAPublicKey((RSAPublicKey) pair.getPublic()); +			} else if (pubKey instanceof DSAPublicKey) { +				return DSASHA1Verify.encodeSSHDSAPublicKey((DSAPublicKey) pair.getPublic()); +			} else {  				return null; +			}  		} catch (IOException e) {  			return null;  		} | 
