aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/src/main/java/com/trilead/ssh2/AuthAgentCallback.java5
-rw-r--r--lib/src/main/java/com/trilead/ssh2/Connection.java11
-rw-r--r--lib/src/main/java/com/trilead/ssh2/KnownHosts.java157
-rw-r--r--lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java30
-rw-r--r--lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java78
-rw-r--r--lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java38
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/PEMDecoder.java81
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/digest/Digest.java25
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/digest/HMAC.java95
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java31
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/digest/MAC.java78
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/digest/MD5.java268
-rw-r--r--lib/src/main/java/com/trilead/ssh2/crypto/digest/SHA1.java664
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/DSAPrivateKey.java58
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/DSAPublicKey.java45
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/DSASHA1Verify.java235
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/DSASignature.java31
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/RSAPrivateKey.java43
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/RSAPublicKey.java31
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/RSASHA1Verify.java259
-rw-r--r--lib/src/main/java/com/trilead/ssh2/signature/RSASignature.java27
-rw-r--r--lib/src/main/java/com/trilead/ssh2/transport/KexManager.java10
22 files changed, 544 insertions, 1756 deletions
diff --git a/lib/src/main/java/com/trilead/ssh2/AuthAgentCallback.java b/lib/src/main/java/com/trilead/ssh2/AuthAgentCallback.java
index c395198..7fe270b 100644
--- a/lib/src/main/java/com/trilead/ssh2/AuthAgentCallback.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/Connection.java b/lib/src/main/java/com/trilead/ssh2/Connection.java
index 98e5fdd..c1e8711 100644
--- a/lib/src/main/java/com/trilead/ssh2/Connection.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/KnownHosts.java b/lib/src/main/java/com/trilead/ssh2/KnownHosts.java
index edca0a2..c68b852 100644
--- a/lib/src/main/java/com/trilead/ssh2/KnownHosts.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java b/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java
index 43c226a..e1e416e 100644
--- a/lib/src/main/java/com/trilead/ssh2/auth/AuthenticationManager.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java b/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java
index 57b9a5e..d3f10a3 100644
--- a/lib/src/main/java/com/trilead/ssh2/channel/AuthAgentForwardThread.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java b/lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java
index 630e0cc..432aef5 100644
--- a/lib/src/main/java/com/trilead/ssh2/channel/ChannelManager.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/PEMDecoder.java b/lib/src/main/java/com/trilead/ssh2/crypto/PEMDecoder.java
index 7d0a015..cf6be37 100644
--- a/lib/src/main/java/com/trilead/ssh2/crypto/PEMDecoder.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/digest/Digest.java b/lib/src/main/java/com/trilead/ssh2/crypto/digest/Digest.java
deleted file mode 100644
index 6ed969c..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/digest/HMAC.java b/lib/src/main/java/com/trilead/ssh2/crypto/digest/HMAC.java
deleted file mode 100644
index 8d52758..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java b/lib/src/main/java/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java
index df84952..30ffe0d 100644
--- a/lib/src/main/java/com/trilead/ssh2/crypto/digest/HashForSSH2Types.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/digest/MAC.java b/lib/src/main/java/com/trilead/ssh2/crypto/digest/MAC.java
index 0433b63..8138e63 100644
--- a/lib/src/main/java/com/trilead/ssh2/crypto/digest/MAC.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/digest/MD5.java b/lib/src/main/java/com/trilead/ssh2/crypto/digest/MD5.java
deleted file mode 100644
index 567f926..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/crypto/digest/SHA1.java b/lib/src/main/java/com/trilead/ssh2/crypto/digest/SHA1.java
deleted file mode 100644
index bba4cc6..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/DSAPrivateKey.java b/lib/src/main/java/com/trilead/ssh2/signature/DSAPrivateKey.java
deleted file mode 100644
index d2a63ae..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/DSAPublicKey.java b/lib/src/main/java/com/trilead/ssh2/signature/DSAPublicKey.java
deleted file mode 100644
index f8351ff..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/DSASHA1Verify.java b/lib/src/main/java/com/trilead/ssh2/signature/DSASHA1Verify.java
index c838ebd..357d66e 100644
--- a/lib/src/main/java/com/trilead/ssh2/signature/DSASHA1Verify.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/DSASignature.java b/lib/src/main/java/com/trilead/ssh2/signature/DSASignature.java
deleted file mode 100644
index eff84cd..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/RSAPrivateKey.java b/lib/src/main/java/com/trilead/ssh2/signature/RSAPrivateKey.java
deleted file mode 100644
index 5d5e606..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/RSAPublicKey.java b/lib/src/main/java/com/trilead/ssh2/signature/RSAPublicKey.java
deleted file mode 100644
index e7e6611..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/RSASHA1Verify.java b/lib/src/main/java/com/trilead/ssh2/signature/RSASHA1Verify.java
index 8a0f07a..9b5c18e 100644
--- a/lib/src/main/java/com/trilead/ssh2/signature/RSASHA1Verify.java
+++ b/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/signature/RSASignature.java b/lib/src/main/java/com/trilead/ssh2/signature/RSASignature.java
deleted file mode 100644
index e04e7ee..0000000
--- a/lib/src/main/java/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/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java b/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java
index 476d93f..43a5267 100644
--- a/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java
+++ b/lib/src/main/java/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");