diff --git a/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java b/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java index cd1694b1..d654799c 100644 --- a/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java +++ b/src/main/java/net/schmizz/sshj/transport/KeyExchanger.java @@ -47,6 +47,7 @@ import net.schmizz.sshj.transport.verification.HostKeyVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.security.GeneralSecurityException; import java.security.PublicKey; import java.util.Arrays; import java.util.LinkedList; @@ -228,8 +229,12 @@ final class KeyExchanger log.debug("Negotiated algorithms: {}", negotiatedAlgs); kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(), negotiatedAlgs .getKeyExchangeAlgorithm()); - kex.init(transport, transport.getServerID().getBytes(), transport.getClientID().getBytes(), buf - .getCompactData(), clientProposal.getPacket().getCompactData()); + try { + kex.init(transport, transport.getServerID().getBytes(), transport.getClientID().getBytes(), buf + .getCompactData(), clientProposal.getPacket().getCompactData()); + } catch (GeneralSecurityException e) { + throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e); + } } /** @@ -347,10 +352,14 @@ final class KeyExchanger case FOLLOWUP: ensureKexOngoing(); log.info("Received kex followup data"); - if (kex.next(msg, buf)) { - verifyHost(kex.getHostKey()); - sendNewKeys(); - expected = Expected.NEWKEYS; + try { + if (kex.next(msg, buf)) { + verifyHost(kex.getHostKey()); + sendNewKeys(); + expected = Expected.NEWKEYS; + } + } catch (GeneralSecurityException e) { + throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e); } break; diff --git a/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java b/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java index 6f8f4ec2..624e8829 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/AbstractDHG.java @@ -51,6 +51,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigInteger; +import java.security.GeneralSecurityException; import java.security.PublicKey; /** @@ -81,6 +82,10 @@ public abstract class AbstractDHG return ByteArrayUtils.copyOf(H); } + public byte[] getK() { + return ByteArrayUtils.copyOf(K); + } + public Digest getHash() { return sha; } @@ -89,12 +94,8 @@ public abstract class AbstractDHG return hostKey; } - public byte[] getK() { - return ByteArrayUtils.copyOf(K); - } - public void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) - throws TransportException { + throws GeneralSecurityException, TransportException { this.trans = trans; this.V_S = ByteArrayUtils.copyOf(V_S); this.V_C = ByteArrayUtils.copyOf(V_C); @@ -109,7 +110,7 @@ public abstract class AbstractDHG } public boolean next(Message msg, SSHPacket packet) - throws TransportException { + throws GeneralSecurityException, TransportException { if (msg != Message.KEXDH_31) throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "Unexpected packet: " + msg); @@ -139,7 +140,8 @@ public abstract class AbstractDHG signature.init(hostKey, null); signature.update(H, 0, H.length); if (!signature.verify(sig)) - throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, "KeyExchange signature verification failed"); + throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, + "KeyExchange signature verification failed"); return true; } diff --git a/src/main/java/net/schmizz/sshj/transport/kex/DH.java b/src/main/java/net/schmizz/sshj/transport/kex/DH.java index dcf79b97..ef672acc 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/DH.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/DH.java @@ -56,17 +56,16 @@ public class DH { private BigInteger e; // my public key private BigInteger f; // your public key private BigInteger K; // shared secret key - private final KeyPairGenerator myKpairGen; - private final KeyAgreement myKeyAgree; + private final KeyPairGenerator generator; + private final KeyAgreement agreement; public DH() { try { - myKpairGen = SecurityUtils.getKeyPairGenerator("DH"); - myKeyAgree = SecurityUtils.getKeyAgreement("DH"); + generator = SecurityUtils.getKeyPairGenerator("DH"); + agreement = SecurityUtils.getKeyAgreement("DH"); } catch (GeneralSecurityException e) { throw new SSHRuntimeException(e); } - } public void setF(BigInteger f) { @@ -81,33 +80,25 @@ public class DH { this.p = p; } - public byte[] getE() { + public byte[] getE() + throws GeneralSecurityException { if (e == null) { - DHParameterSpec dhSkipParamSpec = new DHParameterSpec(p, g); - KeyPair myKpair; - try { - myKpairGen.initialize(dhSkipParamSpec); - myKpair = myKpairGen.generateKeyPair(); - myKeyAgree.init(myKpair.getPrivate()); - } catch (GeneralSecurityException e) { - throw new SSHRuntimeException(e); - } - e = ((javax.crypto.interfaces.DHPublicKey) myKpair.getPublic()).getY(); + generator.initialize(new DHParameterSpec(p, g)); + final KeyPair kp = generator.generateKeyPair(); + agreement.init(kp.getPrivate()); + e = ((javax.crypto.interfaces.DHPublicKey) kp.getPublic()).getY(); } return e.toByteArray(); } - public byte[] getK() { + public byte[] getK() + throws GeneralSecurityException { if (K == null) { - try { - KeyFactory myKeyFac = SecurityUtils.getKeyFactory("DH"); - DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g); - PublicKey yourPubKey = myKeyFac.generatePublic(keySpec); - myKeyAgree.doPhase(yourPubKey, true); - } catch (GeneralSecurityException e) { - throw new SSHRuntimeException(e); - } - K = new BigInteger(myKeyAgree.generateSecret()); + final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DH"); + final DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g); + final PublicKey yourPubKey = keyFactory.generatePublic(keySpec); + agreement.doPhase(yourPubKey, true); + K = new BigInteger(agreement.generateSecret()); } return K.toByteArray(); } diff --git a/src/main/java/net/schmizz/sshj/transport/kex/DHG1.java b/src/main/java/net/schmizz/sshj/transport/kex/DHG1.java index 1bf61a05..2336fd87 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/DHG1.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/DHG1.java @@ -59,8 +59,8 @@ public class DHG1 @Override protected void initDH(DH dh) { - dh.setG(DHGroupData.getG()); - dh.setP(DHGroupData.getP1()); + dh.setG(DHGroupData.G); + dh.setP(DHGroupData.P1); } } diff --git a/src/main/java/net/schmizz/sshj/transport/kex/DHG14.java b/src/main/java/net/schmizz/sshj/transport/kex/DHG14.java index 2b3ef47c..cb3694d3 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/DHG14.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/DHG14.java @@ -60,8 +60,8 @@ public class DHG14 @Override protected void initDH(DH dh) { - dh.setG(DHGroupData.getG()); - dh.setP(DHGroupData.getP14()); + dh.setG(DHGroupData.G); + dh.setP(DHGroupData.P14); } } diff --git a/src/main/java/net/schmizz/sshj/transport/kex/DHGroupData.java b/src/main/java/net/schmizz/sshj/transport/kex/DHGroupData.java index 1dc74233..46dae607 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/DHGroupData.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/DHGroupData.java @@ -40,74 +40,23 @@ import java.math.BigInteger; /** Simple class holding the data for DH group key exchanges. */ public final class DHGroupData { - private static final BigInteger G = new BigInteger(new byte[]{2}); + public static final BigInteger G = + new BigInteger("2"); - private static final BigInteger P1 = new BigInteger(new byte[]{ - (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xC9, (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68, (byte) 0xC2, - (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62, (byte) 0x8B, (byte) 0x80, (byte) 0xDC, (byte) 0x1C, - (byte) 0xD1, (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A, (byte) 0x67, (byte) 0xCC, - (byte) 0x74, (byte) 0x02, (byte) 0x0B, (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13, (byte) 0x9B, - (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79, (byte) 0x8E, (byte) 0x34, (byte) 0x04, - (byte) 0xDD, (byte) 0xEF, (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A, (byte) 0x43, - (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A, (byte) 0x6D, (byte) 0xF2, (byte) 0x5F, (byte) 0x14, - (byte) 0x37, (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D, (byte) 0x51, (byte) 0xC2, - (byte) 0x45, (byte) 0xE4, (byte) 0x85, (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E, (byte) 0x7E, - (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9, (byte) 0xA6, (byte) 0x37, (byte) 0xED, - (byte) 0x6B, (byte) 0x0B, (byte) 0xFF, (byte) 0x5C, (byte) 0xB6, (byte) 0xF4, (byte) 0x06, (byte) 0xB7, - (byte) 0xED, (byte) 0xEE, (byte) 0x38, (byte) 0x6B, (byte) 0xFB, (byte) 0x5A, (byte) 0x89, (byte) 0x9F, - (byte) 0xA5, (byte) 0xAE, (byte) 0x9F, (byte) 0x24, (byte) 0x11, (byte) 0x7C, (byte) 0x4B, (byte) 0x1F, - (byte) 0xE6, (byte) 0x49, (byte) 0x28, (byte) 0x66, (byte) 0x51, (byte) 0xEC, (byte) 0xE6, (byte) 0x53, - (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF - }); + public static final BigInteger P1 = + new BigInteger("1797693134862315907708391567937874531978602960487560117064444236841971802161585193" + + "6894783379586492554150218056548598050364644054819923910005079287700335581663922955" + + "3136239076508735759914822574862575007425302077447712589550957937778424442426617334" + + "727629299387668709205606050270810842907692932019128194467627007"); - private static final BigInteger P14 = new BigInteger(new byte[]{ - (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF, (byte) 0xC9, (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68, (byte) 0xC2, - (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62, (byte) 0x8B, (byte) 0x80, (byte) 0xDC, (byte) 0x1C, - (byte) 0xD1, (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A, (byte) 0x67, (byte) 0xCC, - (byte) 0x74, (byte) 0x02, (byte) 0x0B, (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13, (byte) 0x9B, - (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79, (byte) 0x8E, (byte) 0x34, (byte) 0x04, - (byte) 0xDD, (byte) 0xEF, (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A, (byte) 0x43, - (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A, (byte) 0x6D, (byte) 0xF2, (byte) 0x5F, (byte) 0x14, - (byte) 0x37, (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D, (byte) 0x51, (byte) 0xC2, - (byte) 0x45, (byte) 0xE4, (byte) 0x85, (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E, (byte) 0x7E, - (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9, (byte) 0xA6, (byte) 0x37, (byte) 0xED, - (byte) 0x6B, (byte) 0x0B, (byte) 0xFF, (byte) 0x5C, (byte) 0xB6, (byte) 0xF4, (byte) 0x06, (byte) 0xB7, - (byte) 0xED, (byte) 0xEE, (byte) 0x38, (byte) 0x6B, (byte) 0xFB, (byte) 0x5A, (byte) 0x89, (byte) 0x9F, - (byte) 0xA5, (byte) 0xAE, (byte) 0x9F, (byte) 0x24, (byte) 0x11, (byte) 0x7C, (byte) 0x4B, (byte) 0x1F, - (byte) 0xE6, (byte) 0x49, (byte) 0x28, (byte) 0x66, (byte) 0x51, (byte) 0xEC, (byte) 0xE4, (byte) 0x5B, - (byte) 0x3D, (byte) 0xC2, (byte) 0x00, (byte) 0x7C, (byte) 0xB8, (byte) 0xA1, (byte) 0x63, (byte) 0xBF, - (byte) 0x05, (byte) 0x98, (byte) 0xDA, (byte) 0x48, (byte) 0x36, (byte) 0x1C, (byte) 0x55, (byte) 0xD3, - (byte) 0x9A, (byte) 0x69, (byte) 0x16, (byte) 0x3F, (byte) 0xA8, (byte) 0xFD, (byte) 0x24, (byte) 0xCF, - (byte) 0x5F, (byte) 0x83, (byte) 0x65, (byte) 0x5D, (byte) 0x23, (byte) 0xDC, (byte) 0xA3, (byte) 0xAD, - (byte) 0x96, (byte) 0x1C, (byte) 0x62, (byte) 0xF3, (byte) 0x56, (byte) 0x20, (byte) 0x85, (byte) 0x52, - (byte) 0xBB, (byte) 0x9E, (byte) 0xD5, (byte) 0x29, (byte) 0x07, (byte) 0x70, (byte) 0x96, (byte) 0x96, - (byte) 0x6D, (byte) 0x67, (byte) 0x0C, (byte) 0x35, (byte) 0x4E, (byte) 0x4A, (byte) 0xBC, (byte) 0x98, - (byte) 0x04, (byte) 0xF1, (byte) 0x74, (byte) 0x6C, (byte) 0x08, (byte) 0xCA, (byte) 0x18, (byte) 0x21, - (byte) 0x7C, (byte) 0x32, (byte) 0x90, (byte) 0x5E, (byte) 0x46, (byte) 0x2E, (byte) 0x36, (byte) 0xCE, - (byte) 0x3B, (byte) 0xE3, (byte) 0x9E, (byte) 0x77, (byte) 0x2C, (byte) 0x18, (byte) 0x0E, (byte) 0x86, - (byte) 0x03, (byte) 0x9B, (byte) 0x27, (byte) 0x83, (byte) 0xA2, (byte) 0xEC, (byte) 0x07, (byte) 0xA2, - (byte) 0x8F, (byte) 0xB5, (byte) 0xC5, (byte) 0x5D, (byte) 0xF0, (byte) 0x6F, (byte) 0x4C, (byte) 0x52, - (byte) 0xC9, (byte) 0xDE, (byte) 0x2B, (byte) 0xCB, (byte) 0xF6, (byte) 0x95, (byte) 0x58, (byte) 0x17, - (byte) 0x18, (byte) 0x39, (byte) 0x95, (byte) 0x49, (byte) 0x7C, (byte) 0xEA, (byte) 0x95, (byte) 0x6A, - (byte) 0xE5, (byte) 0x15, (byte) 0xD2, (byte) 0x26, (byte) 0x18, (byte) 0x98, (byte) 0xFA, (byte) 0x05, - (byte) 0x10, (byte) 0x15, (byte) 0x72, (byte) 0x8E, (byte) 0x5A, (byte) 0x8A, (byte) 0xAC, (byte) 0xAA, - (byte) 0x68, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, - (byte) 0xFF - }); - - public static BigInteger getG() { - return G; - } - - public static BigInteger getP1() { - return P1; - } - - public static BigInteger getP14() { - return P14; - } + public static final BigInteger P14 = + new BigInteger("3231700607131100730033891392642382824881794124114023911284200975140074170663435422" + + "2619689417363569347117901737909704191754605873209195028853758986185622153212175412" + + "5149017745202702357960782362488842461894775876411059286460994117232454266225221932" + + "3054091903768052423551912567971587011700105805587765103886184728025797605490356973" + + "2561526167081339361799541336476559160368317896729073178384589680639671900977202194" + + "1686472258710314113364293195361934716365332097170774482279885885653692086452966360" + + "7725026895550592836275112117409697299806841055435958486658329164213621823107899099" + + "9448652468262416972035911852507045361090559"); } diff --git a/src/main/java/net/schmizz/sshj/transport/kex/KeyExchange.java b/src/main/java/net/schmizz/sshj/transport/kex/KeyExchange.java index 0fd4c46a..09a78fde 100644 --- a/src/main/java/net/schmizz/sshj/transport/kex/KeyExchange.java +++ b/src/main/java/net/schmizz/sshj/transport/kex/KeyExchange.java @@ -41,6 +41,7 @@ import net.schmizz.sshj.transport.Transport; import net.schmizz.sshj.transport.TransportException; import net.schmizz.sshj.transport.digest.Digest; +import java.security.GeneralSecurityException; import java.security.PublicKey; /** Key exchange algorithm. */ @@ -55,14 +56,18 @@ public interface KeyExchange { * @param I_S the server key init packet * @param I_C the client key init packet * - * @throws TransportException if there is an error sending a packet + * @throws GeneralSecurityException + * @throws TransportException if there is an error sending a packet */ void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C) - throws TransportException; + throws GeneralSecurityException, TransportException; /** @return the computed H parameter */ byte[] getH(); + /** @return the computed K parameter */ + byte[] getK(); + /** * The message digest used by this key exchange algorithm. * @@ -73,9 +78,6 @@ public interface KeyExchange { /** @return the host key determined from server's response packets */ PublicKey getHostKey(); - /** @return the computed K parameter */ - byte[] getK(); - /** * Process the next packet * @@ -84,9 +86,10 @@ public interface KeyExchange { * * @return a boolean indicating if the processing is complete or if more packets are to be received * - * @throws TransportException if there is an error sending a packet + * @throws GeneralSecurityException + * @throws TransportException if there is an error sending a packet */ boolean next(Message msg, SSHPacket buffer) - throws TransportException; + throws GeneralSecurityException, TransportException; }