diff options
Diffstat (limited to 'lib')
10 files changed, 381 insertions, 154 deletions
| diff --git a/lib/src/main/java/com/trilead/ssh2/crypto/KeyMaterial.java b/lib/src/main/java/com/trilead/ssh2/crypto/KeyMaterial.java index 5dfb55e..035717d 100644 --- a/lib/src/main/java/com/trilead/ssh2/crypto/KeyMaterial.java +++ b/lib/src/main/java/com/trilead/ssh2/crypto/KeyMaterial.java @@ -3,6 +3,8 @@ package com.trilead.ssh2.crypto;  import java.math.BigInteger;
 +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException;  import com.trilead.ssh2.crypto.digest.HashForSSH2Types;
 @@ -66,13 +68,18 @@ public class KeyMaterial  		return res;
  	}
 -	public static KeyMaterial create(String hashType, byte[] H, BigInteger K, byte[] SessionID, int keyLengthCS,
 +	public static KeyMaterial create(String hashAlgo, byte[] H, BigInteger K, byte[] SessionID, int keyLengthCS,  			int blockSizeCS, int macLengthCS, int keyLengthSC, int blockSizeSC, int macLengthSC)
  			throws IllegalArgumentException
  	{
  		KeyMaterial km = new KeyMaterial();
 -		HashForSSH2Types sh = new HashForSSH2Types(hashType);
 +		HashForSSH2Types sh; +		try { +			sh = new HashForSSH2Types(MessageDigest.getInstance(hashAlgo)); +		} catch (NoSuchAlgorithmException e) { +			throw new IllegalArgumentException(e); +		}  		km.initial_iv_client_to_server = calculateKey(sh, K, H, (byte) 'A', SessionID, blockSizeCS);
 diff --git a/lib/src/main/java/com/trilead/ssh2/crypto/dh/DhExchange.java b/lib/src/main/java/com/trilead/ssh2/crypto/dh/DhExchange.java index 5622a72..d5bb112 100644 --- a/lib/src/main/java/com/trilead/ssh2/crypto/dh/DhExchange.java +++ b/lib/src/main/java/com/trilead/ssh2/crypto/dh/DhExchange.java @@ -1,147 +1,132 @@ -
 +/** + * + */  package com.trilead.ssh2.crypto.dh;
 -import java.io.UnsupportedEncodingException;
 +import java.io.IOException;  import java.math.BigInteger;
 -import java.security.SecureRandom;
 -
 -import com.trilead.ssh2.crypto.digest.HashForSSH2Types;
 -import com.trilead.ssh2.log.Logger;
 -
 +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.KeyAgreement; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.DHPublicKeySpec;  /**
 - * DhExchange.
 - * 
 - * @author Christian Plattner, plattner@trilead.com
 - * @version $Id: DhExchange.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $
 + * @author kenny + *   */
 -public class DhExchange
 -{
 -	private static final Logger log = Logger.getLogger(DhExchange.class);
 +public class DhExchange extends GenericDhExchange {  	/* Given by the standard */
 -	static final BigInteger p1, p14;
 -	static final BigInteger g;
 -
 -	BigInteger p;
 +	private static final BigInteger P1 = new BigInteger( +			  "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +			+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +			+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +			+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +			+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +			+ "FFFFFFFFFFFFFFFF", 16); + +	private static final BigInteger P14 = new BigInteger( +			  "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +			+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +			+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +			+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +			+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +			+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +			+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +			+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +			+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +			+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +			+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16); + +	private static final BigInteger G = BigInteger.valueOf(2);  	/* Client public and private */
 -	BigInteger e;
 -	BigInteger x;
 +	private DHPrivateKey clientPrivate; +	private DHPublicKey clientPublic;  	/* Server public */
 -	BigInteger f;
 -
 -	/* Shared secret */
 -
 -	BigInteger k;
 -
 -	static
 -	{
 -		final String p1_string = "17976931348623159077083915679378745319786029604875"
 -				+ "60117064444236841971802161585193689478337958649255415021805654859805036464"
 -				+ "40548199239100050792877003355816639229553136239076508735759914822574862575"
 -				+ "00742530207744771258955095793777842444242661733472762929938766870920560605"
 -				+ "0270810842907692932019128194467627007";
 -
 -		final String p14_string = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129"
 -				+ "024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0"
 -				+ "A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB"
 -				+ "6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A"
 -				+ "163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208"
 -				+ "552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36C"
 -				+ "E3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171"
 -				+ "83995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF";
 -
 -		p1 = new BigInteger(p1_string);
 -		p14 = new BigInteger(p14_string, 16);
 -		g = new BigInteger("2");
 -	}
 -
 -	public DhExchange()
 -	{
 +	private DHPublicKey serverPublic; + +	@Override +	public void init(String name) throws IOException { +		final DHParameterSpec spec; +		if ("diffie-hellman-group1-sha1".equals(name)) { +			spec = new DHParameterSpec(P1, G); +		} else if ("diffie-hellman-group14-sha1".equals(name)) { +			spec = new DHParameterSpec(P14, G); +		} else { +			throw new IllegalArgumentException("Unknown DH group " + name); +		} + +		try { +			KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH"); +			kpg.initialize(spec); +			KeyPair pair = kpg.generateKeyPair(); +			clientPrivate = (DHPrivateKey) pair.getPrivate(); +			clientPublic = (DHPublicKey) pair.getPublic(); +		} catch (NoSuchAlgorithmException e) { +			throw (IOException) new IOException("No DH keypair generator").initCause(e); +		} catch (InvalidAlgorithmParameterException e) { +			throw (IOException) new IOException("Invalid DH parameters").initCause(e); +		}  	}
 -	public void init(int group, SecureRandom rnd)
 -	{
 -		k = null;
 +	@Override +	public byte[] getE() { +		if (clientPublic == null) +			throw new IllegalStateException("DhExchange not initialized!"); -		if (group == 1)
 -			p = p1;
 -		else if (group == 14)
 -			p = p14;
 -		else
 -			throw new IllegalArgumentException("Unknown DH group " + group);
 -
 -		x = new BigInteger(p.bitLength() - 1, rnd);
 -
 -		e = g.modPow(x, p);
 -	}
 -
 -	/**
 -	 * @return Returns the e.
 -	 * @throws IllegalStateException
 -	 */
 -	public BigInteger getE()
 -	{
 -		if (e == null)
 -			throw new IllegalStateException("DhDsaExchange not initialized!");
 -
 -		return e;
 +		return clientPublic.getY().toByteArray();  	}
 -	/**
 -	 * @return Returns the shared secret k.
 -	 * @throws IllegalStateException
 -	 */
 -	public BigInteger getK()
 -	{
 -		if (k == null)
 -			throw new IllegalStateException("Shared secret not yet known, need f first!");
 +	@Override +	protected byte[] getServerE() { +		if (serverPublic == null) +			throw new IllegalStateException("DhExchange not initialized!"); -		return k;
 +		return serverPublic.getY().toByteArray();  	}
 -	/**
 -	 * @param f
 -	 */
 -	public void setF(BigInteger f)
 -	{
 -		if (e == null)
 -			throw new IllegalStateException("DhDsaExchange not initialized!");
 -
 -		BigInteger zero = BigInteger.valueOf(0);
 -
 -		if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0)
 -			throw new IllegalArgumentException("Invalid f specified!");
 -
 -		this.f = f;
 -		this.k = f.modPow(x, p);
 -	}
 -
 -	public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload,
 -			byte[] serverKexPayload, byte[] hostKey) throws UnsupportedEncodingException
 -	{
 -		HashForSSH2Types hash = new HashForSSH2Types("SHA1");
 -
 -		if (log.isEnabled())
 -		{
 -			log.log(90, "Client: '" + new String(clientversion, "ISO-8859-1") + "'");
 -			log.log(90, "Server: '" + new String(serverversion, "ISO-8859-1") + "'");
 +	@Override +	public void setF(byte[] f) throws IOException { +		if (clientPublic == null) +			throw new IllegalStateException("DhExchange not initialized!"); + +		final KeyAgreement ka; +		try { +			KeyFactory kf = KeyFactory.getInstance("DH"); +			DHParameterSpec params = clientPublic.getParams(); +			this.serverPublic = (DHPublicKey) kf.generatePublic(new DHPublicKeySpec( +					new BigInteger(f), params.getP(), params.getG())); + +			ka = KeyAgreement.getInstance("DH"); +			ka.init(clientPrivate); +			ka.doPhase(serverPublic, true); +		} catch (NoSuchAlgorithmException e) { +			throw (IOException) new IOException("No DH key agreement method").initCause(e); +		} catch (InvalidKeyException e) { +			throw (IOException) new IOException("Invalid DH key").initCause(e); +		} catch (InvalidKeySpecException e) { +			throw (IOException) new IOException("Invalid DH key").initCause(e);  		}
 -		hash.updateByteString(clientversion);
 -		hash.updateByteString(serverversion);
 -		hash.updateByteString(clientKexPayload);
 -		hash.updateByteString(serverKexPayload);
 -		hash.updateByteString(hostKey);
 -		hash.updateBigInt(e);
 -		hash.updateBigInt(f);
 -		hash.updateBigInt(k);
 +		sharedSecret = new BigInteger(ka.generateSecret()); +	} -		return hash.getDigest();
 +	@Override +	public String getHashAlgo() { +		return "SHA1";  	}
  }
 diff --git a/lib/src/main/java/com/trilead/ssh2/crypto/dh/EcDhExchange.java b/lib/src/main/java/com/trilead/ssh2/crypto/dh/EcDhExchange.java new file mode 100644 index 0000000..43d31ad --- /dev/null +++ b/lib/src/main/java/com/trilead/ssh2/crypto/dh/EcDhExchange.java @@ -0,0 +1,106 @@ +/** + * + */ +package com.trilead.ssh2.crypto.dh; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.KeyAgreement; + +import com.trilead.ssh2.signature.ECDSASHA2Verify; + +/** + * @author kenny + * + */ +public class EcDhExchange extends GenericDhExchange { +	private ECPrivateKey clientPrivate; +	private ECPublicKey clientPublic; +	private ECPublicKey serverPublic; + +	@Override +	public void init(String name) throws IOException { +		final ECParameterSpec spec; + +		if ("ecdh-sha2-nistp256".equals(name)) { +			spec = ECDSASHA2Verify.EllipticCurves.nistp256; +		} else if ("ecdh-sha2-nistp384".equals(name)) { +			spec = ECDSASHA2Verify.EllipticCurves.nistp384; +		} else if ("ecdh-sha2-nistp521".equals(name)) { +			spec = ECDSASHA2Verify.EllipticCurves.nistp521; +		} else { +			throw new IllegalArgumentException("Unknown EC curve " + name); +		} + +		KeyPairGenerator kpg; +		try { +			kpg = KeyPairGenerator.getInstance("EC"); +			kpg.initialize(spec); +			KeyPair pair = kpg.generateKeyPair(); +			clientPrivate = (ECPrivateKey) pair.getPrivate(); +			clientPublic = (ECPublicKey) pair.getPublic(); +		} catch (NoSuchAlgorithmException e) { +			throw (IOException) new IOException("No DH keypair generator").initCause(e); +		} catch (InvalidAlgorithmParameterException e) { +			throw (IOException) new IOException("Invalid DH parameters").initCause(e); +		} +	} + +	@Override +	public byte[] getE() { +		return ECDSASHA2Verify.encodeECPoint(clientPublic.getW(), clientPublic.getParams() +				.getCurve()); +	} + +	@Override +	protected byte[] getServerE() { +		return ECDSASHA2Verify.encodeECPoint(serverPublic.getW(), serverPublic.getParams() +				.getCurve()); +	} + +	@Override +	public void setF(byte[] f) throws IOException { + +		if (clientPublic == null) +			throw new IllegalStateException("DhDsaExchange not initialized!"); + +		final KeyAgreement ka; +		try { +			KeyFactory kf = KeyFactory.getInstance("EC"); +			ECParameterSpec params = clientPublic.getParams(); +			ECPoint serverPoint = ECDSASHA2Verify.decodeECPoint(f, params.getCurve()); +			this.serverPublic = (ECPublicKey) kf.generatePublic(new ECPublicKeySpec(serverPoint, +																					params)); + +			ka = KeyAgreement.getInstance("ECDH"); +			ka.init(clientPrivate); +			ka.doPhase(serverPublic, true); +		} catch (NoSuchAlgorithmException e) { +			throw (IOException) new IOException("No ECDH key agreement method").initCause(e); +		} catch (InvalidKeyException e) { +			throw (IOException) new IOException("Invalid ECDH key").initCause(e); +		} catch (InvalidKeySpecException e) { +			throw (IOException) new IOException("Invalid ECDH key").initCause(e); +		} + +		sharedSecret = new BigInteger(ka.generateSecret()); +	} + +	@Override +	public String getHashAlgo() { +		return ECDSASHA2Verify.getDigestAlgorithmForParams(clientPublic.getParams()); +	} +} diff --git a/lib/src/main/java/com/trilead/ssh2/crypto/dh/GenericDhExchange.java b/lib/src/main/java/com/trilead/ssh2/crypto/dh/GenericDhExchange.java new file mode 100644 index 0000000..d65490a --- /dev/null +++ b/lib/src/main/java/com/trilead/ssh2/crypto/dh/GenericDhExchange.java @@ -0,0 +1,100 @@ + +package com.trilead.ssh2.crypto.dh; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import com.trilead.ssh2.crypto.digest.HashForSSH2Types; +import com.trilead.ssh2.log.Logger; + + +/** + * DhExchange. + * + * @author Christian Plattner, plattner@trilead.com + * @version $Id: DhExchange.java,v 1.2 2008/04/01 12:38:09 cplattne Exp $ + */ +public abstract class GenericDhExchange +{ +	private static final Logger log = Logger.getLogger(GenericDhExchange.class); + +	/* Shared secret */ + +	BigInteger sharedSecret; + +	protected GenericDhExchange() +	{ +	} + +	public static GenericDhExchange getInstance(String algo) { +		if (algo.startsWith("ecdh-sha2-")) { +			return new EcDhExchange(); +		} else { +			return new DhExchange(); +		} +	} + +	public abstract void init(String name) throws IOException; + +	/** +	 * @return Returns the e (public value) +	 * @throws IllegalStateException +	 */ +	public abstract byte[] getE(); + +	/** +	 * @return Returns the server's e (public value) +	 * @throws IllegalStateException +	 */ +	protected abstract byte[] getServerE(); + +	/** +	 * @return Returns the shared secret k. +	 * @throws IllegalStateException +	 */ +	public BigInteger getK() +	{ +		if (sharedSecret == null) +			throw new IllegalStateException("Shared secret not yet known, need f first!"); + +		return sharedSecret; +	} + +	/** +	 * @param f +	 */ +	public abstract void setF(byte[] f) throws IOException; + +	public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload, +			byte[] serverKexPayload, byte[] hostKey) throws UnsupportedEncodingException +	{ +		HashForSSH2Types hash; +		try { +			hash = new HashForSSH2Types(MessageDigest.getInstance(getHashAlgo())); +		} catch (NoSuchAlgorithmException e) { +			throw new UnsupportedOperationException(e); +		} + +		if (log.isEnabled()) +		{ +			log.log(90, "Client: '" + new String(clientversion, "ISO-8859-1") + "'"); +			log.log(90, "Server: '" + new String(serverversion, "ISO-8859-1") + "'"); +		} + +		hash.updateByteString(clientversion); +		hash.updateByteString(serverversion); +		hash.updateByteString(clientKexPayload); +		hash.updateByteString(serverKexPayload); +		hash.updateByteString(hostKey); +		hash.updateByteString(getE()); +		hash.updateByteString(getServerE()); +		hash.updateBigInt(sharedSecret); + +		return hash.getDigest(); +	} + +	public abstract String getHashAlgo(); +} diff --git a/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHInit.java b/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHInit.java index 26e14f6..9201936 100644 --- a/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHInit.java +++ b/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHInit.java @@ -1,7 +1,5 @@  package com.trilead.ssh2.packets;
 -import java.math.BigInteger;
 -
  /**
   * PacketKexDHInit.
   * 
 @@ -12,11 +10,11 @@ public class PacketKexDHInit  {
  	byte[] payload;
 -	BigInteger e;
 +	byte[] publicKey; -	public PacketKexDHInit(BigInteger e)
 +	public PacketKexDHInit(byte[] publicKey)  	{
 -		this.e = e;
 +		this.publicKey = publicKey;  	}
  	public byte[] getPayload()
 @@ -25,7 +23,7 @@ public class PacketKexDHInit  		{
  			TypesWriter tw = new TypesWriter();
  			tw.writeByte(Packets.SSH_MSG_KEXDH_INIT);
 -			tw.writeMPInt(e);
 +			tw.writeString(publicKey, 0, publicKey.length);  			payload = tw.getBytes();
  		}
  		return payload;
 diff --git a/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHReply.java b/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHReply.java index 0803ff9..461f262 100644 --- a/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHReply.java +++ b/lib/src/main/java/com/trilead/ssh2/packets/PacketKexDHReply.java @@ -2,8 +2,6 @@ package com.trilead.ssh2.packets;  import java.io.IOException;
 -import java.math.BigInteger;
 -
  /**
   * PacketKexDHReply.
   * 
 @@ -15,7 +13,7 @@ public class PacketKexDHReply  	byte[] payload;
  	byte[] hostKey;
 -	BigInteger f;
 +	byte[] publicKey;  	byte[] signature;
  	public PacketKexDHReply(byte payload[], int off, int len) throws IOException
 @@ -32,15 +30,15 @@ public class PacketKexDHReply  					+ packet_type + ")");
  		hostKey = tr.readByteString();
 -		f = tr.readMPINT();
 +		publicKey = tr.readByteString();  		signature = tr.readByteString();
  		if (tr.remain() != 0) throw new IOException("PADDING IN SSH_MSG_KEXDH_REPLY!");
  	}
 -	public BigInteger getF()
 +	public byte[] getF()  	{
 -		return f;
 +		return publicKey;  	}
  	public byte[] getHostKey()
 diff --git a/lib/src/main/java/com/trilead/ssh2/packets/PacketKexInit.java b/lib/src/main/java/com/trilead/ssh2/packets/PacketKexInit.java index 7da5067..2a961c2 100644 --- a/lib/src/main/java/com/trilead/ssh2/packets/PacketKexInit.java +++ b/lib/src/main/java/com/trilead/ssh2/packets/PacketKexInit.java @@ -4,7 +4,6 @@ package com.trilead.ssh2.packets;  import java.io.IOException;
  import java.security.SecureRandom;
 -import com.trilead.ssh2.compression.CompressionFactory;
  import com.trilead.ssh2.crypto.CryptoWishList;
  import com.trilead.ssh2.transport.KexParameters;
 @@ -21,10 +20,10 @@ public class PacketKexInit  	KexParameters kp = new KexParameters();
 -	public PacketKexInit(CryptoWishList cwl, SecureRandom rnd)
 +	public PacketKexInit(CryptoWishList cwl)  	{
  		kp.cookie = new byte[16];
 -		rnd.nextBytes(kp.cookie);
 +		new SecureRandom().nextBytes(kp.cookie);  		kp.kex_algorithms = cwl.kexAlgorithms;
  		kp.server_host_key_algorithms = cwl.serverHostKeyAlgorithms;
 diff --git a/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java b/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java index 1876bea..97bda5f 100644 --- a/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java +++ b/lib/src/main/java/com/trilead/ssh2/signature/ECDSASHA2Verify.java @@ -322,6 +322,17 @@ public class ECDSASHA2Verify {  		}  	} +	public static String getDigestAlgorithmForParams(ECParameterSpec params) { +		int size = getCurveSize(params); +		if (size <= 256) { +			return "SHA256"; +		} else if (size <= 384) { +			return "SHA384"; +		} else { +			return "SHA512"; +		} +	} +  	/**  	 * Decode an OctetString to EllipticCurvePoint according to SECG 2.3.4  	 */ @@ -370,18 +381,33 @@ public class ECDSASHA2Verify {  		M[0] = 0x04;  		{ -			byte[] affineX = group.getAffineX().toByteArray(); -			System.arraycopy(affineX, 0, M, 1, elementSize - affineX.length); +			byte[] affineX = removeLeadingZeroes(group.getAffineX().toByteArray()); +			System.arraycopy(affineX, 0, M, 1, affineX.length);  		}  		{ -			byte[] affineY = group.getAffineY().toByteArray(); -			System.arraycopy(affineY, 0, M, 1 + elementSize, elementSize - affineY.length); +			byte[] affineY = removeLeadingZeroes(group.getAffineY().toByteArray()); +			System.arraycopy(affineY, 0, M, 1 + elementSize, affineY.length);  		}  		return M;  	} +	private static byte[] removeLeadingZeroes(byte[] input) { +		if (input[0] != 0x00) { +			return input; +		} + +		int pos = 1; +		while (pos < input.length - 1 && input[pos] == 0x00) { +			pos++; +		} + +		byte[] output = new byte[input.length - pos]; +		System.arraycopy(input, pos, output, 0, output.length); +		return output; +	} +  	public static class EllipticCurves {  		public static ECParameterSpec nistp256 = new ECParameterSpec(  				new EllipticCurve( 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 a74a224..04043e4 100644 --- a/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java +++ b/lib/src/main/java/com/trilead/ssh2/transport/KexManager.java @@ -18,8 +18,8 @@ import com.trilead.ssh2.crypto.CryptoWishList;  import com.trilead.ssh2.crypto.KeyMaterial;
  import com.trilead.ssh2.crypto.cipher.BlockCipher;
  import com.trilead.ssh2.crypto.cipher.BlockCipherFactory;
 -import com.trilead.ssh2.crypto.dh.DhExchange;
  import com.trilead.ssh2.crypto.dh.DhGroupExchange;
 +import com.trilead.ssh2.crypto.dh.GenericDhExchange;  import com.trilead.ssh2.crypto.digest.MAC;
  import com.trilead.ssh2.log.Logger;
  import com.trilead.ssh2.packets.PacketKexDHInit;
 @@ -58,6 +58,9 @@ public class KexManager  	private static final Set<String> KEX_ALGS = new TreeSet<String>();
  	static {
 +		KEX_ALGS.add("ecdh-sha2-nistp256"); +		KEX_ALGS.add("ecdh-sha2-nistp384"); +		KEX_ALGS.add("ecdh-sha2-nistp521");  		KEX_ALGS.add("diffie-hellman-group-exchange-sha1");
  		KEX_ALGS.add("diffie-hellman-group14-sha1");
  		KEX_ALGS.add("diffie-hellman-group1-sha1");
 @@ -261,7 +264,7 @@ public class KexManager  			kxs = new KexState();
  			kxs.dhgexParameters = nextKEXdhgexParameters;
 -			PacketKexInit kp = new PacketKexInit(nextKEXcryptoWishList, rnd);
 +			PacketKexInit kp = new PacketKexInit(nextKEXcryptoWishList);  			kxs.localKEX = kp;
  			tm.sendKexMessage(kp.getPayload());
  		}
 @@ -279,7 +282,7 @@ public class KexManager  			int enc_sc_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_server_to_client);
  			int enc_sc_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_server_to_client);
 -			km = KeyMaterial.create("SHA1", kxs.H, kxs.K, sessionId, enc_cs_key_len, enc_cs_block_len, mac_cs_key_len,
 +			km = KeyMaterial.create(kxs.hashAlgo, kxs.H, kxs.K, sessionId, enc_cs_key_len, enc_cs_block_len, mac_cs_key_len,  					enc_sc_key_len, enc_sc_block_len, mac_sc_key_len);
  		}
  		catch (IllegalArgumentException e)
 @@ -424,7 +427,7 @@ public class KexManager  				 */
  				kxs = new KexState();
  				kxs.dhgexParameters = nextKEXdhgexParameters;
 -				kip = new PacketKexInit(nextKEXcryptoWishList, rnd);
 +				kip = new PacketKexInit(nextKEXcryptoWishList);  				kxs.localKEX = kip;
  				tm.sendKexMessage(kip.getPayload());
  			}
 @@ -459,19 +462,20 @@ public class KexManager  					PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters);
  					tm.sendKexMessage(dhgexreq.getPayload());
  				}
 +				kxs.hashAlgo = "SHA1";  				kxs.state = 1;
  				return;
  			}
  			if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1")
 -					|| kxs.np.kex_algo.equals("diffie-hellman-group14-sha1"))
 -			{
 -				kxs.dhx = new DhExchange();
 +					|| kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") +					|| kxs.np.kex_algo.equals("ecdh-sha2-nistp256") +					|| kxs.np.kex_algo.equals("ecdh-sha2-nistp384") +					|| kxs.np.kex_algo.equals("ecdh-sha2-nistp521")) { +				kxs.dhx = GenericDhExchange.getInstance(kxs.np.kex_algo); -				if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1"))
 -					kxs.dhx.init(1, rnd);
 -				else
 -					kxs.dhx.init(14, rnd);
 +				kxs.dhx.init(kxs.np.kex_algo); +				kxs.hashAlgo = kxs.dhx.getHashAlgo();  				PacketKexDHInit kp = new PacketKexDHInit(kxs.dhx.getE());
  				tm.sendKexMessage(kp.getPayload());
 @@ -600,7 +604,10 @@ public class KexManager  		}
  		if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1")
 -				|| kxs.np.kex_algo.equals("diffie-hellman-group14-sha1"))
 +				|| kxs.np.kex_algo.equals("diffie-hellman-group14-sha1") +				|| kxs.np.kex_algo.equals("ecdh-sha2-nistp256") +				|| kxs.np.kex_algo.equals("ecdh-sha2-nistp384") +				|| kxs.np.kex_algo.equals("ecdh-sha2-nistp521"))  		{
  			if (kxs.state == 1)
  			{
 diff --git a/lib/src/main/java/com/trilead/ssh2/transport/KexState.java b/lib/src/main/java/com/trilead/ssh2/transport/KexState.java index dabf450..d9f1004 100644 --- a/lib/src/main/java/com/trilead/ssh2/transport/KexState.java +++ b/lib/src/main/java/com/trilead/ssh2/transport/KexState.java @@ -4,8 +4,8 @@ package com.trilead.ssh2.transport;  import java.math.BigInteger;
  import com.trilead.ssh2.DHGexParameters;
 -import com.trilead.ssh2.crypto.dh.DhExchange;
  import com.trilead.ssh2.crypto.dh.DhGroupExchange;
 +import com.trilead.ssh2.crypto.dh.GenericDhExchange;  import com.trilead.ssh2.packets.PacketKexInit;
  /**
 @@ -26,7 +26,8 @@ public class KexState  	public byte[] hostkey;
 -	public DhExchange dhx;
 +	public String hashAlgo; +	public GenericDhExchange dhx;  	public DhGroupExchange dhgx;
  	public DHGexParameters dhgexParameters;
  }
 | 
