📄 sshio.java
字号:
/* * This file is part of "The Java Telnet Application". * * (c) Matthias L. Jugel, Marcus Mei遪er 1996-2002. All Rights Reserved. * * Please visit http://javatelnet.org/ for updates and contact. * * --LICENSE NOTICE-- * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * --LICENSE NOTICE-- */package de.mud.ssh;import java.io.IOException;import java.math.BigInteger;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.SecureRandom;/** * Secure Shell IO * @author Marcus Meissner * @version $Id: SshIO.java,v 1.28 2002/10/26 19:52:44 marcus Exp $ */public abstract class SshIO { private static MessageDigest md5; static { try { md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { System.err.println("SshIO: unable to load message digest algorithm: "+e); e.printStackTrace(); } } /** * variables for the connection */ private String idstr = ""; //("SSH-<protocolmajor>.<protocolminor>-<version>\n") private String idstr_sent = "SSH/JTA (c) Marcus Meissner, Matthias L. Jugel\n"; /** * Debug level. This results in additional diagnostic messages on the * java console. */ private static int debug = 0; /** * State variable for Ssh negotiation reader */ private SshCrypto crypto = null; String cipher_type = "IDEA"; private int remotemajor, remoteminor; private int mymajor, myminor; private int useprotocol; private String login = "", password = ""; //nobody is to access those fields : better to use pivate, nobody knows :-) public String dataToSend = null; public String hashHostKey = null; // equals to the applet parameter if any byte lastPacketSentType; // phase : handleBytes private int phase = 0; private final int PHASE_INIT = 0; private final int PHASE_SSH_RECEIVE_PACKET = 1; // SSH v2 RSA BigInteger rsa_e, rsa_n; //handlePacket //messages // The supported packet types and the corresponding message numbers are // given in the following table. Messages with _MSG_ in their name may // be sent by either side. Messages with _CMSG_ are only sent by the // client, and messages with _SMSG_ only by the server. // private final byte SSH_MSG_DISCONNECT = 1; private final byte SSH_SMSG_PUBLIC_KEY = 2; private final byte SSH_CMSG_SESSION_KEY = 3; private final byte SSH_CMSG_USER = 4; private final byte SSH_CMSG_AUTH_PASSWORD = 9; private final byte SSH_CMSG_REQUEST_PTY = 10; private final byte SSH_CMSG_EXEC_SHELL = 12; private final byte SSH_SMSG_SUCCESS = 14; private final byte SSH_SMSG_FAILURE = 15; private final byte SSH_CMSG_STDIN_DATA = 16; private final byte SSH_SMSG_STDOUT_DATA = 17; private final byte SSH_SMSG_STDERR_DATA = 18; private final byte SSH_SMSG_EXITSTATUS = 20; private final byte SSH_MSG_IGNORE = 32; private final byte SSH_CMSG_EXIT_CONFIRMATION = 33; private final byte SSH_MSG_DEBUG = 36; /* SSH v2 stuff */ private final byte SSH2_MSG_DISCONNECT = 1; private final byte SSH2_MSG_IGNORE = 2; private final byte SSH2_MSG_SERVICE_REQUEST = 5; private final byte SSH2_MSG_SERVICE_ACCEPT = 6; private final byte SSH2_MSG_KEXINIT = 20; private final byte SSH2_MSG_NEWKEYS = 21; private final byte SSH2_MSG_KEXDH_INIT = 30; private final byte SSH2_MSG_KEXDH_REPLY = 31; private String kexalgs, hostkeyalgs, encalgs2c, encalgc2s, macalgs2c, macalgc2s, compalgc2s, compalgs2c, langc2s, langs2; private int outgoingseq = 0, incomingseq = 0; // // encryption types // private int SSH_CIPHER_NONE = 0; // No encryption private int SSH_CIPHER_IDEA = 1; // IDEA in CFB mode (patented) private int SSH_CIPHER_DES = 2; // DES in CBC mode private int SSH_CIPHER_3DES = 3; // Triple-DES in CBC mode private int SSH_CIPHER_TSS = 4; // An experimental stream cipher private int SSH_CIPHER_RC4 = 5; // RC4 (patented) private int SSH_CIPHER_BLOWFISH = 6; // Bruce Scheiers blowfish (public d) // // authentication methods // private final int SSH_AUTH_RHOSTS = 1; //.rhosts or /etc/hosts.equiv private final int SSH_AUTH_RSA = 2; //pure RSA authentication private final int SSH_AUTH_PASSWORD = 3; //password authentication, implemented ! private final int SSH_AUTH_RHOSTS_RSA = 4; //.rhosts with RSA host authentication private boolean cansenddata = false; /** * Initialise SshIO */ public SshIO() { crypto = null; } public void setLogin(String user) { if (user == null) user = ""; login = user; } public void setPassword(String password) { if (password == null) password = ""; this.password = password; } SshPacket currentpacket; protected abstract void write(byte[] buf) throws IOException; public abstract String getTerminalType(); byte[] one = new byte[1]; private void write(byte b) throws IOException { one[0] = b; write(one); } public void disconnect() { // System.err.println("In Disconnect"); login = ""; password = ""; phase = 0; crypto = null; } synchronized public void sendData(String str) throws IOException { if (debug > 1) System.out.println("SshIO.send(" + str + ")"); if (dataToSend == null) dataToSend = str; else dataToSend += str; if (cansenddata) { Send_SSH_CMSG_STDIN_DATA(dataToSend); dataToSend = null; } } /** * Read data from the remote host. Blocks until data is available. * * Returns an array of bytes that will be displayed. * */ public byte[] handleSSH(byte buff[]) throws IOException { byte[] rest; String result; if (debug > 1) System.out.println("SshIO.getPacket(" + buff + "," + buff.length + ")"); if (phase == PHASE_INIT) { byte b; // of course, byte is a signed entity (-128 -> 127) int boffset = 0; // offset into the buffer received while (boffset < buff.length) { b = buff[boffset++]; // both sides MUST send an identification string of the form // "SSH-protoversion-softwareversion comments", // followed by newline character(ascii 10 = '\n' or '\r') idstr += (char) b; if (b == '\n') { phase++; if (!idstr.substring(0, 4).equals("SSH-")) { System.out.println("Received invalid ID string: " + idstr + ", (substr " + idstr.substring(0, 4) + ")"); throw (new IOException()); } remotemajor = Integer.parseInt(idstr.substring(4, 5)); String minorverstr = idstr.substring(6, 8); if (!Character.isDigit(minorverstr.charAt(1))) minorverstr = minorverstr.substring(0, 1); remoteminor = Integer.parseInt(minorverstr); System.out.println("remotemajor " + remotemajor); System.out.println("remoteminor " + remoteminor); if (remotemajor == 2) { mymajor = 2; myminor = 0; useprotocol = 2; } else { if (false && (remoteminor == 99)) { mymajor = 2; myminor = 0; useprotocol = 2; } else { mymajor = 1; myminor = 5; useprotocol = 1; } } // this is how we tell the remote server what protocol we use. idstr_sent = "SSH-" + mymajor + "." + myminor + "-" + idstr_sent; write(idstr_sent.getBytes()); if (useprotocol == 2) currentpacket = new SshPacket2(null); else currentpacket = new SshPacket1(null); } } if (boffset == buff.length) return "".getBytes(); return "Must not have left over data after PHASE_INIT!\n".getBytes(); } result = ""; rest = currentpacket.addPayload(buff); if (currentpacket.isFinished()) { if (useprotocol == 1) { result = result + handlePacket1((SshPacket1) currentpacket); currentpacket = new SshPacket1(crypto); } else { result = result + handlePacket2((SshPacket2) currentpacket); currentpacket = new SshPacket2(crypto); } } while (rest != null) { rest = currentpacket.addPayload(rest); if (currentpacket.isFinished()) { // the packet is finished, otherwise we would not have got a rest if (useprotocol == 1) { result = result + handlePacket1((SshPacket1) currentpacket); currentpacket = new SshPacket1(crypto); } else { result = result + handlePacket2((SshPacket2) currentpacket); currentpacket = new SshPacket2(crypto); } } } return result.getBytes(); } /** * Handle SSH protocol Version 2 * * @param p the packet we will process here. * @return a array of bytes */ private String handlePacket2(SshPacket2 p) throws IOException { switch (p.getType()) { case SSH2_MSG_IGNORE: System.out.println("SSH2: SSH2_MSG_IGNORE"); break; case SSH2_MSG_DISCONNECT: int discreason = p.getInt32(); String discreason1 = p.getString(); /*String discreason2 = p.getString();*/ System.out.println("SSH2: SSH2_MSG_DISCONNECT(" + discreason + "," + discreason1 + "," + /*discreason2+*/")"); return "\nSSH2 disconnect: " + discreason1 + "\n"; case SSH2_MSG_NEWKEYS: { System.out.println("SSH2: SSH2_MSG_NEWKEYS"); sendPacket2(new SshPacket2(SSH2_MSG_NEWKEYS)); byte[] session_key = new byte[16]; crypto = new SshCrypto(cipher_type, session_key); SshPacket2 pn = new SshPacket2(SSH2_MSG_SERVICE_REQUEST); pn.putString("ssh-userauth"); sendPacket2(pn); break; } case SSH2_MSG_SERVICE_ACCEPT: { System.out.println("Service Accept: " + p.getString()); break; } case SSH2_MSG_KEXINIT: { byte[] fupp; System.out.println("SSH2: SSH2_MSG_KEXINIT"); byte kexcookie[] = p.getBytes(16); // unused. String kexalgs = p.getString(); System.out.println("- " + kexalgs); String hostkeyalgs = p.getString(); System.out.println("- " + hostkeyalgs); String encalgc2s = p.getString(); System.out.println("- " + encalgc2s); String encalgs2c = p.getString(); System.out.println("- " + encalgs2c); String macalgc2s = p.getString(); System.out.println("- " + macalgc2s); String macalgs2c = p.getString(); System.out.println("- " + macalgs2c); String compalgc2s = p.getString(); System.out.println("- " + compalgc2s); String compalgs2c = p.getString(); System.out.println("- " + compalgs2c); String langc2s = p.getString(); System.out.println("- " + langc2s); String langs2c = p.getString(); System.out.println("- " + langs2c); fupp = p.getBytes(1); System.out.println("- first_kex_follows: " + fupp[0]); /* int32 reserved (0) */ SshPacket2 pn = new SshPacket2(SSH2_MSG_KEXINIT); byte[] kexsend = new byte[16]; String ciphername; pn.putBytes(kexsend); pn.putString("diffie-hellman-group1-sha1"); pn.putString("ssh-rsa"); /* FIXME: check if it really is in the encalgc2s */ cipher_type = "NONE"; ciphername = "none"; /* FIXME: dito for HMAC */ pn.putString("none"); pn.putString("none"); pn.putString("hmac-md5"); pn.putString("hmac-md5"); pn.putString("none"); pn.putString("none"); pn.putString(""); pn.putString(""); pn.putByte((byte) 0); pn.putInt32(0); sendPacket2(pn); pn = new SshPacket2(SSH2_MSG_KEXDH_INIT); pn.putMpInt(BigInteger.valueOf(0xdeadbeef)); sendPacket2(pn); break; } case SSH2_MSG_KEXDH_REPLY: { String result; System.out.println("SSH2_MSG_KEXDH_REPLY"); int bloblen = p.getInt32(); System.out.println("bloblen is " + bloblen); /* the blob has a substructure: * String type * if RSA: * bignum1 * bignum2 * if DSA: * bignum1,2,3,4 */ String keytype = p.getString(); System.out.println("KEXDH: " + keytype); if (keytype.equals("ssh-rsa")) { rsa_e = p.getMpInt(); rsa_n = p.getMpInt(); result = "\n\rSSH-RSA (" + rsa_n + "," + rsa_e + ")\n\r"; } else { return "\n\rUnsupported kexdh algorithm " + keytype + "!\n\r"; } BigInteger dhserverpub = p.getMpInt(); result += "DH Server Pub: " + dhserverpub + "\n\r"; /* signature is a new blob, length is Int32. */ /* * RSA:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -