mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 15:20:54 +03:00
changed some things around, lesser conversions / copying. still not found the bug. grr.
This commit is contained in:
@@ -341,41 +341,13 @@ public class Buffer<T extends Buffer<T>> {
|
|||||||
*/
|
*/
|
||||||
public BigInteger readMPInt()
|
public BigInteger readMPInt()
|
||||||
throws BufferException {
|
throws BufferException {
|
||||||
return new BigInteger(readMPIntAsBytes());
|
return new BigInteger(readBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an SSH multiple-precision integer from a {@code BigInteger}
|
|
||||||
*
|
|
||||||
* @param bi {@code BigInteger} to write
|
|
||||||
*
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public T putMPInt(BigInteger bi) {
|
public T putMPInt(BigInteger bi) {
|
||||||
return putMPInt(bi.toByteArray());
|
final byte[] asBytes = bi.toByteArray();
|
||||||
}
|
putUInt32(asBytes.length);
|
||||||
|
return putRawBytes(asBytes);
|
||||||
/**
|
|
||||||
* Writes an SSH multiple-precision integer from a Java byte-array
|
|
||||||
*
|
|
||||||
* @param foo byte-array
|
|
||||||
*
|
|
||||||
* @return this
|
|
||||||
*/
|
|
||||||
public T putMPInt(byte[] foo) {
|
|
||||||
int i = foo.length;
|
|
||||||
if ((foo[0] & 0x80) != 0) {
|
|
||||||
i++;
|
|
||||||
putUInt32(i);
|
|
||||||
putByte((byte) 0);
|
|
||||||
} else
|
|
||||||
putUInt32(i);
|
|
||||||
return putRawBytes(foo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] readMPIntAsBytes()
|
|
||||||
throws BufferException {
|
|
||||||
return readBytes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long readUInt64()
|
public long readUInt64()
|
||||||
|
|||||||
@@ -96,8 +96,6 @@ final class Encoder
|
|||||||
long encode(SSHPacket buffer) {
|
long encode(SSHPacket buffer) {
|
||||||
encodeLock.lock();
|
encodeLock.lock();
|
||||||
try {
|
try {
|
||||||
buffer = checkHeaderSpace(buffer);
|
|
||||||
|
|
||||||
if (log.isTraceEnabled())
|
if (log.isTraceEnabled())
|
||||||
log.trace("Encoding packet #{}: {}", seq, buffer.printHex());
|
log.trace("Encoding packet #{}: {}", seq, buffer.printHex());
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import net.schmizz.sshj.common.Buffer;
|
|||||||
import net.schmizz.sshj.common.DisconnectReason;
|
import net.schmizz.sshj.common.DisconnectReason;
|
||||||
import net.schmizz.sshj.common.ErrorNotifiable;
|
import net.schmizz.sshj.common.ErrorNotifiable;
|
||||||
import net.schmizz.sshj.common.Factory;
|
import net.schmizz.sshj.common.Factory;
|
||||||
import net.schmizz.sshj.common.IOUtils;
|
|
||||||
import net.schmizz.sshj.common.KeyType;
|
import net.schmizz.sshj.common.KeyType;
|
||||||
import net.schmizz.sshj.common.Message;
|
import net.schmizz.sshj.common.Message;
|
||||||
import net.schmizz.sshj.common.SSHException;
|
import net.schmizz.sshj.common.SSHException;
|
||||||
@@ -57,6 +56,7 @@ import net.schmizz.sshj.transport.verification.HostKeyVerifier;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -234,6 +234,7 @@ final class KeyExchanger
|
|||||||
|
|
||||||
private void gotKexInit(SSHPacket buf)
|
private void gotKexInit(SSHPacket buf)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
|
buf.rpos(buf.rpos() - 1);
|
||||||
final Proposal serverProposal = new Proposal(buf);
|
final Proposal serverProposal = new Proposal(buf);
|
||||||
negotiatedAlgs = clientProposal.negotiate(serverProposal);
|
negotiatedAlgs = clientProposal.negotiate(serverProposal);
|
||||||
log.debug("Negotiated algorithms: {}", negotiatedAlgs);
|
log.debug("Negotiated algorithms: {}", negotiatedAlgs);
|
||||||
@@ -241,10 +242,8 @@ final class KeyExchanger
|
|||||||
negotiatedAlgs.getKeyExchangeAlgorithm());
|
negotiatedAlgs.getKeyExchangeAlgorithm());
|
||||||
try {
|
try {
|
||||||
kex.init(transport,
|
kex.init(transport,
|
||||||
transport.getServerID().getBytes(IOUtils.UTF8),
|
transport.getServerID(), transport.getClientID(),
|
||||||
transport.getClientID().getBytes(IOUtils.UTF8),
|
serverProposal.getPacket().getCompactData(), clientProposal.getPacket().getCompactData());
|
||||||
buf.getCompactData(),
|
|
||||||
clientProposal.getPacket().getCompactData());
|
|
||||||
} catch (GeneralSecurityException e) {
|
} catch (GeneralSecurityException e) {
|
||||||
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e);
|
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED, e);
|
||||||
}
|
}
|
||||||
@@ -262,7 +261,7 @@ final class KeyExchanger
|
|||||||
*
|
*
|
||||||
* @return the resized key
|
* @return the resized key
|
||||||
*/
|
*/
|
||||||
private static byte[] resizedKey(byte[] E, int blockSize, Digest hash, byte[] K, byte[] H) {
|
private static byte[] resizedKey(byte[] E, int blockSize, Digest hash, BigInteger K, byte[] H) {
|
||||||
while (blockSize > E.length) {
|
while (blockSize > E.length) {
|
||||||
Buffer.PlainBuffer buffer = new Buffer.PlainBuffer().putMPInt(K).putRawBytes(H).putRawBytes(E);
|
Buffer.PlainBuffer buffer = new Buffer.PlainBuffer().putMPInt(K).putRawBytes(H).putRawBytes(E);
|
||||||
hash.update(buffer.array(), 0, buffer.available());
|
hash.update(buffer.array(), 0, buffer.available());
|
||||||
@@ -280,13 +279,15 @@ final class KeyExchanger
|
|||||||
private void gotNewKeys() {
|
private void gotNewKeys() {
|
||||||
final Digest hash = kex.getHash();
|
final Digest hash = kex.getHash();
|
||||||
|
|
||||||
|
final byte[] H = kex.getH();
|
||||||
|
|
||||||
if (sessionID == null)
|
if (sessionID == null)
|
||||||
// session id is 'H' from the first key exchange and does not change thereafter
|
// session id is 'H' from the first key exchange and does not change thereafter
|
||||||
sessionID = Arrays.copyOf(kex.getH(), kex.getH().length);
|
sessionID = H;
|
||||||
|
|
||||||
final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer()
|
final Buffer.PlainBuffer hashInput = new Buffer.PlainBuffer()
|
||||||
.putMPInt(kex.getK())
|
.putMPInt(kex.getK())
|
||||||
.putRawBytes(kex.getH())
|
.putRawBytes(H)
|
||||||
.putByte((byte) 0) // <placeholder>
|
.putByte((byte) 0) // <placeholder>
|
||||||
.putRawBytes(sessionID);
|
.putRawBytes(sessionID);
|
||||||
final int pos = hashInput.available() - sessionID.length - 1; // Position of <placeholder>
|
final int pos = hashInput.available() - sessionID.length - 1; // Position of <placeholder>
|
||||||
@@ -360,7 +361,6 @@ final class KeyExchanger
|
|||||||
* having sent the packet ourselves (would cause gotKexInit() to fail)
|
* having sent the packet ourselves (would cause gotKexInit() to fail)
|
||||||
*/
|
*/
|
||||||
kexInitSent.await(transport.getTimeout(), TimeUnit.SECONDS);
|
kexInitSent.await(transport.getTimeout(), TimeUnit.SECONDS);
|
||||||
buf.rpos(buf.rpos() - 1);
|
|
||||||
gotKexInit(buf);
|
gotKexInit(buf);
|
||||||
expected = Expected.FOLLOWUP;
|
expected = Expected.FOLLOWUP;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -65,16 +65,14 @@ public abstract class AbstractDHG
|
|||||||
|
|
||||||
private Transport trans;
|
private Transport trans;
|
||||||
|
|
||||||
private final Digest sha = new SHA1();
|
private final Digest sha1 = new SHA1();
|
||||||
private final DH dh = new DH();
|
private final DH dh = new DH();
|
||||||
|
|
||||||
private byte[] V_S;
|
private String V_S;
|
||||||
private byte[] V_C;
|
private String V_C;
|
||||||
private byte[] I_S;
|
private byte[] I_S;
|
||||||
private byte[] I_C;
|
private byte[] I_C;
|
||||||
|
|
||||||
private byte[] e;
|
|
||||||
private byte[] K;
|
|
||||||
private byte[] H;
|
private byte[] H;
|
||||||
private PublicKey hostKey;
|
private PublicKey hostKey;
|
||||||
|
|
||||||
@@ -84,13 +82,13 @@ public abstract class AbstractDHG
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getK() {
|
public BigInteger getK() {
|
||||||
return Arrays.copyOf(K, K.length);
|
return dh.getK();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Digest getHash() {
|
public Digest getHash() {
|
||||||
return sha;
|
return sha1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -99,19 +97,18 @@ public abstract class AbstractDHG
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Transport trans, byte[] V_S, byte[] V_C, byte[] I_S, byte[] I_C)
|
public void init(Transport trans, String V_S, String V_C, byte[] I_S, byte[] I_C)
|
||||||
throws GeneralSecurityException, TransportException {
|
throws GeneralSecurityException, TransportException {
|
||||||
this.trans = trans;
|
this.trans = trans;
|
||||||
this.V_S = Arrays.copyOf(V_S, V_S.length);
|
this.V_S = V_S;
|
||||||
this.V_C = Arrays.copyOf(V_C, V_C.length);
|
this.V_C = V_C;
|
||||||
this.I_S = Arrays.copyOf(I_S, I_S.length);
|
this.I_S = Arrays.copyOf(I_S, I_S.length);
|
||||||
this.I_C = Arrays.copyOf(I_C, I_C.length);
|
this.I_C = Arrays.copyOf(I_C, I_C.length);
|
||||||
sha.init();
|
sha1.init();
|
||||||
initDH(dh);
|
initDH(dh);
|
||||||
e = dh.getE();
|
|
||||||
|
|
||||||
log.info("Sending SSH_MSG_KEXDH_INIT");
|
log.info("Sending SSH_MSG_KEXDH_INIT");
|
||||||
trans.write(new SSHPacket(Message.KEXDH_INIT).putMPInt(e));
|
trans.write(new SSHPacket(Message.KEXDH_INIT).putMPInt(dh.getE()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -122,19 +119,18 @@ public abstract class AbstractDHG
|
|||||||
|
|
||||||
log.info("Received SSH_MSG_KEXDH_REPLY");
|
log.info("Received SSH_MSG_KEXDH_REPLY");
|
||||||
final byte[] K_S;
|
final byte[] K_S;
|
||||||
final byte[] f;
|
final BigInteger f;
|
||||||
final byte[] sig; // signature sent by server
|
final byte[] sig; // signature sent by server
|
||||||
try {
|
try {
|
||||||
K_S = packet.readBytes();
|
K_S = packet.readBytes();
|
||||||
f = packet.readMPIntAsBytes();
|
f = packet.readMPInt();
|
||||||
sig = packet.readBytes();
|
sig = packet.readBytes();
|
||||||
hostKey = new Buffer.PlainBuffer(K_S).readPublicKey();
|
hostKey = new Buffer.PlainBuffer(K_S).readPublicKey();
|
||||||
} catch (Buffer.BufferException be) {
|
} catch (Buffer.BufferException be) {
|
||||||
throw new TransportException(be);
|
throw new TransportException(be);
|
||||||
}
|
}
|
||||||
|
|
||||||
dh.setF(new BigInteger(f));
|
dh.computeK(f);
|
||||||
K = dh.getK();
|
|
||||||
|
|
||||||
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer()
|
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer()
|
||||||
.putString(V_C)
|
.putString(V_C)
|
||||||
@@ -142,11 +138,11 @@ public abstract class AbstractDHG
|
|||||||
.putString(I_C)
|
.putString(I_C)
|
||||||
.putString(I_S)
|
.putString(I_S)
|
||||||
.putString(K_S)
|
.putString(K_S)
|
||||||
.putMPInt(e)
|
.putMPInt(dh.getE())
|
||||||
.putMPInt(f)
|
.putMPInt(f)
|
||||||
.putMPInt(K);
|
.putMPInt(dh.getK());
|
||||||
sha.update(buf.array(), 0, buf.available());
|
sha1.update(buf.array(), buf.rpos(), buf.available());
|
||||||
H = sha.digest();
|
H = sha1.digest();
|
||||||
|
|
||||||
Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(),
|
Signature signature = Factory.Named.Util.create(trans.getConfig().getSignatureFactories(),
|
||||||
KeyType.fromKey(hostKey).toString());
|
KeyType.fromKey(hostKey).toString());
|
||||||
@@ -158,6 +154,7 @@ public abstract class AbstractDHG
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void initDH(DH dh);
|
protected abstract void initDH(DH dh)
|
||||||
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ public class DH {
|
|||||||
private BigInteger p;
|
private BigInteger p;
|
||||||
private BigInteger g;
|
private BigInteger g;
|
||||||
private BigInteger e; // my public key
|
private BigInteger e; // my public key
|
||||||
private BigInteger f; // your public key
|
|
||||||
private BigInteger K; // shared secret key
|
private BigInteger K; // shared secret key
|
||||||
private final KeyPairGenerator generator;
|
private final KeyPairGenerator generator;
|
||||||
private final KeyAgreement agreement;
|
private final KeyAgreement agreement;
|
||||||
@@ -68,39 +67,32 @@ public class DH {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setF(BigInteger f) {
|
public void init(BigInteger p, BigInteger g)
|
||||||
this.f = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setG(BigInteger g) {
|
|
||||||
this.g = g;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setP(BigInteger p) {
|
|
||||||
this.p = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getE()
|
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
if (e == null) {
|
this.p = p;
|
||||||
|
this.g = g;
|
||||||
generator.initialize(new DHParameterSpec(p, g));
|
generator.initialize(new DHParameterSpec(p, g));
|
||||||
final KeyPair kp = generator.generateKeyPair();
|
final KeyPair kp = generator.generateKeyPair();
|
||||||
agreement.init(kp.getPrivate());
|
agreement.init(kp.getPrivate());
|
||||||
e = ((javax.crypto.interfaces.DHPublicKey) kp.getPublic()).getY();
|
e = ((javax.crypto.interfaces.DHPublicKey) kp.getPublic()).getY();
|
||||||
}
|
|
||||||
return e.toByteArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getK()
|
public void computeK(BigInteger f)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
if (K == null) {
|
|
||||||
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DH");
|
final KeyFactory keyFactory = SecurityUtils.getKeyFactory("DH");
|
||||||
final DHPublicKeySpec keySpec = new DHPublicKeySpec(f, p, g);
|
final PublicKey yourPubKey = keyFactory.generatePublic(new DHPublicKeySpec(f, p, g));
|
||||||
final PublicKey yourPubKey = keyFactory.generatePublic(keySpec);
|
|
||||||
agreement.doPhase(yourPubKey, true);
|
agreement.doPhase(yourPubKey, true);
|
||||||
K = new BigInteger(agreement.generateSecret());
|
K = new BigInteger(agreement.generateSecret());
|
||||||
|
|
||||||
}
|
}
|
||||||
return K.toByteArray();
|
|
||||||
|
public BigInteger getE() {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getK() {
|
||||||
|
return K;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.transport.kex;
|
package net.schmizz.sshj.transport.kex;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Diffie-Hellman key exchange with SHA-1 and Oakley Group 2 [RFC2409] (1024-bit MODP Group).
|
* Diffie-Hellman key exchange with SHA-1 and Oakley Group 2 [RFC2409] (1024-bit MODP Group).
|
||||||
*
|
*
|
||||||
@@ -60,9 +62,9 @@ public class DHG1
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initDH(DH dh) {
|
protected void initDH(DH dh)
|
||||||
dh.setG(DHGroupData.G);
|
throws GeneralSecurityException {
|
||||||
dh.setP(DHGroupData.P1);
|
dh.init(DHGroupData.P1, DHGroupData.G);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
*/
|
*/
|
||||||
package net.schmizz.sshj.transport.kex;
|
package net.schmizz.sshj.transport.kex;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Diffie-Hellman key exchange with SHA-1 and Oakley Group 14 [RFC3526] (2048-bit MODP Group).
|
* Diffie-Hellman key exchange with SHA-1 and Oakley Group 14 [RFC3526] (2048-bit MODP Group).
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -61,9 +63,8 @@ public class DHG14
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initDH(DH dh) {
|
protected void initDH(DH dh) throws GeneralSecurityException {
|
||||||
dh.setG(DHGroupData.G);
|
dh.init(DHGroupData.P14, DHGroupData.G);
|
||||||
dh.setP(DHGroupData.P14);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import net.schmizz.sshj.transport.Transport;
|
|||||||
import net.schmizz.sshj.transport.TransportException;
|
import net.schmizz.sshj.transport.TransportException;
|
||||||
import net.schmizz.sshj.transport.digest.Digest;
|
import net.schmizz.sshj.transport.digest.Digest;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
@@ -59,14 +60,14 @@ public interface KeyExchange {
|
|||||||
* @throws GeneralSecurityException
|
* @throws GeneralSecurityException
|
||||||
* @throws TransportException if there is an error sending a packet
|
* @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)
|
void init(Transport trans, String V_S, String V_C, byte[] I_S, byte[] I_C)
|
||||||
throws GeneralSecurityException, TransportException;
|
throws GeneralSecurityException, TransportException;
|
||||||
|
|
||||||
/** @return the computed H parameter */
|
/** @return the computed H parameter */
|
||||||
byte[] getH();
|
byte[] getH();
|
||||||
|
|
||||||
/** @return the computed K parameter */
|
/** @return the computed K parameter */
|
||||||
byte[] getK();
|
BigInteger getK();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message digest used by this key exchange algorithm.
|
* The message digest used by this key exchange algorithm.
|
||||||
|
|||||||
Reference in New Issue
Block a user