diff --git a/src/main/java/net/schmizz/sshj/DefaultConfig.java b/src/main/java/net/schmizz/sshj/DefaultConfig.java index 4a264d11..86d6fc07 100644 --- a/src/main/java/net/schmizz/sshj/DefaultConfig.java +++ b/src/main/java/net/schmizz/sshj/DefaultConfig.java @@ -15,12 +15,22 @@ */ package net.schmizz.sshj; +import java.io.IOException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; + +import org.slf4j.Logger; + import com.hierynomus.sshj.signature.SignatureEdDSA; import com.hierynomus.sshj.transport.cipher.BlockCiphers; import com.hierynomus.sshj.transport.cipher.StreamCiphers; import com.hierynomus.sshj.transport.kex.DHGroups; import com.hierynomus.sshj.transport.kex.ExtendedDHGroups; import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile; + import net.schmizz.keepalive.KeepAliveProvider; import net.schmizz.sshj.common.Factory; import net.schmizz.sshj.common.LoggerFactory; @@ -28,13 +38,24 @@ import net.schmizz.sshj.common.SecurityUtils; import net.schmizz.sshj.signature.SignatureDSA; import net.schmizz.sshj.signature.SignatureECDSA; import net.schmizz.sshj.signature.SignatureRSA; -import net.schmizz.sshj.transport.cipher.*; +import net.schmizz.sshj.transport.cipher.AES128CBC; +import net.schmizz.sshj.transport.cipher.AES128CTR; +import net.schmizz.sshj.transport.cipher.AES192CBC; +import net.schmizz.sshj.transport.cipher.AES192CTR; +import net.schmizz.sshj.transport.cipher.AES256CBC; +import net.schmizz.sshj.transport.cipher.AES256CTR; +import net.schmizz.sshj.transport.cipher.BlowfishCBC; +import net.schmizz.sshj.transport.cipher.Cipher; +import net.schmizz.sshj.transport.cipher.TripleDESCBC; import net.schmizz.sshj.transport.compression.NoneCompression; -import net.schmizz.sshj.transport.kex.Curve25519SHA256; import net.schmizz.sshj.transport.kex.DHGexSHA1; -import net.schmizz.sshj.transport.kex.DHGexSHA256; import net.schmizz.sshj.transport.kex.ECDHNistP; -import net.schmizz.sshj.transport.mac.*; +import net.schmizz.sshj.transport.mac.HMACMD5; +import net.schmizz.sshj.transport.mac.HMACMD596; +import net.schmizz.sshj.transport.mac.HMACSHA1; +import net.schmizz.sshj.transport.mac.HMACSHA196; +import net.schmizz.sshj.transport.mac.HMACSHA2256; +import net.schmizz.sshj.transport.mac.HMACSHA2512; import net.schmizz.sshj.transport.random.BouncyCastleRandom; import net.schmizz.sshj.transport.random.JCERandom; import net.schmizz.sshj.transport.random.SingletonRandomFactory; @@ -42,10 +63,6 @@ import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile; import net.schmizz.sshj.userauth.keyprovider.PKCS5KeyFile; import net.schmizz.sshj.userauth.keyprovider.PKCS8KeyFile; import net.schmizz.sshj.userauth.keyprovider.PuTTYKeyFile; -import org.slf4j.Logger; - -import java.io.IOException; -import java.util.*; /** * A {@link net.schmizz.sshj.Config} that is initialized as follows. Items marked with an asterisk are added to the config only if @@ -108,8 +125,8 @@ public class DefaultConfig protected void initKeyExchangeFactories(boolean bouncyCastleRegistered) { if (bouncyCastleRegistered) { - setKeyExchangeFactories(new Curve25519SHA256.Factory(), - new DHGexSHA256.Factory(), + setKeyExchangeFactories(/*new Curve25519SHA256.Factory(), + new DHGexSHA256.Factory(),*/ new ECDHNistP.Factory521(), new ECDHNistP.Factory384(), new ECDHNistP.Factory256(), @@ -210,7 +227,8 @@ public class DefaultConfig protected void initSignatureFactories() { setSignatureFactories( - new SignatureECDSA.Factory(), + new SignatureECDSA.Factory256(), + new SignatureECDSA.Factory384(), new SignatureRSA.Factory(), new SignatureDSA.Factory(), new SignatureEdDSA.Factory() diff --git a/src/main/java/net/schmizz/sshj/common/ECDSAVariationsAdapter.java b/src/main/java/net/schmizz/sshj/common/ECDSAVariationsAdapter.java new file mode 100644 index 00000000..f492f1ac --- /dev/null +++ b/src/main/java/net/schmizz/sshj/common/ECDSAVariationsAdapter.java @@ -0,0 +1,92 @@ +package net.schmizz.sshj.common; + +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.asn1.nist.NISTNamedCurves; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.jce.spec.ECParameterSpec; +import org.bouncycastle.jce.spec.ECPublicKeySpec; +import org.bouncycastle.math.ec.ECPoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.hierynomus.sshj.secg.SecgUtils; + +public class ECDSAVariationsAdapter { + + private final static String BASE_ALGORITHM_NAME = "ecdsa-sha2-nistp"; + + private final static Logger log = LoggerFactory.getLogger(ECDSAVariationsAdapter.class); + + public final static Map SUPPORTED_CURVES = new HashMap(); + public final static Map NIST_CURVES_NAMES = new HashMap(); + + static { + NIST_CURVES_NAMES.put("256", "p-256"); + NIST_CURVES_NAMES.put("384", "p-384"); + NIST_CURVES_NAMES.put("521", "p-521"); + + SUPPORTED_CURVES.put("256", "nistp256"); + SUPPORTED_CURVES.put("384", "nistp384"); + SUPPORTED_CURVES.put("521", "nistp521"); + } + + public static PublicKey readPubKeyFromBuffer(Buffer buf, String variation) throws GeneralSecurityException { + String algorithm = BASE_ALGORITHM_NAME + variation; + if (!SecurityUtils.isBouncyCastleRegistered()) { + throw new GeneralSecurityException("BouncyCastle is required to read a key of type " + algorithm); + } + try { + // final String algo = buf.readString(); it has been already read + final String curveName = buf.readString(); + final int keyLen = buf.readUInt32AsInt(); + final byte x04 = buf.readByte(); // it must be 0x04, but don't think + // we need that check + final byte[] x = new byte[(keyLen - 1) / 2]; + final byte[] y = new byte[(keyLen - 1) / 2]; + buf.readRawBytes(x); + buf.readRawBytes(y); + if (log.isDebugEnabled()) { + log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s", + algorithm, curveName, keyLen, x04, Arrays.toString(x), Arrays.toString(y))); + } + + if (!SUPPORTED_CURVES.values().contains(curveName)) { + throw new GeneralSecurityException(String.format("Unknown curve %s", curveName)); + } + + BigInteger bigX = new BigInteger(1, x); + BigInteger bigY = new BigInteger(1, y); + + X9ECParameters ecParams = NISTNamedCurves.getByName(NIST_CURVES_NAMES.get(variation)); + ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY); + ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(), ecParams.getG(), ecParams.getN()); + ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec); + + KeyFactory keyFactory = KeyFactory.getInstance("ECDSA"); + return keyFactory.generatePublic(publicSpec); + } catch (Exception ex) { + throw new GeneralSecurityException(ex); + } + } + + public static void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { + final ECPublicKey ecdsa = (ECPublicKey) pk; + byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve()); + + buf.putString(Integer.toString(fieldSizeFromKey(ecdsa))) + .putBytes(encoded); + } + + public static int fieldSizeFromKey(ECPublicKey ecPublicKey) { + return ecPublicKey.getParams().getCurve().getField().getFieldSize(); + } + +} diff --git a/src/main/java/net/schmizz/sshj/common/KeyType.java b/src/main/java/net/schmizz/sshj/common/KeyType.java index c93d3ea7..20ab87ed 100644 --- a/src/main/java/net/schmizz/sshj/common/KeyType.java +++ b/src/main/java/net/schmizz/sshj/common/KeyType.java @@ -35,15 +35,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.bouncycastle.asn1.nist.NISTNamedCurves; -import org.bouncycastle.asn1.x9.X9ECParameters; -import org.bouncycastle.jce.spec.ECParameterSpec; -import org.bouncycastle.jce.spec.ECPublicKeySpec; -import org.bouncycastle.math.ec.ECPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.hierynomus.sshj.secg.SecgUtils; import com.hierynomus.sshj.signature.Ed25519PublicKey; import com.hierynomus.sshj.userauth.certificate.Certificate; @@ -121,133 +115,43 @@ public enum KeyType { /** SSH identifier for ECDSA-256 keys */ ECDSA256("ecdsa-sha2-nistp256") { - private final Logger log = LoggerFactory.getLogger(getClass()); @Override public PublicKey readPubKeyFromBuffer(Buffer buf) throws GeneralSecurityException { - if (!SecurityUtils.isBouncyCastleRegistered()) { - throw new GeneralSecurityException("BouncyCastle is required to read a key of type " + sType); - } - try { - // final String algo = buf.readString(); it has been already read - final String curveName = buf.readString(); - final int keyLen = buf.readUInt32AsInt(); - final byte x04 = buf.readByte(); // it must be 0x04, but don't think we need that check - final byte[] x = new byte[(keyLen - 1) / 2]; - final byte[] y = new byte[(keyLen - 1) / 2]; - buf.readRawBytes(x); - buf.readRawBytes(y); - if(log.isDebugEnabled()) { - log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s", - sType, - curveName, - keyLen, - x04, - Arrays.toString(x), - Arrays.toString(y)) - ); - } - - if (!NISTP_CURVE_256.equals(curveName)) { - throw new GeneralSecurityException(String.format("Unknown curve %s", curveName)); - } - - BigInteger bigX = new BigInteger(1, x); - BigInteger bigY = new BigInteger(1, y); - - X9ECParameters ecParams = NISTNamedCurves.getByName("p-256"); - ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY); - ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(), - ecParams.getG(), ecParams.getN()); - ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec); - - KeyFactory keyFactory = KeyFactory.getInstance("ECDSA"); - return keyFactory.generatePublic(publicSpec); - } catch (Exception ex) { - throw new GeneralSecurityException(ex); - } + return ECDSAVariationsAdapter.readPubKeyFromBuffer(buf, "256"); } @Override protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { - final ECPublicKey ecdsa = (ECPublicKey) pk; - byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve()); - - buf.putString(NISTP_CURVE_256) - .putBytes(encoded); + ECDSAVariationsAdapter.writePubKeyContentsIntoBuffer(pk, buf); } @Override protected boolean isMyType(Key key) { - return ("ECDSA".equals(key.getAlgorithm()) && ((ECPublicKey) key).getParams().getCurve().getField().getFieldSize() == 256); + return ("ECDSA".equals(key.getAlgorithm()) && ECDSAVariationsAdapter.fieldSizeFromKey((ECPublicKey) key) == 256); } }, /** SSH identifier for ECDSA-384 keys */ ECDSA384("ecdsa-sha2-nistp384") { - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Override + + @Override public PublicKey readPubKeyFromBuffer(Buffer buf) throws GeneralSecurityException { - if (!SecurityUtils.isBouncyCastleRegistered()) { - throw new GeneralSecurityException("BouncyCastle is required to read a key of type " + sType); - } - try { - // final String algo = buf.readString(); it has been already read - final String curveName = buf.readString(); - final int keyLen = buf.readUInt32AsInt(); - final byte x04 = buf.readByte(); // it must be 0x04, but don't think we need that check - final byte[] x = new byte[(keyLen - 1) / 2]; - final byte[] y = new byte[(keyLen - 1) / 2]; - buf.readRawBytes(x); - buf.readRawBytes(y); - if(log.isDebugEnabled()) { - log.debug(String.format("Key algo: %s, Key curve: %s, Key Len: %s, 0x04: %s\nx: %s\ny: %s", - sType, - curveName, - keyLen, - x04, - Arrays.toString(x), - Arrays.toString(y)) - ); - } - - if (!NISTP_CURVE_384.equals(curveName)) { - throw new GeneralSecurityException(String.format("Unknown curve %s", curveName)); - } - - BigInteger bigX = new BigInteger(1, x); - BigInteger bigY = new BigInteger(1, y); - - X9ECParameters ecParams = NISTNamedCurves.getByName("p-384"); - ECPoint pPublicPoint = ecParams.getCurve().createPoint(bigX, bigY); - ECParameterSpec spec = new ECParameterSpec(ecParams.getCurve(), - ecParams.getG(), ecParams.getN()); - ECPublicKeySpec publicSpec = new ECPublicKeySpec(pPublicPoint, spec); - - KeyFactory keyFactory = KeyFactory.getInstance("ECDSA"); - return keyFactory.generatePublic(publicSpec); - } catch (Exception ex) { - throw new GeneralSecurityException(ex); - } + return ECDSAVariationsAdapter.readPubKeyFromBuffer(buf, "384"); } @Override protected void writePubKeyContentsIntoBuffer(PublicKey pk, Buffer buf) { - final ECPublicKey ecdsa = (ECPublicKey) pk; - byte[] encoded = SecgUtils.getEncoded(ecdsa.getW(), ecdsa.getParams().getCurve()); - - buf.putString(NISTP_CURVE_384) - .putBytes(encoded); + ECDSAVariationsAdapter.writePubKeyContentsIntoBuffer(pk, buf); } @Override protected boolean isMyType(Key key) { - return ("ECDSA".equals(key.getAlgorithm()) && ((ECPublicKey) key).getParams().getCurve().getField().getFieldSize() == 384); + return ("ECDSA".equals(key.getAlgorithm()) && ECDSAVariationsAdapter.fieldSizeFromKey((ECPublicKey) key) == 384); } }, @@ -350,10 +254,8 @@ public enum KeyType { } }; - - private static final String NISTP_CURVE_256 = "nistp256"; - private static final String NISTP_CURVE_384 = "nistp384"; - + private static String NISTP_CURVE_256 = "qqq"; + private static String NISTP_CURVE_384 = "qqq"; protected final String sType; private KeyType(String type) { diff --git a/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java b/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java index 32273285..18264507 100644 --- a/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java +++ b/src/main/java/net/schmizz/sshj/signature/SignatureECDSA.java @@ -15,24 +15,24 @@ */ package net.schmizz.sshj.signature; +import java.math.BigInteger; +import java.security.SignatureException; + import net.schmizz.sshj.common.Buffer; import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.common.SSHRuntimeException; -import java.math.BigInteger; -import java.security.SignatureException; - /** ECDSA {@link Signature} */ public class SignatureECDSA extends AbstractSignature { - /** A named factory for ECDSA signature */ - public static class Factory + /** A named factory for ECDSA-256 signature */ + public static class Factory256 implements net.schmizz.sshj.common.Factory.Named { @Override public Signature create() { - return new SignatureECDSA(); + return new SignatureECDSA("SHA256withECDSA", KeyType.ECDSA256.toString()); } @Override @@ -42,10 +42,29 @@ public class SignatureECDSA } - public SignatureECDSA() { - super("SHA256withECDSA"); + /** A named factory for ECDSA-384 signature */ + public static class Factory384 + implements net.schmizz.sshj.common.Factory.Named { + + @Override + public Signature create() { + return new SignatureECDSA("SHA384withECDSA", KeyType.ECDSA384.toString()); + } + + @Override + public String getName() { + return KeyType.ECDSA384.toString(); + } + } + private String keyTypeName; + + public SignatureECDSA(String algorithm, String keyTypeName) { + super(algorithm); + this.keyTypeName = keyTypeName; + } + @Override public byte[] encode(byte[] sig) { int rIndex = 3; @@ -75,8 +94,8 @@ public class SignatureECDSA try { Buffer sigbuf = new Buffer.PlainBuffer(sig); final String algo = new String(sigbuf.readBytes()); - if (!"ecdsa-sha2-nistp256".equals(algo)) { - throw new SSHRuntimeException(String.format("Signature :: ecdsa-sha2-nistp256 expected, got %s", algo)); + if (!keyTypeName.equals(algo)) { + throw new SSHRuntimeException(String.format("Signature :: " + keyTypeName + " expected, got %s", algo)); } final int rsLen = sigbuf.readUInt32AsInt(); if (sigbuf.available() != rsLen) { diff --git a/src/main/java/net/schmizz/sshj/signature/SignatureECDSA384.java b/src/main/java/net/schmizz/sshj/signature/SignatureECDSA384.java deleted file mode 100644 index 33fcdc54..00000000 --- a/src/main/java/net/schmizz/sshj/signature/SignatureECDSA384.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C)2009 - SSHJ Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.schmizz.sshj.signature; - -import net.schmizz.sshj.common.Buffer; -import net.schmizz.sshj.common.KeyType; -import net.schmizz.sshj.common.SSHRuntimeException; - -import java.math.BigInteger; -import java.security.SignatureException; - -/** ECDSA {@link Signature} */ -public class SignatureECDSA384 - extends AbstractSignature { - - /** A named factory for ECDSA signature */ - public static class Factory - implements net.schmizz.sshj.common.Factory.Named { - - @Override - public Signature create() { - return new SignatureECDSA384(); - } - - @Override - public String getName() { - return KeyType.ECDSA384.toString(); - } - - } - - public SignatureECDSA384() { - super("SHA384withECDSA"); - } - - @Override - public byte[] encode(byte[] sig) { - int rIndex = 3; - int rLen = sig[rIndex++] & 0xff; - byte[] r = new byte[rLen]; - System.arraycopy(sig, rIndex, r, 0, r.length); - - int sIndex = rIndex + rLen + 1; - int sLen = sig[sIndex++] & 0xff; - byte[] s = new byte[sLen]; - System.arraycopy(sig, sIndex, s, 0, s.length); - - System.arraycopy(sig, 4, r, 0, rLen); - System.arraycopy(sig, 6 + rLen, s, 0, sLen); - - Buffer buf = new Buffer.PlainBuffer(); - buf.putMPInt(new BigInteger(r)); - buf.putMPInt(new BigInteger(s)); - - return buf.getCompactData(); - } - - @Override - public boolean verify(byte[] sig) { - byte[] r; - byte[] s; - try { - Buffer sigbuf = new Buffer.PlainBuffer(sig); - final String algo = new String(sigbuf.readBytes()); - if (!"ecdsa-sha2-nistp384".equals(algo)) { - throw new SSHRuntimeException(String.format("Signature :: ecdsa-sha2-nistp384 expected, got %s", algo)); - } - final int rsLen = sigbuf.readUInt32AsInt(); - if (sigbuf.available() != rsLen) { - throw new SSHRuntimeException("Invalid key length"); - } - r = sigbuf.readBytes(); - s = sigbuf.readBytes(); - } catch (Exception e) { - throw new SSHRuntimeException(e); - } - - int rLen = r.length; - int sLen = s.length; - - /* We can't have the high bit set, so add an extra zero at the beginning if so. */ - if ((r[0] & 0x80) != 0) { - rLen++; - } - if ((s[0] & 0x80) != 0) { - sLen++; - } - - /* Calculate total output length */ - int length = 6 + rLen + sLen; - byte[] asn1 = new byte[length]; - - /* ASN.1 SEQUENCE tag */ - asn1[0] = (byte) 0x30; - - /* Size of SEQUENCE */ - asn1[1] = (byte) (4 + rLen + sLen); - - /* ASN.1 INTEGER tag */ - asn1[2] = (byte) 0x02; - - /* "r" INTEGER length */ - asn1[3] = (byte) rLen; - - /* Copy in the "r" INTEGER */ - System.arraycopy(r, 0, asn1, 4, rLen); - - /* ASN.1 INTEGER tag */ - asn1[rLen + 4] = (byte) 0x02; - - /* "s" INTEGER length */ - asn1[rLen + 5] = (byte) sLen; - - /* Copy in the "s" INTEGER */ - System.arraycopy(s, 0, asn1, (6 + rLen), sLen); - - - try { - return signature.verify(asn1); - } catch (SignatureException e) { - throw new SSHRuntimeException(e); - } - } -}