changed some things around, lesser conversions / copying. still not found the bug. grr.

This commit is contained in:
Shikhar Bhushan
2011-06-18 20:16:56 +01:00
parent 73fcc81e83
commit 8b61d96808
8 changed files with 66 additions and 103 deletions

View File

@@ -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()

View File

@@ -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());

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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;
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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.