aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2013-02-03 19:00:31 -0800
committerKenny Root <kenny@the-b.org>2013-02-03 22:59:52 -0800
commit4271e2ed172a016e9455f0e43b628a744907ce63 (patch)
tree0ee025c12c415a91d53d11d3812bbff01c7a4c43
parent084ced208717d116b07bac3a3f6116f38e453a30 (diff)
downloadsshlib-4271e2ed172a016e9455f0e43b628a744907ce63.tar.gz
sshlib-4271e2ed172a016e9455f0e43b628a744907ce63.tar.bz2
sshlib-4271e2ed172a016e9455f0e43b628a744907ce63.zip
Remove J2ME compatibility layer for keys
Use JCE instead of the DIY crypto library that is in Trilead. This was apparently for J2ME devices. Well, I'm sorry, J2ME devices, you're dead to me.
-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");