gt:                     DESKeySpec keySpec = new DESKeySpec(keyBytes);
context: /*
   * Copyright (c) 2005-2009 Citrix Systems, Inc.
   *
   * This library is free software; you can redistribute it and/or modify it
   * under the terms of version 2 of the GNU General Public License as published
   * by the Free Software Foundation, with the additional linking exception as
   * follows:
   * 
   *   Linking this library statically or dynamically with other modules is
   *   making a combined work based on this library. Thus, the terms and
   *   conditions of the GNU General Public License cover the whole combination.
   * 
   *   As a special exception, the copyright holders of this library give you
   *   permission to link this library with independent modules to produce an
   *   executable, regardless of the license terms of these independent modules,
   *   and to copy and distribute the resulting executable under terms of your
   *   choice, provided that you also meet, for each linked independent module,
   *   the terms and conditions of the license of that module. An independent
   *   module is a module which is not derived from or based on this library. If
   *   you modify this library, you may extend this exception to your version of
   *   the library, but you are not obligated to do so. If you do not wish to do
   *   so, delete this exception statement from your 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., 51
   * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   */
  package com.citrix.xenserver.console;
  
  import java.awt.Color;
  // import java.awt.Graphics;
  // import java.awt.Dimension;
  import java.awt.Image;
  // import java.awt.Rectangle;
  import java.awt.Transparency;
  import java.awt.color.ColorSpace;
  import java.awt.image.BufferedImage;
  import java.awt.image.ColorModel;
  import java.awt.image.ComponentColorModel;
  // import java.awt.image.IndexColorModel;
  import java.awt.image.DataBuffer;
  import java.awt.image.DataBufferByte;
  import java.awt.image.DirectColorModel;
  import java.awt.image.PixelInterleavedSampleModel;
  import java.awt.image.Raster;
  import java.awt.image.SampleModel;
  import java.awt.image.SinglePixelPackedSampleModel;
  import java.awt.image.WritableRaster;
  import java.io.BufferedInputStream;
  import java.io.BufferedOutputStream;
  // import java.io.Console;
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.EOFException;
  import java.io.IOException;
  // import java.io.InputStream;
  import java.net.Socket;
  import java.util.Arrays;
  import java.util.logging.Logger;
  import java.util.logging.Level;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import javax.crypto.Cipher;
  import javax.crypto.SecretKey;
  import javax.crypto.SecretKeyFactory;
  import javax.crypto.spec.DESKeySpec;
  import javax.swing.SwingUtilities;
  
  /**
   * Implements "The RFB Protocol" Version 3.3. Includes support for the Cursor
   * pseudo-encoding, for client-side cursor rendering.
   * 
   * <p>
   * See <a href="http://realvnc.com/docs/rfbproto.pdf" /> for the specification.
   */
  public class VNCStream {
      private static final Logger logger = Logger.getLogger(VNCStream.class.getName());
  
      public static final int NO_IP = 0;
      public static final int INCORRECT_PASSWORD = 1;
      public static final int CONNECTION_FAILED = 2;
      public static final int CONNECTION_SUCCEEDED = 4;
  
      private static final int THUMBNAIL_SLEEP_TIME = 500;
  
      private static final ColorSpace colorSpace_ = ColorSpace
              .getInstance(ColorSpace.CS_sRGB);
  
      public static class VNCException extends IOException {
          static final long serialVersionUID = 0;
  
          VNCException(String msg) {
              super(msg);
          }
      }
  
      private static class ProtocolVersion {
          int major_;
          int minor_;
  
          ProtocolVersion(int major_, int minor_) {
              this.major_ = major_;
              this.minor_ = minor_;
          }
  
      }
  
      private static final int RAW_ENCODING = 0;
      private static final int COPY_RECTANGLE_ENCODING = 1;
      private static final int RRE_ENCODING = 2;
      private static final int CORRE_ENCODING = 4;
      private static final int HEXTILE_ENCODING = 5;
      private static final int CURSOR_PSEUDO_ENCODING = -239;
      private static final int DESKTOP_SIZE_PSEUDO_ENCODING = -223;
  
      private static final int SET_PIXEL_FORMAT = 0;
      private static final int SET_ENCODINGS = 2;
      private static final int FRAMEBUFFER_UPDATE_REQUEST = 3;
      private static final int KEY_EVENT = 4;
      private static final int POINTER_EVENT = 5;
      private static final int CLIENT_CUT_TEXT = 6;
  
      private static final int RAW_SUBENCODING = 1;
      private static final int BACKGROUND_SPECIFIED_SUBENCODING = 2;
      private static final int FOREGROUND_SPECIFIED_SUBENCODING = 4;
      private static final int ANY_SUBRECTS_SUBENCODING = 8;
      private static final int SUBRECTS_COLORED_SUBENCODING = 16;
  
      private static final int FRAME_BUFFER_UPDATE = 0;
      private static final int BELL = 2;
      private static final int SERVER_CUT_TEXT = 3;
  
      private static final int MAX_STRING_LENGTH = 1 << 16;
  
      private boolean _connected = false;
  
      /**
       * The encodings used when the display is 32bpp. Note that these are
       * ordered: preferred encoding first.
       */
      private static final int[] encodings_32 = new int[] { HEXTILE_ENCODING,
              CORRE_ENCODING, RRE_ENCODING, COPY_RECTANGLE_ENCODING,
              RAW_ENCODING, CURSOR_PSEUDO_ENCODING, DESKTOP_SIZE_PSEUDO_ENCODING };
  
      /**
       * The encodings used when the display is 8bpp. We don't support client-side
       * cursors in this mode. Note that these are ordered: preferred encoding
       * first.
       */
      private static final int[] encodings_8 = new int[] { HEXTILE_ENCODING,
              CORRE_ENCODING, RRE_ENCODING, COPY_RECTANGLE_ENCODING,
              RAW_ENCODING, DESKTOP_SIZE_PSEUDO_ENCODING };
  
      /*
       * By the RFB spec, the keycodes are those used by X: see
       * /usr/include/X11/keysymdef.h. These are the three that we need for
       * ctrl-alt-delete.
       */
      private static final int KEY_CTRL_L = 0xffe3;
      private static final int KEY_ALT_L = 0xffe9;
      private static final int KEY_DELETE = 0xffff;
  
      static {
          try {
              // Force early class loading.
              byte[] keyBytes = new byte[8];
              byte[] challenge = new byte[16];
              Cipher cipher = Cipher.getInstance("DES");
              cipher.init(Cipher.ENCRYPT_MODE, SecretKeyFactory
                      .getInstance("DES")
                      .generateSecret(new DESKeySpec(keyBytes)));
              cipher.doFinal(challenge);
          } catch (Exception e) {
              assert false : e;
          }
      }
  
      private final VNCClient client_;
  
      public Helper helper = null;
      private ConnectionListener _listener;
      private ConsoleListener _console;
  
      public VNCStream(VNCClient client, ConnectionListener listener,
              ConsoleListener console) {
          client_ = client;
          _listener = listener;
          _console = console;
      }
  
      /**
       * Takes responsibility for closing the given socket.
       */
      /*
       * public int testConnectivity(Socket socket, char [] password) { try { try {
       * new Helper(client_, socket, password).connect(); } finally {
       * _console.writeline("VNCStream.testConnectivity closing socket");
       * socket.close(); } logger.error("Connection succeeded"); return
       * CONNECTION_SUCCEEDED; } catch (VNCException exn) {
       * logger.error("Connection failed (VNC): " + exn); return
       * INCORRECT_PASSWORD; } catch (IOException exn) { logger.error("Connection
       * failed: " + exn); return CONNECTION_FAILED; } }
       */
  
      /**
       * 
       */
      public void connect(RawHTTP rawHttp, char[] password) throws IOException {
          Helper h;
          _console.writeline("Connecting...");
          synchronized (this) {
              helper = h = new Helper(client_, rawHttp, password, _listener,
                      _console);
          }
  
          h.start();
          _connected = true;
          _console.writeline("Connected");
      }
  
      public void connectSocket(Socket socket, char[] password)
              throws IOException {
          Helper h;
          _console.writeline("Connecting...");
          synchronized (this) {
              helper = h = new Helper(client_, socket, password, _listener,
                      _console);
          }
  
          h.start();
          _connected = true;
          _console.writeline("Connected");
      }
  
      /**
       * Nothrow guarantee.
       */
      public void disconnect() {
          Helper h;
  
          synchronized (this) {
              h = helper;
              helper = null;
          }
  
          if (h != null) {
              h.terminate();
          }
          _connected = false;
      }
  
      public synchronized void pause() {
          if (helper != null) {
              helper.pause();
          }
      }
  
      public boolean isConnected() {
          return this._connected;
      }
  
      public synchronized void unpause() {
          if (helper != null) {
              helper.unpause();
          }
      }
  
      public synchronized void setUpdateThumbnail(boolean updateThumbnail) {
          if (helper != null) {
              helper.setUpdateThumbnail(updateThumbnail);
          }
      }
  
      public synchronized void keyEvent(boolean down, int key) {
          if (helper != null) {
              helper.keyEvent(down, key);
          }
      }
  
      public synchronized void pointerEvent(int buttonMask, int x, int y) {
          if (helper != null) {
              helper.pointerEvent(buttonMask, x, y);
          }
      }
  
      public synchronized void sendCtrlAltDelete() {
          if (helper != null) {
              helper.sendCtrlAltDelete();
          }
      }
  
      /**
       * Pass a wheel scroll event to the server, at the given co-ordinates.
       * 
       * @param r
       *            The number of clicks to scroll, negative for up/away, positive
       *            for down/towards.
       */
      public synchronized void pointerWheelEvent(int x, int y, int r) {
          if (helper != null) {
              helper.pointerWheelEvent(x, y, r);
          }
      }
  
      public synchronized void clientCutText(String text) {
          if (helper != null) {
              helper.clientCutText(text);
          }
      }
  
      private static final class Helper extends Thread {
  
          /*
           * To write, you must synchronize on out_. All the methods named
           * writeXyz expect to be synchronized on out_ already. Reading is only
           * allowed from the thread inside run(), and only one thread should be
           * in that function at any one time. Do not read whilst holding the lock
           * on out_, because reads can block indefinitely, and the KeyEvent
           * handling needs to be able to write from the AWT thread.
           * 
           * paused and updateThumbnail may only be accessed under synchronisation
           * on this object. All other non-final fields may only be accessed from
           * the thread inside run().
           * 
           */
  
          private final VNCClient client_;
          private final char[] password;
  
          private final DataInputStream in_;
          private final DataOutputStream out_;
          private final Socket socket;
  
          private volatile boolean running = true;
          private volatile Thread runThread = null;
  
          private boolean paused = false;
          private boolean updateThumbnail = false;
  
          private int width_;
          private int height_;
          private VNCPixelFormat pixelFormat_;
          private int[] bandOffsets32_;
          private ColorModel colorModel32_;
          private int[] bitMasks8_;
          private ColorModel colorModel8_;
  
          /**
           * This buffer is used by readFillRectangles (part of the Hextile
           * handling), and readColor. Only the first few bytes are used in
           * readColor. In readFillRectangles, the maximum space required is 1530 ==
           * 6 * 255 -- 4 bytes per colour plus two bytes for x,y,w,h, multiplied
           * by 255, the maximum number of rectangles to be sent in one go.
           */
          private byte[] data = new byte[1530];
  
          private void writePadding(int n) throws IOException {
              for (int i = 0; i < n; ++i) {
                  out_.write(0);
              }
          }
  
          private void writeFlag(boolean v) throws IOException {
              out_.writeByte(v ? 1 : 0);
          }
  
          private void writeInt8(int v) throws IOException {
              out_.writeByte(v);
          }
  
          private void writeInt16(int v) throws IOException {
              out_.writeShort(v);
          }
  
          private void writeInt32(int v) throws IOException {
              out_.writeInt(v);
          }
  
          private void writeString(String s) throws IOException {
              writeInt32(s.length());
              out_.write(s.getBytes("US-ASCII"));
          }
  
          private void readPadding(int n) throws IOException {
              in_.skip(n);
          }
  
          private void readFully(byte b[], int off, int len) throws IOException {
              int n = 0;
              while (n < len) {
                  int count = in_.read(b, off + n, len - n);
                  if (count < 0) {
                      throw new EOFException();
                  }
                  n += count;
              }
          }
  
          private boolean readFlag() throws IOException {
              return readCard8() == 0 ? false : true;
          }
  
          private int readCard8() throws IOException {
              int v = in_.read();
              if (v < 0) {
                  throw new EOFException();
              }
              return v;
          }
  
          private int readCard16() throws IOException {
              int b1 = readCard8();
              int b0 = readCard8();
              return (short) ((b1 << 8) | b0);
          }
  
          private int readCard32() throws IOException {
              int b3 = readCard8();
              int b2 = readCard8();
              int b1 = readCard8();
              int b0 = readCard8();
              return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
          }
  
          private String readString() throws IOException {
              int length = readCard32();
              if (length < 0 || length >= MAX_STRING_LENGTH) {
                  throw new VNCException("Invalid string length: " + length);
              }
              byte[] buffer = new byte[length];
              readFully(buffer, 0, length);
              return new String(buffer, "US-ASCII");
          }
  
          private ProtocolVersion getProtocolVersion() throws IOException {
              byte[] buffer = new byte[12];
              readFully(buffer, 0, 12);
              String s = new String(buffer, "US-ASCII");
              Pattern pattern = Pattern.compile("RFB ([0-9]{3})\\.([0-9]{3})\n");
              Matcher matcher = pattern.matcher(s);
              if (!matcher.matches()) {
                  throw new VNCException("expected protocol version: " + s);
              }
  
              return new ProtocolVersion(Integer.parseInt(matcher.group(1)),
                      Integer.parseInt(matcher.group(2)));
          }
  
          private void sendProtocolVersion() throws IOException {
              synchronized (out_) {
                  out_.write("RFB 003.003\n".getBytes("US-ASCII"));
                  out_.flush();
              }
          }
  
          private VNCPixelFormat readPixelFormat() throws IOException {
              VNCPixelFormat pixelFormat = new VNCPixelFormat();
              pixelFormat.bitsPerPixel_ = readCard8();
              pixelFormat.depth_ = readCard8();
              pixelFormat.bigEndian_ = readFlag();
              pixelFormat.trueColor_ = readFlag();
              pixelFormat.redMax_ = readCard16();
              pixelFormat.greenMax_ = readCard16();
              pixelFormat.blueMax_ = readCard16();
              pixelFormat.redShift_ = readCard8();
              pixelFormat.greenShift_ = readCard8();
              pixelFormat.blueShift_ = readCard8();
              readPadding(3);
              _console.writeline("readPixelFormat " + pixelFormat.bitsPerPixel_
                      + " " + pixelFormat.depth_);
              return pixelFormat;
          }
  
          private void writePixelFormat(VNCPixelFormat pixelFormat)
                  throws IOException {
              _console.writeline("writePixelFormat " + pixelFormat.bitsPerPixel_
                      + " " + pixelFormat.depth_);
  
              writeInt8(pixelFormat.bitsPerPixel_);
              writeInt8(pixelFormat.depth_);
              writeFlag(pixelFormat.bigEndian_);
              writeFlag(pixelFormat.trueColor_);
              writeInt16(pixelFormat.redMax_);
              writeInt16(pixelFormat.greenMax_);
              writeInt16(pixelFormat.blueMax_);
              writeInt8(pixelFormat.redShift_);
              writeInt8(pixelFormat.greenShift_);
              writeInt8(pixelFormat.blueShift_);
              writePadding(3);
          }
  
          private void writePixelFormat() throws IOException {
              // set pixel format
              writeInt8(SET_PIXEL_FORMAT);
              writePadding(3);
              writePixelFormat(pixelFormat_);
          }
  
          private void force32bpp() throws IOException {
              _console.writeline("force32bpp()");
  
              pixelFormat_.bitsPerPixel_ = 32;
              pixelFormat_.depth_ = 24;
              pixelFormat_.trueColor_ = true;
              pixelFormat_.redMax_ = 255;
              pixelFormat_.greenMax_ = 255;
              pixelFormat_.blueMax_ = 255;
              pixelFormat_.redShift_ = 16;
              pixelFormat_.greenShift_ = 8;
              pixelFormat_.blueShift_ = 0;
              // Note that we keep the big endian value from the server.
  
              setupPixelFormat();
  
              synchronized (out_) {
                  writePixelFormat();
              }
          }
  
          private void setupPixelFormat() throws IOException {
              _console.writeline("setupPixelFormat(" + pixelFormat_.bitsPerPixel_
                      + ")");
  
              if (pixelFormat_.bitsPerPixel_ == 32) {
                  bandOffsets32_ = pixelFormat_.bigEndian_ ? (new int[] {
                          3 - (pixelFormat_.redShift_ >> 3),
                          3 - (pixelFormat_.greenShift_ >> 3),
                          3 - (pixelFormat_.blueShift_ >> 3), 0 }) : (new int[] {
                          pixelFormat_.redShift_ >> 3,
                          pixelFormat_.greenShift_ >> 3,
                          pixelFormat_.blueShift_ >> 3, 3 });
                  colorModel32_ = new ComponentColorModel(colorSpace_, true, // hasAlpha
                          true, // isAlphaPremultiplied
                          Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
              } else if (pixelFormat_.bitsPerPixel_ == 8) {
                  bitMasks8_ = new int[] {
                          pixelFormat_.redMax_ << pixelFormat_.redShift_,
                          pixelFormat_.greenMax_ << pixelFormat_.greenShift_,
                          pixelFormat_.blueMax_ << pixelFormat_.blueShift_, };
                  colorModel8_ = new DirectColorModel(8, bitMasks8_[0],
                          bitMasks8_[1], bitMasks8_[2]);
              } else {
                  throw new IOException("unexpected bits per pixel: "
                          + pixelFormat_.bitsPerPixel_);
              }
          }
  
          private void writeSetEncodings() throws IOException {
              _console.writeline("writeSetEncodings");
  
              int[] encodings;
  
              if (pixelFormat_.bitsPerPixel_ == 8) {
                  _console.writeline("Disabling local cursors for VNC.");
                  encodings = encodings_8;
              } else {
                  encodings = encodings_32;
              }
  
              writeSetEncodings(encodings);
          }
  
          private void writeSetEncodings(int[] encodings) throws IOException {
              writeInt8(SET_ENCODINGS);
              writePadding(1);
              writeInt16(encodings.length);
              for (int i = 0; i < encodings.length; ++i) {
                  writeInt32(encodings[i]);
              }
          }
  
          private void writeFramebufferUpdateRequest(int x, int y, int width,
                  int height, boolean incremental) throws IOException {
              writeInt8(FRAMEBUFFER_UPDATE_REQUEST);
              writeFlag(incremental);
              writeInt16(x);
              writeInt16(y);
              writeInt16(width);
              writeInt16(height);
          }
  
          private static byte reverse(byte v) {
              byte r = 0;
              if ((v & 0x01) != 0)
                  r |= 0x80;
              if ((v & 0x02) != 0)
                  r |= 0x40;
              if ((v & 0x04) != 0)
                  r |= 0x20;
              if ((v & 0x08) != 0)
                  r |= 0x10;
              if ((v & 0x10) != 0)
                  r |= 0x08;
              if ((v & 0x20) != 0)
                  r |= 0x04;
              if ((v & 0x40) != 0)
                  r |= 0x02;
              if ((v & 0x80) != 0)
                  r |= 0x01;
              return r;
          }
  
          private void handshake() throws IOException {
              ProtocolVersion protocolVersion = getProtocolVersion();
              if (protocolVersion.major_ < 3) {
                  throw new VNCException("don't know protocol version "
                          + protocolVersion.major_);
              }
          }
  
          private void authenticationExchange() throws IOException {
              // _console.writeline("authenticationExchange");
  
              int scheme = readCard32();
              if (scheme == 0) {
                  String reason = readString();
                  throw new VNCException("connection failed: " + reason);
              } else if (scheme == 1) {
                  // no authentication needed
              } else if (scheme == 2) {
                  try {
                      byte[] keyBytes = new byte[8];
                      for (int i = 0; (i < 8) && (i < password.length); ++i) {
                          keyBytes[i] = reverse((byte) password[i]);
                      }
                      Arrays.fill(password, '\0');
  