|
@@ -2,23 +2,21 @@ package de.tudarmstadt.informatik.hostage.protocol;
|
|
|
|
|
|
import java.math.BigInteger;
|
|
|
import java.nio.ByteBuffer;
|
|
|
-import java.security.KeyFactory;
|
|
|
-import java.security.KeyPair;
|
|
|
-import java.security.KeyPairGenerator;
|
|
|
-import java.security.MessageDigest;
|
|
|
-import java.security.PublicKey;
|
|
|
import java.security.SecureRandom;
|
|
|
-import java.security.Signature;
|
|
|
-import java.security.interfaces.DSAPublicKey;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
|
|
|
-import javax.crypto.KeyAgreement;
|
|
|
-import javax.crypto.interfaces.DHPublicKey;
|
|
|
-import javax.crypto.spec.DHParameterSpec;
|
|
|
-import javax.crypto.spec.DHPublicKeySpec;
|
|
|
-
|
|
|
import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.crypto.KeyMaterial;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.crypto.PEMDecoder;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.crypto.cipher.CBCMode;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.crypto.cipher.DESede;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.crypto.dh.DhExchange;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.crypto.digest.MAC;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.signature.DSAPrivateKey;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.signature.DSASHA1Verify;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.signature.DSASignature;
|
|
|
+import de.tudarmstadt.informatik.hostage.ssh.util.TypesWriter;
|
|
|
import de.tudarmstadt.informatik.hostage.wrapper.Packet;
|
|
|
|
|
|
/**
|
|
@@ -34,82 +32,100 @@ public class SSH implements Protocol {
|
|
|
SERVER_VERSION,
|
|
|
CLIENT_VERSION,
|
|
|
KEX_INIT,
|
|
|
+ USERAUTH,
|
|
|
+ CONNECTION,
|
|
|
+ CHANNEL,
|
|
|
+ LOOP, // TODO for debugging
|
|
|
CLOSED
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Denotes in which state the protocol is right now.
|
|
|
*/
|
|
|
- private STATE connectionState = STATE.NONE;
|
|
|
-
|
|
|
- /** Denotes in which state the protocol is right now */
|
|
|
private STATE state = STATE.NONE;
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+ @Override
|
|
|
public int getPort() {
|
|
|
return 22;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ @Override
|
|
|
public TALK_FIRST whoTalksFirst() {
|
|
|
return TALK_FIRST.SERVER;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ @Override
|
|
|
public List<Packet> processMessage(Packet packet) {
|
|
|
List<Packet> response = new ArrayList<Packet>();
|
|
|
byte[] request = null;
|
|
|
if(packet != null) {
|
|
|
request = packet.getMessage();
|
|
|
}
|
|
|
-
|
|
|
- switch(connectionState) {
|
|
|
+ switch(state) {
|
|
|
case NONE:
|
|
|
response.add(new Packet(serverVersion + serverType + "\r\n"));
|
|
|
- connectionState = STATE.SERVER_VERSION;
|
|
|
+ state = STATE.SERVER_VERSION;
|
|
|
break;
|
|
|
case SERVER_VERSION:
|
|
|
extractType(request);
|
|
|
- extractCookie(request);
|
|
|
+ extractPayload(request);
|
|
|
response.add(kexInit());
|
|
|
- connectionState = STATE.CLIENT_VERSION;
|
|
|
+ state = STATE.CLIENT_VERSION;
|
|
|
break;
|
|
|
case CLIENT_VERSION:
|
|
|
extractPubKey(request);
|
|
|
response.add(dhKexReply());
|
|
|
- //FIXME signature in dhKexReply seems to be wrong
|
|
|
response.add(newKeys());
|
|
|
- connectionState = STATE.KEX_INIT;
|
|
|
+ state = STATE.KEX_INIT;
|
|
|
break;
|
|
|
case KEX_INIT:
|
|
|
- connectionState = STATE.CLOSED;
|
|
|
+ response.add(serviceReply(request));
|
|
|
+ state = STATE.USERAUTH;
|
|
|
+ break;
|
|
|
+ case USERAUTH:
|
|
|
+ response.add(userauthReply(request));
|
|
|
+ state = STATE.CONNECTION;
|
|
|
+ break;
|
|
|
+ case CONNECTION:
|
|
|
+ response.add(channelOpenReply(request));
|
|
|
+ state = STATE.CHANNEL;
|
|
|
+ break;
|
|
|
+ case CHANNEL:
|
|
|
+ response.add(channelSuccessReply(request));
|
|
|
+ response.add(data(request));
|
|
|
+ state = STATE.LOOP;
|
|
|
+ break;
|
|
|
+ case LOOP:
|
|
|
+ decryptPacket(request);
|
|
|
+ response.add(data(request));
|
|
|
+ state = STATE.LOOP;
|
|
|
break;
|
|
|
case CLOSED:
|
|
|
break;
|
|
|
default:
|
|
|
- connectionState = STATE.CLOSED;
|
|
|
+ state = STATE.CLOSED;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
return response;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ @Override
|
|
|
public boolean isClosed() {
|
|
|
return (state == STATE.CLOSED);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ @Override
|
|
|
public boolean isSecure() {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ @Override
|
|
|
public Class<byte[]> getType() {
|
|
|
return byte[].class;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ @Override
|
|
|
public String toString() {
|
|
|
return "SSH";
|
|
|
}
|
|
@@ -119,7 +135,7 @@ public class SSH implements Protocol {
|
|
|
* @param packet content that is wrapped.
|
|
|
* @return wrapped packet.
|
|
|
*/
|
|
|
- private Packet wrapPacket(byte[] packet) {
|
|
|
+ private Packet wrapPacket(byte[] packet, boolean encrypt) {
|
|
|
int packetLength = 5 + packet.length; //4 byte packet length, 1 byte padding length, payload length
|
|
|
int paddingLengthCBS = cipherBlockSize - (packetLength % cipherBlockSize);
|
|
|
int paddingLength8 = 8 - (packetLength % 8);
|
|
@@ -134,7 +150,37 @@ public class SSH implements Protocol {
|
|
|
SecureRandom rndm = new SecureRandom();
|
|
|
paddingString[i] = (byte) rndm.nextInt(255);
|
|
|
}
|
|
|
- return new Packet(HelperUtils.concat(packetLen, paddingLen, packet, paddingString));
|
|
|
+ byte[] response = HelperUtils.concat(packetLen, paddingLen, packet, paddingString);
|
|
|
+ if(encrypt) {
|
|
|
+ byte[] mac = new byte[20];
|
|
|
+ macEnc.initMac(send_packet_number);
|
|
|
+ macEnc.update(response, 0, response.length);
|
|
|
+ macEnc.getMac(mac, 0);
|
|
|
+
|
|
|
+ byte[] responseEnc = new byte[response.length];
|
|
|
+ for(int i = 0; i < response.length; i+=8) {
|
|
|
+ cbcEnc.transformBlock(response, i, responseEnc, i);
|
|
|
+ }
|
|
|
+ response = HelperUtils.concat(responseEnc,mac);
|
|
|
+ }
|
|
|
+ send_packet_number++;
|
|
|
+
|
|
|
+ return new Packet(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ private byte[] decryptPacket(byte[] request) {
|
|
|
+ byte[] message = new byte[request.length - ((request.length % 8 == 0) ? 0 : 20)];
|
|
|
+ for(int i = 0; i < message.length; i += 8) { // -12 wegen MAC
|
|
|
+ cbcDec.transformBlock(request, i, message, i);
|
|
|
+ }
|
|
|
+ System.out.println("Encrypted packet:");
|
|
|
+ System.out.println(HelperUtils.bytesToHexString(request));
|
|
|
+ System.out.println("\nDecrypted packet:");
|
|
|
+ System.out.println(HelperUtils.bytesToHexString(message));
|
|
|
+ System.out.println("\nDecrypted string packet:");
|
|
|
+ System.out.println(HelperUtils.byteToStr(message));
|
|
|
+ System.out.println();
|
|
|
+ return message;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -143,7 +189,7 @@ public class SSH implements Protocol {
|
|
|
*/
|
|
|
private Packet kexInit() {
|
|
|
byte[] msgCode = {0x14};
|
|
|
- I_S = randomBytes(16);
|
|
|
+ byte[] cookie = HelperUtils.randomBytes(16);
|
|
|
byte[] kexLength = ByteBuffer.allocate(4).putInt(kex_alg.getBytes().length).array();
|
|
|
byte[] serverLength = ByteBuffer.allocate(4).putInt(server_alg.getBytes().length).array();
|
|
|
byte[] encrypt_c_Length = ByteBuffer.allocate(4).putInt(encrypt_alg_c.getBytes().length).array();
|
|
@@ -157,11 +203,12 @@ public class SSH implements Protocol {
|
|
|
byte[] kexFirsPckt = {0x00};
|
|
|
byte[] reserved = {0x00, 0x00, 0x00, 0x00};
|
|
|
|
|
|
- byte[] response = HelperUtils.concat(msgCode, I_S, kexLength, kex_alg.getBytes(), serverLength, server_alg.getBytes(),
|
|
|
+ byte[] response = HelperUtils.concat(msgCode, cookie, kexLength, kex_alg.getBytes(), serverLength, server_alg.getBytes(),
|
|
|
encrypt_c_Length, encrypt_alg_c.getBytes(), encrypt_s_Length, encrypt_alg_s.getBytes(), mac_c_Length, mac_alg_c.getBytes(),
|
|
|
mac_s_Length, mac_alg_s.getBytes(), comp_c_Length, comp_alg_c.getBytes(), comp_s_Length, comp_alg_s.getBytes(),
|
|
|
language_c_s, language_s_c, kexFirsPckt, reserved);
|
|
|
- return wrapPacket(response);
|
|
|
+ I_S = response;
|
|
|
+ return wrapPacket(response, false);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -169,126 +216,123 @@ public class SSH implements Protocol {
|
|
|
* @return Diffie-Hellman Kex Reply packet.
|
|
|
*/
|
|
|
private Packet dhKexReply() {
|
|
|
- generateDHKeys();
|
|
|
- generateHostKey();
|
|
|
- generateSha1Hash();
|
|
|
- generateSignature();
|
|
|
- byte[] msgCode = {0x1f};
|
|
|
- byte[] hostKeyLength = ByteBuffer.allocate(4).putInt(K_S.length).array();
|
|
|
- byte[] fDHLength = ByteBuffer.allocate(4).putInt(f.length).array();
|
|
|
- byte[] signatureLength = ByteBuffer.allocate(4).putInt(sig.length).array();
|
|
|
- byte[] server_algLength = ByteBuffer.allocate(4).putInt(server_alg.getBytes().length).array();
|
|
|
- byte[] payloadLength = ByteBuffer.allocate(4).putInt(server_algLength.length + signatureLength.length + sig.length + server_alg.getBytes().length).array();
|
|
|
- byte[] response = HelperUtils.concat(msgCode, hostKeyLength, K_S,
|
|
|
- fDHLength, f, payloadLength, server_algLength, server_alg.getBytes(), signatureLength, sig);
|
|
|
- return wrapPacket(response);
|
|
|
+ //TODO make it small
|
|
|
+ try {
|
|
|
+ SecureRandom rnd = new SecureRandom();
|
|
|
+ DhExchange dhx = new DhExchange();
|
|
|
+ dhx.serverInit(1, rnd);
|
|
|
+ dhx.setE(new BigInteger(e));
|
|
|
+ f = dhx.getF();
|
|
|
+ DSAPrivateKey dsa = (DSAPrivateKey) PEMDecoder.decode(dsa_pem, null);
|
|
|
+ K_S = DSASHA1Verify.encodeSSHDSAPublicKey(dsa.getPublicKey());
|
|
|
+ h = dhx.calculateH(V_C, V_S, I_C, I_S, K_S);
|
|
|
+ k = dhx.getK();
|
|
|
+ DSASignature ds = DSASHA1Verify.generateSignature(h, dsa, rnd);
|
|
|
+ sig = DSASHA1Verify.encodeSSHDSASignature(ds);
|
|
|
+ TypesWriter tw = new TypesWriter();
|
|
|
+ tw.writeByte(31);
|
|
|
+ tw.writeString(K_S, 0, K_S.length);
|
|
|
+ tw.writeMPInt(f);
|
|
|
+ tw.writeString(sig, 0, sig.length);
|
|
|
+ byte[] response = tw.getBytes();
|
|
|
+
|
|
|
+ //init for decryption and encryption
|
|
|
+ KeyMaterial km = KeyMaterial.create("SHA1", h, k, h, 24, 8, 20, 24, 8, 20); // alg, h, k, keylength, blocklength, maclength, keylength, blocklength, maclength
|
|
|
+ enc = new DESede();
|
|
|
+ dec = new DESede();
|
|
|
+ enc.init(true, km.enc_key_server_to_client);
|
|
|
+ dec.init(false, km.enc_key_client_to_server);
|
|
|
+ cbcEnc = new CBCMode(enc, km.initial_iv_server_to_client, true);
|
|
|
+ cbcDec = new CBCMode(dec, km.initial_iv_client_to_server, false);
|
|
|
+ macEnc = new MAC("hmac-sha1", km.integrity_key_server_to_client);
|
|
|
+ macDec = new MAC("hmac-sha1", km.integrity_key_client_to_server);
|
|
|
+
|
|
|
+ return wrapPacket(response, false);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return wrapPacket(null, false);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
* New Keys response.
|
|
|
* @return New Keys response.
|
|
|
*/
|
|
|
private Packet newKeys() {
|
|
|
byte[] msgCode = {0x15};
|
|
|
- return wrapPacket(msgCode);
|
|
|
+ return wrapPacket(msgCode, false);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Generates the required Diffie-Hellman keys with p and g from Oakley Group 1.
|
|
|
- */
|
|
|
- private void generateDHKeys() {
|
|
|
- try {
|
|
|
- KeyPairGenerator myKpairGen = KeyPairGenerator.getInstance("DH");
|
|
|
- KeyAgreement myKeyAgree = KeyAgreement.getInstance("DH");
|
|
|
- BigInteger p = new BigInteger(this.p);
|
|
|
- BigInteger g = new BigInteger(this.g);
|
|
|
- BigInteger e = new BigInteger(this.e);
|
|
|
-
|
|
|
- DHParameterSpec dhParamSpec = new DHParameterSpec(p, g);
|
|
|
- myKpairGen.initialize(dhParamSpec);
|
|
|
- KeyPair myKpair = myKpairGen.generateKeyPair();
|
|
|
- myKeyAgree.init(myKpair.getPrivate());
|
|
|
- BigInteger f = ((DHPublicKey) (myKpair.getPublic())).getY();
|
|
|
- this.f = f.toByteArray();
|
|
|
-
|
|
|
- KeyFactory myKeyFac = KeyFactory.getInstance("DH");
|
|
|
- DHPublicKeySpec keySpec = new DHPublicKeySpec(e, p, g);
|
|
|
- PublicKey yourPubKey = myKeyFac.generatePublic(keySpec);
|
|
|
- myKeyAgree.doPhase(yourPubKey, true);
|
|
|
- byte[] mySharedSecret = myKeyAgree.generateSecret();
|
|
|
- k = mySharedSecret;
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
+ // TODO
|
|
|
+ private Packet serviceReply(byte[] request) {
|
|
|
+ byte[] messageBuf;
|
|
|
+ if(request[5] == 0x15) { //if newkeys request is included in the same packet
|
|
|
+ messageBuf = new byte[request.length - 16];
|
|
|
+ System.arraycopy(request, 16, messageBuf, 0, request.length-16);
|
|
|
+ } else {
|
|
|
+ messageBuf = request;
|
|
|
}
|
|
|
+ byte[] message = decryptPacket(messageBuf);
|
|
|
+
|
|
|
+ if (message[5] != 0x05 && message[9] != 0x0c) {
|
|
|
+ // TODO disconnect because its not servicerequest ssh-userauth
|
|
|
+ }
|
|
|
+ byte[] msgcode = {0x06};
|
|
|
+ byte[] serviceLength;
|
|
|
+ byte[] service = "ssh-userauth".getBytes();
|
|
|
+ serviceLength = ByteBuffer.allocate(4).putInt(service.length).array();
|
|
|
+
|
|
|
+ byte[] response = HelperUtils.concat(msgcode, serviceLength, service);
|
|
|
+ return wrapPacket(response, true);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Generates the Host Key based on the DSA algorithm
|
|
|
- */
|
|
|
- private void generateHostKey() {
|
|
|
- try {
|
|
|
- KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
|
|
|
- dsa = generator.generateKeyPair();
|
|
|
-
|
|
|
- byte[] string = "ssh-dss".getBytes();
|
|
|
- byte[] stringLength = ByteBuffer.allocate(4).putInt(string.length).array();
|
|
|
-
|
|
|
- byte[] p = ((DSAPublicKey) dsa.getPublic()).getParams().getP().toByteArray();
|
|
|
- if(p[0] != 0x00) p = HelperUtils.concat(new byte[]{0x00}, p);
|
|
|
- byte[] pLength = ByteBuffer.allocate(4).putInt(p.length).array();
|
|
|
-
|
|
|
- byte[] q = ((DSAPublicKey) dsa.getPublic()).getParams().getQ().toByteArray();
|
|
|
- if(q[0] != 0x00) q = HelperUtils.concat(new byte[]{0x00}, q);
|
|
|
- byte[] qLength = ByteBuffer.allocate(4).putInt(q.length).array();
|
|
|
-
|
|
|
- byte[] g = ((DSAPublicKey) dsa.getPublic()).getParams().getG().toByteArray();
|
|
|
- if(g[0] != 0x00) g = HelperUtils.concat(new byte[]{0x00}, g);
|
|
|
- byte[] gLength = ByteBuffer.allocate(4).putInt(g.length).array();
|
|
|
-
|
|
|
- byte[] y = ((DSAPublicKey) dsa.getPublic()).getY().toByteArray();
|
|
|
- if(y[0] != 0x00) y = HelperUtils.concat(new byte[]{0x00}, y);
|
|
|
- byte[] yLength = ByteBuffer.allocate(4).putInt(y.length).array();
|
|
|
-
|
|
|
- K_S = HelperUtils.concat(stringLength, string, pLength, p, qLength, q, gLength, g, yLength, y);
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
+ // TODO
|
|
|
+ private Packet userauthReply(byte[] request) {
|
|
|
+ byte[] message = decryptPacket(request);
|
|
|
+ if (message[5] != 0x32) {
|
|
|
+ // TODO disconnect because its not servicerequest ssh-connect
|
|
|
+ }
|
|
|
+ byte[] msgcode = {0x34};
|
|
|
+ byte[] response = msgcode;
|
|
|
+
|
|
|
+ return wrapPacket(response, true);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Generates the SHA-1 Hash from several values
|
|
|
- */
|
|
|
- private void generateSha1Hash() {
|
|
|
- try {
|
|
|
- MessageDigest sha = MessageDigest.getInstance("SHA-1");
|
|
|
- sha.update(V_C);
|
|
|
- sha.update(V_S);
|
|
|
- sha.update(I_C);
|
|
|
- sha.update(I_S);
|
|
|
- sha.update(K_S);
|
|
|
- sha.update(e);
|
|
|
- sha.update(f);
|
|
|
- sha.update(k);
|
|
|
- h = sha.digest();
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
+ // TODO
|
|
|
+ private Packet channelOpenReply(byte[] request) {
|
|
|
+ byte[] message = decryptPacket(request);
|
|
|
+ // TODO if contains "session" ok else disc
|
|
|
+ byte[] msgcode = {0x5b};
|
|
|
+ recipientChannel = new byte[4];
|
|
|
+ byte[] senderChannel = new byte[4];
|
|
|
+ byte[] initialWindowSize = new byte[4];
|
|
|
+ byte[] maximumPacketSize = new byte[4];
|
|
|
+ System.arraycopy(message, 17, recipientChannel, 0, 4); //TODO dynamic position
|
|
|
+ System.arraycopy(message, 17, senderChannel, 0, 4);
|
|
|
+ System.arraycopy(message, 21, initialWindowSize, 0, 4);
|
|
|
+ System.arraycopy(message, 25, maximumPacketSize, 0, 4);
|
|
|
+ byte[] response = HelperUtils.concat(msgcode, recipientChannel, senderChannel, initialWindowSize, maximumPacketSize);
|
|
|
+ System.out.println("CHANNEL REPLY:");
|
|
|
+ System.out.println(HelperUtils.bytesToHexString(response));
|
|
|
+ return wrapPacket(response, true);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Generates the signature of the hash using DSA algorithm with SHA-1
|
|
|
- */
|
|
|
- private void generateSignature() {
|
|
|
- //FIXME something is wrong with this signature.. maybe one of the used components is generated wrong?!
|
|
|
- try {
|
|
|
- Signature sig = Signature.getInstance("SHA1withDSA");
|
|
|
- sig.initVerify(dsa.getPublic());
|
|
|
- sig.initSign(dsa.getPrivate());
|
|
|
- sig.update(h);
|
|
|
- this.sig = extractSignature(sig.sign());
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- }
|
|
|
+ byte[] recipientChannel; //TODO
|
|
|
+ private Packet channelSuccessReply(byte[] request) {
|
|
|
+ decryptPacket(request);
|
|
|
+ byte[] msgcode = {0x63}; //TODO check msg type
|
|
|
+ byte[] response = HelperUtils.concat(msgcode, recipientChannel);
|
|
|
+ System.out.println(HelperUtils.bytesToHexString(response));
|
|
|
+ return wrapPacket(response, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Packet data(byte[] request) {
|
|
|
+ byte[] msgcode = {0x5E};
|
|
|
+ byte[] msglength = new byte[4];
|
|
|
+ byte[] msg = "lolol".getBytes();
|
|
|
+ msglength = ByteBuffer.allocate(4).putInt(msg.length).array();
|
|
|
+ byte[] response = HelperUtils.concat(msgcode, recipientChannel, msglength, msg);
|
|
|
+ return wrapPacket(response, true);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -297,27 +341,32 @@ public class SSH implements Protocol {
|
|
|
*/
|
|
|
private void extractType(byte[] request) {
|
|
|
int length = 0;
|
|
|
- for(int i = 8; i < request.length; i++, length++) { //start at 8 because "SSH-2.0-" is not part of type
|
|
|
+ for(int i = 0; i < request.length; i++, length++) {
|
|
|
if(request[i] == 0x0d) break; //find the end of the type: '\r'
|
|
|
}
|
|
|
V_C = new byte[length];
|
|
|
- System.arraycopy(request, 8, V_C, 0, length);
|
|
|
+ System.arraycopy(request, 0, V_C, 0, length);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Extracts the cookie from the Kex Init client request
|
|
|
- * @param request containing the clients cookie
|
|
|
+ * Extracts the payload of a packet and writes it in I_C.
|
|
|
+ * @param request packet of which the payload is extracted.
|
|
|
*/
|
|
|
- private void extractCookie(byte[] request) {
|
|
|
+ private void extractPayload(byte[] request) {
|
|
|
int pos = 0;
|
|
|
- if(request[5] != 0x14) { //if type packet is in front of kex init
|
|
|
- pos = 1; //start behind the end of type message
|
|
|
+ if(request[5] != 0x14) {
|
|
|
+ pos = 1;
|
|
|
for(int i = 0; i < request.length; i++, pos++) {
|
|
|
- if(request[i] == 0x0a) break; //find end of type message: '\n'
|
|
|
+ if(request[i] == 0xa) break;
|
|
|
}
|
|
|
}
|
|
|
- I_C = new byte[16];
|
|
|
- System.arraycopy(request, 6+pos, I_C, 0, 16); //srcLen: headersize+position after type packet
|
|
|
+ int packetLength = byteToInt(new byte[]{request[pos], request[1+pos], request[2+pos], request[3+pos]});
|
|
|
+ int paddingLength = byteToInt(new byte[]{request[4+pos]});
|
|
|
+ byte[] payload = new byte[packetLength - paddingLength - 1];
|
|
|
+ for(int i = 5; i < packetLength - paddingLength - 1; i++) {
|
|
|
+ payload[i-5] = request[i+pos];
|
|
|
+ }
|
|
|
+ I_C = payload;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -345,98 +394,53 @@ public class SSH implements Protocol {
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Generates a random byte[] of a specified size
|
|
|
- * @param size of the byte[]
|
|
|
- * @return random byte[]
|
|
|
- */
|
|
|
- private byte[] randomBytes(int size) {
|
|
|
- byte[] bytes = new byte[size];
|
|
|
- SecureRandom rdm = new SecureRandom();
|
|
|
- rdm.nextBytes(bytes);
|
|
|
- return bytes;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Extracts r and s from a DSA-signature
|
|
|
- * @param signature
|
|
|
- * @return r and s as byte[]
|
|
|
- */
|
|
|
- private byte[] extractSignature(byte[] signature) {
|
|
|
- int length = 0;
|
|
|
- int index = 3;
|
|
|
- length = signature[index++] & 0xff;
|
|
|
- byte[] r = new byte[length];
|
|
|
- System.arraycopy(signature, index, r, 0, r.length);
|
|
|
- index = index + length + 1;
|
|
|
- length = signature[index++] & 0xff;
|
|
|
- byte[] s = new byte[length];
|
|
|
- System.arraycopy(signature, index, s, 0, s.length);
|
|
|
- byte[] result = new byte[40];
|
|
|
- // result must be 40 bytes, but r and s may be longer than 20
|
|
|
- System.arraycopy(r,
|
|
|
- (r.length > 20) ? 1 : 0,
|
|
|
- result,
|
|
|
- (r.length > 20) ? 0 : 20 - r.length,
|
|
|
- (r.length > 20) ? 20 : r.length);
|
|
|
- System.arraycopy(s,
|
|
|
- (s.length > 20) ? 1 : 0,
|
|
|
- result,
|
|
|
- (s.length > 20) ? 20 : 40 - s.length,
|
|
|
- (s.length > 20) ? 20 : s.length);
|
|
|
- return result;
|
|
|
- }
|
|
|
-
|
|
|
private String serverVersion = ProtocolSettings.getSshVersion();
|
|
|
private String serverType = ProtocolSettings.getSshType();
|
|
|
-
|
|
|
- //Diffie-Hellman-Group-1 p and g
|
|
|
- private final byte[] p = {
|
|
|
- (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
|
|
|
- };
|
|
|
- private final byte[] g = {0x02};
|
|
|
+ private int send_packet_number = 0;
|
|
|
|
|
|
//SSH Parameters for Kex etc.
|
|
|
- private byte[] V_S = serverType.getBytes();
|
|
|
+ private byte[] V_S = (serverVersion + serverType).getBytes();
|
|
|
private byte[] V_C;
|
|
|
private byte[] I_S;
|
|
|
private byte[] I_C;
|
|
|
private byte[] e;
|
|
|
- private byte[] f;
|
|
|
- private byte[] k;
|
|
|
+ private BigInteger f;
|
|
|
private byte[] h;
|
|
|
+ private BigInteger k;
|
|
|
private byte[] K_S;
|
|
|
private byte[] sig;
|
|
|
-
|
|
|
- //Keys for signature
|
|
|
- private KeyPair dsa;
|
|
|
|
|
|
//allowed algorithms for kexinit
|
|
|
private String kex_alg = "diffie-hellman-group1-sha1";
|
|
|
private String server_alg = "ssh-dss";
|
|
|
- private String encrypt_alg_c = "aes128-ctr";
|
|
|
- private String encrypt_alg_s = "aes128-ctr";
|
|
|
+ private String encrypt_alg_c = "3des-cbc";
|
|
|
+ private String encrypt_alg_s = "3des-cbc";
|
|
|
private String mac_alg_c = "hmac-sha1";
|
|
|
private String mac_alg_s = "hmac-sha1";
|
|
|
private String comp_alg_c = "none";
|
|
|
private String comp_alg_s = "none";
|
|
|
|
|
|
private int cipherBlockSize = 16;
|
|
|
+
|
|
|
+ DESede enc;
|
|
|
+ DESede dec;
|
|
|
+ CBCMode cbcEnc;
|
|
|
+ CBCMode cbcDec;
|
|
|
+ MAC macEnc;
|
|
|
+ MAC macDec;
|
|
|
+
|
|
|
+ //dsa private key
|
|
|
+ private final char[] dsa_pem = ("-----BEGIN DSA PRIVATE KEY-----\n" +
|
|
|
+ "MIIBugIBAAKBgQCDZ9R2vfCPwjv5vKF1igIv9drrZ7G0dhMkGT9AZTjgI34Qm4w0\n" +
|
|
|
+ "0iWeCqO7SmqiaMIjbRIm91MeDed4ObAq4sAkqRE/2P4mTbzFx5KhEczRRiDoqQBX\n" +
|
|
|
+ "xYa0yWKJpeZ94SGM6DEPuBTxKo0T4uMjbq2FzHL2FXT1/WoNCmRU6gFSiwIVAMK4\n" +
|
|
|
+ "Epz3JiwDUbkSpLOjIqtEhJmVAoGAL6zlXRI4Q8iwvSDh0vDf1j9a5Aaaq+93LTjK\n" +
|
|
|
+ "SwL4nvUWBl2Aa0vqu05ZS5rOD1I+/naLMg0fNgFJRhA03sl+12MI3a2HXJWXRSdj\n" +
|
|
|
+ "m1Vq9cUXqiYrX6+iGfEaA/y9UO4ZPF6if6eLypXB8VuqjtjDCiMMsM6+qQki7L71\n" +
|
|
|
+ "yN4M75ICgYAcFXUhN2zRug3JvwmGxW8gMgHquSiBnbx1582KGh2B/ukE/kOrbKYD\n" +
|
|
|
+ "HUkBzolcm4x1Odq5apowlriFxY6zMQP615plIK4x9NaU6dvc/HoTkjzT5EYSMN39\n" +
|
|
|
+ "eAGufJ0jrtIpKL4lP8o8yrAHfmbR7bjecWc0viTH0+OWlyVsex/bZAIUEKn310Li\n" +
|
|
|
+ "v62Zs4hlDvhwvx8MQ+A=\n" +
|
|
|
+ "-----END DSA PRIVATE KEY-----").toCharArray();
|
|
|
|
|
|
}
|