5776634 [rkeene@sledge /home/rkeene/archive/floydssh/ssh]$ cat -n SshIO.java
  1 /*
  2  * This file is part of "The Java Telnet Application".
  3  *
  4  * (c) Matthias L. Jugel, Marcus Meißner 1996-2002. All Rights Reserved.
  5  * The file was changed by Radek Polak to work as midlet in MIDP 1.0
  6  *
  7  * Please visit http://javatelnet.org/ for updates and contact.
  8  *
  9  * --LICENSE NOTICE--
 10  * This program is free software; you can redistribute it and/or
 11  * modify it under the terms of the GNU General Public License
 12  * as published by the Free Software Foundation; either version 2
 13  * of the License, or (at your option) any later version.
 14  *
 15  * This program is distributed in the hope that it will be useful,
 16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18  * GNU General Public License for more details.
 19  *
 20  * You should have received a copy of the GNU General Public License
 21  * along with this program; if not, write to the Free Software
 22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 23  * --LICENSE NOTICE--
 24  */
 25 
 26 package ssh;
 27 
 28 import telnet.Telnet;
 29 import java.io.IOException;
 30 
 31 /**
 32  * Secure Shell IO
 33  * @author Marcus Meissner
 34  * @version $Id: SshIO.java,v 1.27 2002/10/26 19:06:30 marcus Exp $
 35  */
 36 public class SshIO {
 37 
 38   private static MD5 md5 = new MD5();
 39 
 40   /**
 41    * variables for the connection
 42    */
 43   private String idstr = ""; //("SSH-<protocolmajor>.<protocolminor>-<version>\n")
 44   private String idstr_sent = "SSH/JTA (c) Marcus Meissner, Matthias L. Jugel\n";
 45 
 46   /**
 47    * Debug level. This results in additional diagnostic messages on the
 48    * java console.
 49    */
 50 //  private static int debug = 0;
 51 
 52   /**
 53    * State variable for Ssh negotiation reader
 54    */
 55   private SshCrypto crypto = null;
 56 
 57   String cipher_type;// = "IDEA";
 58   public static java.util.Random rnd = new java.util.Random();
 59 
 60   private int remotemajor, remoteminor;
 61   private int mymajor, myminor;
 62   private int useprotocol;
 63 
 64   public String login, password;
 65   //nobody is to access those fields  : better to use pivate, nobody knows :-)
 66 
 67   public String dataToSend = null;
 68 
 69   public String hashHostKey = null;  // equals to the applet parameter if any
 70 
 71   byte lastPacketSentType;
 72 
 73 
 74   // phase : handleBytes
 75   private int phase = 0;
 76   private final int PHASE_INIT = 0;
 77   private final int PHASE_SSH_RECEIVE_PACKET = 1;
 78 
 79 
 80   // SSH v2 RSA
 81   BigInteger rsa_e, rsa_n;
 82 
 83   //handlePacket
 84   //messages
 85   //  The supported packet types and the corresponding message numbers are
 86   //    given in the following table.  Messages with _MSG_ in their name may
 87   //    be sent by either side.  Messages with _CMSG_ are only sent by the
 88   //  client, and messages with _SMSG_ only by the server.
 89   //
 90   private final byte SSH_MSG_DISCONNECT = 1;
 91   private final byte SSH_SMSG_PUBLIC_KEY = 2;
 92   private final byte SSH_CMSG_SESSION_KEY = 3;
 93   private final byte SSH_CMSG_USER = 4;
 94   private final byte SSH_CMSG_AUTH_PASSWORD = 9;
 95   private final byte SSH_CMSG_REQUEST_PTY = 10;
 96   private final byte SSH_CMSG_EXEC_SHELL = 12;
 97   private final byte SSH_SMSG_SUCCESS = 14;
 98   private final byte SSH_SMSG_FAILURE = 15;
 99   private final byte SSH_CMSG_STDIN_DATA = 16;
100   private final byte SSH_SMSG_STDOUT_DATA = 17;
101   private final byte SSH_SMSG_STDERR_DATA = 18;
102   private final byte SSH_SMSG_EXITSTATUS = 20;
103   private final byte SSH_MSG_IGNORE = 32;
104   private final byte SSH_CMSG_EXIT_CONFIRMATION = 33;
105   private final byte SSH_MSG_DEBUG = 36;
106 
107 
108   /* SSH v2 stuff */
109 
110   private final byte SSH2_MSG_DISCONNECT = 1;
111   private final byte SSH2_MSG_IGNORE = 2;
112   private final byte SSH2_MSG_SERVICE_REQUEST = 5;
113   private final byte SSH2_MSG_SERVICE_ACCEPT = 6;
114 
115   private final byte SSH2_MSG_KEXINIT = 20;
116   private final byte SSH2_MSG_NEWKEYS = 21;
117 
118   private final byte SSH2_MSG_KEXDH_INIT = 30;
119   private final byte SSH2_MSG_KEXDH_REPLY = 31;
120 
121   private String kexalgs, hostkeyalgs, encalgs2c, encalgc2s, macalgs2c, macalgc2s, compalgc2s, compalgs2c, langc2s,
	langs2;
122 
123   private int outgoingseq = 0, incomingseq = 0;
124 
125   //
126   // encryption types
127   //
128   private int SSH_CIPHER_NONE = 0;   // No encryption
129   private int SSH_CIPHER_IDEA = 1;  // IDEA in CFB mode     (patented)
130   private int SSH_CIPHER_DES = 2;  // DES in CBC mode
131   private int SSH_CIPHER_3DES = 3;  // Triple-DES in CBC mode
132   private int SSH_CIPHER_TSS = 4;  // An experimental stream cipher
133 
134   private int SSH_CIPHER_RC4 = 5;  // RC4           (patented)
135 
136   private int SSH_CIPHER_BLOWFISH = 6;  // Bruce Scheiers blowfish (public d)
137 
138 
139   //
140   // authentication methods
141   //
142   private final int SSH_AUTH_RHOSTS = 1;   //.rhosts or /etc/hosts.equiv
143   private final int SSH_AUTH_RSA = 2;   //pure RSA authentication
144   private final int SSH_AUTH_PASSWORD = 3;   //password authentication, implemented !
145   private final int SSH_AUTH_RHOSTS_RSA = 4;   //.rhosts with RSA host authentication
146 
147 
148   private boolean cansenddata = false;
149 
150   /**
151    * Initialise SshIO
152    */
153   public SshIO() {
154     crypto = null;
155   }
156 
157   SshPacket currentpacket;
158 
159   /** write data to our back end */
160   public void write(byte[] b) throws IOException {
161     if( Telnet.outputCount + b.length > Telnet.output.length )
162     {
163       byte[] newOutput = new byte[Telnet.outputCount+b.length];
164       System.arraycopy( Telnet.output, 0, newOutput, 0, Telnet.outputCount );
165       Telnet.output = newOutput;
166     }
167     System.arraycopy(b, 0, Telnet.output, Telnet.outputCount, b.length);
168     Telnet.outputCount += b.length;
169   }
170 
171   byte[] one = new byte[1];
172 
173   private void write(byte b) throws IOException {
174     one[0] = b;
175     write(one);
176   }
177 
178   public void disconnect() {
179     login = "";
180     password = "";
181     phase = 0;
182     crypto = null;
183   }
184 
185   synchronized public void sendData(String str) throws IOException {
186 //    if (debug > 1) System.out.println("SshIO.send(" + str + ")");
187     if (dataToSend == null)
188       dataToSend = str;
189     else
190       dataToSend += str;
191     if (cansenddata) {
192       Send_SSH_CMSG_STDIN_DATA(dataToSend);
193       dataToSend = null;
194     }
195   }
196 
197   /**
198    * Read data from the remote host. Blocks until data is available.
199    *
200    * Returns an array of bytes that will be displayed.
201    *
202    */
203   public byte[] handleSSH(byte buff[])
204     throws IOException {
205     byte[] rest;
206     String result;
207 
208  //  if (debug > 1)
209 //     Telnet.console.append("SshIO.getPacket(" + buff + "," + buff.length + ")");
210 
211 
212     if (phase == PHASE_INIT) {
213       byte b;       // of course, byte is a signed entity (-128 -> 127)
214       int boffset = 0;  // offset into the buffer received
215 
216       while (boffset < buff.length) {
217         b = buff[boffset++];
218         // both sides MUST send an identification string of the form
219         // "SSH-protoversion-softwareversion comments",
220         // followed by newline character(ascii 10 = '\n' or '\r')
221         idstr += (char) b;
222         if (b == '\n') {
223           phase++;
224 //          if (!idstr.substring(0, 4).equals("SSH-")) {
225 //            System.out.println("Received invalid ID string: " + idstr + ", (substr " + idstr.substring(0, 4) + ")");
226 //            throw (new IOException());
227 //          }
228           remotemajor = Integer.parseInt(idstr.substring(4, 5));
229           String minorverstr = idstr.substring(6, 8);
230           if (!Character.isDigit(minorverstr.charAt(1)))
231             minorverstr = minorverstr.substring(0, 1);
232           remoteminor = Integer.parseInt(minorverstr);
233 
234   //        System.out.println("remotemajor " + remotemajor);
235 //          System.out.println("remoteminor " + remoteminor);
236 
237           if (remotemajor == 2) {
238             mymajor = 2;
239             myminor = 0;
240             useprotocol = 2;
241           } else {
242             if (false && (remoteminor == 99)) {
243               mymajor = 2;
244               myminor = 0;
245               useprotocol = 2;
246             } else {
247               mymajor = 1;
248               myminor = 5;
249               useprotocol = 1;
250             }
251           }
252           // this is how we tell the remote server what protocol we use.
253           idstr_sent = "SSH-" + mymajor + "." + myminor + "-" + idstr_sent;
254           write(idstr_sent.getBytes());
255 
256           if (useprotocol == 2)
257             currentpacket = new SshPacket2(null);
258           else
259             currentpacket = new SshPacket1(null);
260         }
261       }
262       if (boffset == buff.length)
263         return "".getBytes();
264       return "Must not have left over data after PHASE_INIT!\n".getBytes();
265     }
266 
267     result = "";
268     rest = currentpacket.addPayload(buff);
269     if (currentpacket.isFinished()) {
270       if (useprotocol == 1) {
271         result = result + handlePacket1((SshPacket1) currentpacket);
272         currentpacket = new SshPacket1(crypto);
273       } else {
274         result = result + handlePacket2((SshPacket2) currentpacket);
275         currentpacket = new SshPacket2(crypto);
276       }
277     }
278     while (rest != null) {
279       rest = currentpacket.addPayload(rest);
280       if (currentpacket.isFinished()) {
281         // the packet is finished, otherwise we would not have got a rest
282         if (useprotocol == 1) {
283           result = result + handlePacket1((SshPacket1) currentpacket);
284           currentpacket = new SshPacket1(crypto);
285         } else {
286           result = result + handlePacket2((SshPacket2) currentpacket);
287           currentpacket = new SshPacket2(crypto);
288         }
289       }
290     }
291     return result.getBytes();
292   }
293 
294   /**
295    * Handle SSH protocol Version 2
296    *
297    * @param p the packet we will process here.
298    * @return a array of bytes
299    */
300   private String handlePacket2(SshPacket2 p)
301     throws IOException {
302     switch (p.getType()) {
303       case SSH2_MSG_IGNORE:
304 //        System.out.println("SSH2: SSH2_MSG_IGNORE");
305         break;
306       case SSH2_MSG_DISCONNECT:
307         int discreason = p.getInt32();
308         String discreason1 = p.getString();
309         /*String discreason2 = p.getString();*/
310 //        System.out.println("SSH2: SSH2_MSG_DISCONNECT(" + discreason + "," + discreason1 + "," + /*discreason2+*/")");
311 
312         return "\nSSH2 disconnect: " + discreason1 + "\n";
313 
314       case SSH2_MSG_NEWKEYS:
315         {
316 //          System.out.println("SSH2: SSH2_MSG_NEWKEYS");
317           sendPacket2(new SshPacket2(SSH2_MSG_NEWKEYS));
318 
319           byte[] session_key = new byte[16];
320 
321           crypto = new SshCrypto(cipher_type, session_key);
322 
323           SshPacket2 pn = new SshPacket2(SSH2_MSG_SERVICE_REQUEST);
324           pn.putString("ssh-userauth");
325           sendPacket2(pn);
326           break;
327         }
328       case SSH2_MSG_SERVICE_ACCEPT:
329         {
330 //          System.out.println("Service Accept: " + p.getString());
331           break;
332         }
333       case SSH2_MSG_KEXINIT:
334         {
335           byte[] fupp;
336 //          System.out.println("SSH2: SSH2_MSG_KEXINIT");
337           byte kexcookie[] = p.getBytes(16); // unused.
338 
339           String kexalgs = p.getString();
340 //          System.out.println("- " + kexalgs);
341           String hostkeyalgs = p.getString();
342 //          System.out.println("- " + hostkeyalgs);
343           String encalgc2s = p.getString();
344 //          System.out.println("- " + encalgc2s);
345           String encalgs2c = p.getString();
346 //          System.out.println("- " + encalgs2c);
347           String macalgc2s = p.getString();
348 //          System.out.println("- " + macalgc2s);
349           String macalgs2c = p.getString();
350 //          System.out.println("- " + macalgs2c);
351           String compalgc2s = p.getString();
352 //          System.out.println("- " + compalgc2s);
353           String compalgs2c = p.getString();
354 //          System.out.println("- " + compalgs2c);
355           String langc2s = p.getString();
356 //          System.out.println("- " + langc2s);
357           String langs2c = p.getString();
358 //          System.out.println("- " + langs2c);
359           fupp = p.getBytes(1);
360 //          System.out.println("- first_kex_follows: " + fupp[0]);
361           /* int32 reserved (0) */
362 
363           SshPacket2 pn = new SshPacket2(SSH2_MSG_KEXINIT);
364           byte[] kexsend = new byte[16];
365           String ciphername;
366           pn.putBytes(kexsend);
367           pn.putString("diffie-hellman-group1-sha1");
368           pn.putString("ssh-rsa");
369 
370           /* FIXME: check if it really is in the encalgc2s */
371           cipher_type = "NONE";
372           ciphername = "none";
373 
374           /* FIXME: dito for HMAC */
375 
376           pn.putString("none");
377           pn.putString("none");
378           pn.putString("hmac-md5");
379           pn.putString("hmac-md5");
380           pn.putString("none");
381           pn.putString("none");
382           pn.putString("");
383           pn.putString("");
384           pn.putByte((byte) 0);
385           pn.putInt32(0);
386           sendPacket2(pn);
387 
388           pn = new SshPacket2(SSH2_MSG_KEXDH_INIT);
389           pn.putMpInt(BigInteger.valueOf(0xdeadbeef));
390           sendPacket2(pn);
391           break;
392         }
393       case SSH2_MSG_KEXDH_REPLY:
394         {
395           String result;
396 
397 //          System.out.println("SSH2_MSG_KEXDH_REPLY");
398           int bloblen = p.getInt32();
399 //          System.out.println("bloblen is " + bloblen);
400           /* the blob has a substructure:
401            *    String type
402            *    if RSA:
403            *        bignum1
404            *        bignum2
405            *    if DSA:
406            *        bignum1,2,3,4
407            */
408           String keytype = p.getString();
409 //          System.out.println("KEXDH: " + keytype);
410           if (keytype.equals("ssh-rsa")) {
411             rsa_e = p.getMpInt();
412             rsa_n = p.getMpInt();
413             result = "\n\rSSH-RSA (" + rsa_n + "," + rsa_e + ")\n\r";
414           } else {
415             return "\n\rUnsupported kexdh algorithm " + keytype + "!\n\r";
416           }
417           BigInteger dhserverpub = p.getMpInt();
418           result += "DH Server Pub: " + dhserverpub + "\n\r";
419 
420           /* signature is a new blob, length is Int32. */
421           /*
422            * RSA:
423            *    String      type (ssh-rsa)
424            *    Int32/byte[]    signed signature
425            */
426           int siglen = p.getInt32();
427           String sigstr = p.getString();
428           result += "Signature: ktype is " + sigstr + "\r\n";
429           byte sigdata[] = p.getBytes(p.getInt32());
430 
431           return result;
432         }
433       default:
434         return "SSH2: handlePacket2 Unknown type " + p.getType();
435     }
436     return "";
437   }
438 
439 
440   private String handlePacket1(SshPacket1 p)
441     throws IOException { //the message to handle is data and its length is
442 
443     byte b;         // of course, byte is a signed entity (-128 -> 127)
444 
445     //we have to deal with data....
446 
447 //    if (debug > 0)
448 //      System.out.println("1 packet to handle, type " + p.getType());
449 
450 
451     switch (p.getType()) {
452       case SSH_MSG_IGNORE:
453         return "";
454 
455       case SSH_MSG_DISCONNECT:
456         String str = p.getString();
457         disconnect();
458         return str;
459 
460       case SSH_SMSG_PUBLIC_KEY:
461         byte[] anti_spoofing_cookie;            //8 bytes
462         byte[] server_key_bits;             //32-bit int
463         byte[] server_key_public_exponent;      //mp-int
464         byte[] server_key_public_modulus;           //mp-int
465         byte[] host_key_bits;               //32-bit int
466         byte[] host_key_public_exponent;            //mp-int
467         byte[] host_key_public_modulus;         //mp-int
468         byte[] protocol_flags;              //32-bit int
469         byte[] supported_ciphers_mask;          //32-bit int
470         byte[] supported_authentications_mask;      //32-bit int
471 
472         anti_spoofing_cookie = p.getBytes(8);
473         server_key_bits = p.getBytes(4);
474         server_key_public_exponent = p.getMpInt();
475         server_key_public_modulus = p.getMpInt();
476         host_key_bits = p.getBytes(4);
477         host_key_public_exponent = p.getMpInt();
478         host_key_public_modulus = p.getMpInt();
479         protocol_flags = p.getBytes(4);
480         supported_ciphers_mask = p.getBytes(4);
481         supported_authentications_mask = p.getBytes(4);
482 
483         // We have completely received the PUBLIC_KEY
484         // We prepare the answer ...
485 
486         String ret = Send_SSH_CMSG_SESSION_KEY(
487           anti_spoofing_cookie, server_key_public_modulus,
488           host_key_public_modulus, supported_ciphers_mask,
489           server_key_public_exponent, host_key_public_exponent
490         );
491         if (ret != null)
492           return ret;
493 
494         // we check if MD5(server_key_public_exponent) is equals to the
495         // applet parameter if any .
496         if (hashHostKey != null && hashHostKey.compareTo("") != 0) {
497           // we compute hashHostKeyBis the hash value in hexa of
498           // host_key_public_modulus
499           byte[] Md5_hostKey = md5.digest(host_key_public_modulus);
500           String hashHostKeyBis = "";
501           for (int i = 0; i < Md5_hostKey.length; i++) {
502             String hex = "";
503             int[] v = new int[2];
504             v[0] = (Md5_hostKey[i] & 240) >> 4;
505             v[1] = (Md5_hostKey[i] & 15);
506             for (int j = 0; j < 1; j++)
507               switch (v[j]) {
508                 case 10:
509                   hex += "a";
510                   break;
511                 case 11:
512                   hex += "b";
513                   break;
514                 case 12:
515                   hex += "c";
516                   break;
517                 case 13:
518                   hex += "d";
519                   break;
520                 case 14:
521                   hex += "e";
522                   break;
523                 case 15:
524                   hex += "f";
525                   break;
526                 default :
527                   hex += String.valueOf(v[j]);
528                   break;
529               }
530             hashHostKeyBis = hashHostKeyBis + hex;
531           }
532           //we compare the 2 values
533           if (hashHostKeyBis.compareTo(hashHostKey) != 0) {
534             login = password = "";
535             return "\nHash value of the host key not correct \r\n";
536 //              + "login & password have been reset \r\n"
537 //              + "- erase the 'hashHostKey' parameter in the Html\r\n"
538 //              + "(it is used for auhentificating the server and "
539 //              + "prevent you from connecting \r\n"
540 //              + "to any other)\r\n";
541           }
542         }
543         break;
544 
545       case SSH_SMSG_SUCCESS:
546 //        if (debug > 0)
547 //          System.out.println("SSH_SMSG_SUCCESS (last packet was " + lastPacketSentType + ")");
548         if (lastPacketSentType == SSH_CMSG_SESSION_KEY) {
549           //we have succefully sent the session key !! (at last :-) )
550           Send_SSH_CMSG_USER();
551           break;
552         }
553 
554         if (lastPacketSentType == SSH_CMSG_USER) {
555           // authentication is NOT needed for this user
556           Send_SSH_CMSG_REQUEST_PTY(); //request a pseudo-terminal
557           return "\nEmpty password login.\r\n";
558         }
559 
560         if (lastPacketSentType == SSH_CMSG_AUTH_PASSWORD) {// password correct !!!
561           //yahoo
562 //          if (debug > 0)
563 //            System.out.println("login succesful");
564 
565           //now we have to start the interactive session ...
566           Send_SSH_CMSG_REQUEST_PTY(); //request a pseudo-terminal
567           return "\nLogin & password accepted\r\n";
568         }
569 
570         if (lastPacketSentType == SSH_CMSG_REQUEST_PTY) {// pty accepted !!
571           /* we can send data with a pty accepted ... no need for a shell. */
572           cansenddata = true;
573           if (dataToSend != null) {
574             Send_SSH_CMSG_STDIN_DATA(dataToSend);
575             dataToSend = null;
576           }
577           Send_SSH_CMSG_EXEC_SHELL(); //we start a shell
578           break;
579         }
580         if (lastPacketSentType == SSH_CMSG_EXEC_SHELL) {// shell is running ...
581           /* empty */
582         }
583 
584         break;
585 
586       case SSH_SMSG_FAILURE:
587         if (lastPacketSentType == SSH_CMSG_AUTH_PASSWORD) {// password incorrect ???
588 //          System.out.println("failed to log in");
589           disconnect();
590           return "\nLogin & password not accepted\r\n";
591         }
592         if (lastPacketSentType == SSH_CMSG_USER) {
593           // authentication is needed for the given user
594           // (in most cases that's true)
595           Send_SSH_CMSG_AUTH_PASSWORD();
596           break;
597         }
598 
599         if (lastPacketSentType == SSH_CMSG_REQUEST_PTY) {// pty not accepted !!
600           break;
601         }
602         break;
603 
604       case SSH_SMSG_STDOUT_DATA: //receive some data from the server
605         return p.getString();
606 
607       case SSH_SMSG_STDERR_DATA: //receive some error data from the server
608         //  if(debug > 1)
609         str = "Error : " + p.getString();
610 //        System.out.println("SshIO.handlePacket : " + "STDERR_DATA " + str);
611         return str;
612 
613       case SSH_SMSG_EXITSTATUS: //sent by the server to indicate that
614         // the client program has terminated.
615         //32-bit int   exit status of the command
616         int value = p.getInt32();
617         Send_SSH_CMSG_EXIT_CONFIRMATION();
618 //        System.out.println("SshIO : Exit status " + value);
619         disconnect();
620         break;
621 
622       case SSH_MSG_DEBUG:
623         str = p.getString();
624 //        if (debug > 0) {
625 //          System.out.println("SshIO.handlePacket : " + " DEBUG " + str);
626 
627           // bad bad bad bad bad. We should not do actions in DEBUG messages,
628           // but apparently some SSH demons does not send SSH_SMSG_FAILURE for
629           // just USER CMS.
630 /*
631       if(lastPacketSentType==SSH_CMSG_USER) {
632         Send_SSH_CMSG_AUTH_PASSWORD();
633         break;
634       }
635 */
636 //          return str;
637   //      }
638         return "";
639 
640       default:
641 //        System.err.print("SshIO.handlePacket1: Packet Type unknown: " + p.getType());
642         break;
643 
644     }// switch(b)
645     return "";
646   } // handlePacket
647 
648   private void sendPacket1(SshPacket1 packet) throws IOException {
649     write(packet.getPayLoad(crypto));
650     lastPacketSentType = packet.getType();
651   }
652 
653   private void sendPacket2(SshPacket2 packet) throws IOException {
654     write(packet.getPayLoad(crypto, outgoingseq));
655     outgoingseq++;
656     lastPacketSentType = packet.getType();
657   }
658 
659   //
660   // Send_SSH_CMSG_SESSION_KEY
661   // Create :
662   // the session_id,
663   // the session_key,
664   // the Xored session_key,
665   // the double_encrypted session key
666   // send SSH_CMSG_SESSION_KEY
667   // Turn the encryption on (initialise the block cipher)
668   //
669 
670   private String Send_SSH_CMSG_SESSION_KEY(byte[] anti_spoofing_cookie,
671                                            byte[] server_key_public_modulus,
672                                            byte[] host_key_public_modulus,
673                                            byte[] supported_ciphers_mask,
674                                            byte[] server_key_public_exponent,
675                                            byte[] host_key_public_exponent)
676     throws IOException {
677 
678     String str;
679     int boffset;
680 
681     byte cipher_types;      //encryption types
682     byte[] session_key;     //mp-int
683 
684     // create the session id
685     //  session_id = md5(hostkey->n || servkey->n || cookie) //protocol V 1.5. (we use this one)
686     //  session_id = md5(servkey->n || hostkey->n || cookie) //protocol V 1.1.(Why is it different ??)
687     //
688 
689     byte[] session_id_byte = new byte[host_key_public_modulus.length + server_key_public_modulus.length +
	anti_spoofing_cookie.length];
690 
691     System.arraycopy(host_key_public_modulus, 0, session_id_byte, 0, host_key_public_modulus.length);
692     System.arraycopy(server_key_public_modulus, 0, session_id_byte, host_key_public_modulus.length,
	server_key_public_modulus.length);
693     System.arraycopy(anti_spoofing_cookie, 0, session_id_byte, host_key_public_modulus.length +
	server_key_public_modulus.length, anti_spoofing_cookie.length);
694 
695     byte[] hash_md5 = md5.digest(session_id_byte);
696 
697 
698     //  SSH_CMSG_SESSION_KEY : Sent by the client
699     //      1 byte       cipher_type (must be one of the supported values)
700     //      8 bytes      anti_spoofing_cookie (must match data sent by the server)
701     //      mp-int       double-encrypted session key (uses the session-id)
702     //      32-bit int   protocol_flags
703     //
704     if ((supported_ciphers_mask[3] & (byte) (1 << SSH_CIPHER_BLOWFISH)) != 0) {
705       cipher_types = (byte) SSH_CIPHER_BLOWFISH;
706       cipher_type = "Blowfish";
707     } else {
708       if ((supported_ciphers_mask[3] & (1 << SSH_CIPHER_IDEA)) != 0) {
709         cipher_types = (byte) SSH_CIPHER_IDEA;
710         cipher_type = "IDEA";
711       } else {
712         if ((supported_ciphers_mask[3] & (1 << SSH_CIPHER_3DES)) != 0) {
713           cipher_types = (byte) SSH_CIPHER_3DES;
714           cipher_type = "DES3";
715         } else {
716           if ((supported_ciphers_mask[3] & (1 << SSH_CIPHER_DES)) != 0) {
717             cipher_types = (byte) SSH_CIPHER_DES;
718             cipher_type = "DES";
719           } else {
720 //            System.err.println("SshIO: remote server does not supported IDEA, BlowFish or 3DES, support cypher mask is
	" + supported_ciphers_mask[3] + ".\n");
721             disconnect();
722             return "\rRemote server does not support IDEA/Blowfish/3DES blockcipher, closing connection.\r\n";
723           }
724         }
725       }
726     }
727 //    if (debug > 0)
728 //      System.out.println("SshIO: Using " + cipher_type + " blockcipher.\n");
729 
730 
731     //  anti_spoofing_cookie : the same
732     //      double_encrypted_session_key :
733     //      32 bytes of random bits
734     //      Xor the 16 first bytes with the session-id
735     //      encrypt with the server_key_public (small) then the host_key_public(big) using RSA.
736     //
737 
738     //32 bytes of random bits
739     byte[] random_bits1 = new byte[16], random_bits2 = new byte[16];
740 
741 
742     /// java.util.Date date = new java.util.Date(); ////the number of milliseconds since January 1, 1970, 00:00:00 GMT.
743     //Math.random()   a pseudorandom double between 0.0 and 1.0.
744     random_bits2 = random_bits1 =
745       // md5.hash("" + Math.random() * (new java.util.Date()).getDate());
746       md5.digest(("" + rnd.nextLong() * (new java.util.Date()).getTime()).getBytes()); // RADEK - zase RANDOM
747 
748     random_bits1 = md5.digest(SshMisc.addArrayOfBytes(md5.digest((password + login).getBytes()),
749                                                       random_bits1));
750     random_bits2 = md5.digest(SshMisc.addArrayOfBytes(md5.digest((password + login).getBytes()),
751                                                       random_bits2));
752 
753     // SecureRandom random = new java.security.SecureRandom(random_bits1); //no supported by netscape :-(
754     // random.nextBytes(random_bits1);
755     // random.nextBytes(random_bits2);
756 
757     session_key = SshMisc.addArrayOfBytes(random_bits1, random_bits2);
758 
759     //Xor the 16 first bytes with the session-id
760     byte[] session_keyXored = SshMisc.XORArrayOfBytes(random_bits1, hash_md5);
761     session_keyXored = SshMisc.addArrayOfBytes(session_keyXored, random_bits2);
762 
763     //We encrypt now!!
764     byte[] encrypted_session_key =
765       SshCrypto.encrypteRSAPkcs1Twice(session_keyXored,
766                                       server_key_public_exponent,
767                                       server_key_public_modulus,
768                                       host_key_public_exponent,
769                                       host_key_public_modulus);
770 
771     //  protocol_flags :protocol extension   cf. page 18
772     int protocol_flags = 0; /* currently 0 */
773 
774     SshPacket1 packet = new SshPacket1(SSH_CMSG_SESSION_KEY);
775     packet.putByte((byte) cipher_types);
776     packet.putBytes(anti_spoofing_cookie);
777     packet.putBytes(encrypted_session_key);
778     packet.putInt32(protocol_flags);
779     sendPacket1(packet);
780     crypto = new SshCrypto(cipher_type, session_key);
781     return "";
782   }
783 
784   /**
785    * SSH_CMSG_USER
786    * string   user login name on server
787    */
788   private String Send_SSH_CMSG_USER() throws IOException {
789 //    if (debug > 0) System.err.println("Send_SSH_CMSG_USER(" + login + ")");
790 
791     SshPacket1 p = new SshPacket1(SSH_CMSG_USER);
792     p.putString(login);
793     sendPacket1(p);
794 
795     return "";
796   }
797 
798   /**
799    * Send_SSH_CMSG_AUTH_PASSWORD
800    * string   user password
801    */
802   private String Send_SSH_CMSG_AUTH_PASSWORD() throws IOException {
803     SshPacket1 p = new SshPacket1(SSH_CMSG_AUTH_PASSWORD);
804     p.putString(password);
805     sendPacket1(p);
806     return "";
807   }
808 
809   /**
810    * Send_SSH_CMSG_EXEC_SHELL
811    *  (no arguments)
812    *   Starts a shell (command interpreter), and enters interactive
813    *   session mode.
814    */
815   private String Send_SSH_CMSG_EXEC_SHELL() throws IOException {
816     SshPacket1 packet = new SshPacket1(SSH_CMSG_EXEC_SHELL);
817     sendPacket1(packet);
818     return "";
819   }
820 
821   /**
822    * Send_SSH_CMSG_STDIN_DATA
823    *
824    */
825   private String Send_SSH_CMSG_STDIN_DATA(String str) throws IOException {
826     SshPacket1 packet = new SshPacket1(SSH_CMSG_STDIN_DATA);
827     packet.putString(str);
828     sendPacket1(packet);
829     return "";
830   }
831 
832   /**
833    * Send_SSH_CMSG_REQUEST_PTY
834    *   string       TERM environment variable value (e.g. vt100)
835    *   32-bit int   terminal height, rows (e.g., 24)
836    *   32-bit int   terminal width, columns (e.g., 80)
837    *   32-bit int   terminal width, pixels (0 if no graphics) (e.g., 480)
838    */
839   private String Send_SSH_CMSG_REQUEST_PTY() throws IOException {
840     SshPacket1 p = new SshPacket1(SSH_CMSG_REQUEST_PTY);
841 
842     p.putString(Telnet.emulation.getTerminalID());
843     p.putInt32(Telnet.emulation.height);    // Int32    rows
844     p.putInt32(Telnet.emulation.width);     // Int32    columns
845     p.putInt32(0);      // Int32    x pixels
846     p.putInt32(0);      // Int32    y pixels
847     p.putByte((byte) 0);    // Int8     terminal modes
848     sendPacket1(p);
849     return "";
850   }
851 
852   private String Send_SSH_CMSG_EXIT_CONFIRMATION() throws IOException {
853     SshPacket1 packet = new SshPacket1(SSH_CMSG_EXIT_CONFIRMATION);
854     sendPacket1(packet);
855     return "";
856   }
857 }
5776635 [rkeene@sledge /home/rkeene/archive/floydssh/ssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2004-03-06 22:44:06