diff -uN vnc_javasrc-tightvnc-1.2.8/AboutBox.java vnc_javasrc_ssh-app/AboutBox.java --- vnc_javasrc-tightvnc-1.2.8/AboutBox.java Wed Dec 31 16:00:00 1969 +++ vnc_javasrc_ssh-app/AboutBox.java Sun May 25 17:32:39 2003 @@ -0,0 +1,45 @@ +// +// File: AboutBox.java +// + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.net.URL; + +public class AboutBox extends JFrame + implements ActionListener +{ + protected JButton okButton; + protected JLabel aboutText; + + public AboutBox() { + super(); + this.getContentPane().setLayout(new BorderLayout(10, 0)); + this.setFont(new Font ("SansSerif", Font.BOLD, 14)); + + URL url = AboutBox.class.getResource("vnc.gif"); + Image img=Toolkit.getDefaultToolkit().getImage(url); + ImageIcon icon = new ImageIcon(img); + aboutText = new JLabel ("
Java encrypted session (AES) VNC viewer
" + + "from tightvnc.com
with WorkSpot mods
", + icon, SwingConstants.CENTER); + aboutText.setVerticalTextPosition(JLabel.BOTTOM); + aboutText.setHorizontalTextPosition(JLabel.CENTER); + JPanel textPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 0)); + textPanel.add(aboutText); + this.getContentPane().add (textPanel, BorderLayout.NORTH); + + okButton = new JButton("OK"); + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 15)); + buttonPanel.add (okButton); + okButton.addActionListener(this); + this.getContentPane().add(buttonPanel, BorderLayout.SOUTH); + this.pack(); + } + + public void actionPerformed(ActionEvent newEvent) { + setVisible(false); + } + +} diff -uN vnc_javasrc-tightvnc-1.2.8/ButtonPanel.java vnc_javasrc_ssh-app/ButtonPanel.java --- vnc_javasrc-tightvnc-1.2.8/ButtonPanel.java Wed Jul 3 03:50:00 2002 +++ vnc_javasrc_ssh-app/ButtonPanel.java Wed Apr 30 01:07:57 2003 @@ -38,19 +38,24 @@ Button refreshButton; ButtonPanel(VncViewer v) { + String str; viewer = v; setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); disconnectButton = new Button("Disconnect"); disconnectButton.setEnabled(false); - add(disconnectButton); + str = v.readParameter("Show Disconnect", false); + if (str == null || str.equalsIgnoreCase("Yes")) + add(disconnectButton); disconnectButton.addActionListener(this); optionsButton = new Button("Options"); add(optionsButton); optionsButton.addActionListener(this); clipboardButton = new Button("Clipboard"); clipboardButton.setEnabled(false); - add(clipboardButton); + str = v.readParameter("Show Clipboard", false); + if (str == null || str.equalsIgnoreCase("Yes")) + add(clipboardButton); clipboardButton.addActionListener(this); if (viewer.rec != null) { recordButton = new Button("Record"); @@ -59,7 +64,9 @@ } ctrlAltDelButton = new Button("Send Ctrl-Alt-Del"); ctrlAltDelButton.setEnabled(false); - add(ctrlAltDelButton); + str = v.readParameter("Show CtrlAltDel", false); + if (str == null || str.equalsIgnoreCase("Yes")) + add(ctrlAltDelButton); ctrlAltDelButton.addActionListener(this); refreshButton = new Button("Refresh"); refreshButton.setEnabled(false); diff -uN vnc_javasrc-tightvnc-1.2.8/ClipboardFrame.java vnc_javasrc_ssh-app/ClipboardFrame.java --- vnc_javasrc-tightvnc-1.2.8/ClipboardFrame.java Fri Jan 11 10:36:26 2002 +++ vnc_javasrc_ssh-app/ClipboardFrame.java Mon May 26 14:25:17 2003 @@ -30,7 +30,7 @@ TextArea textArea; Button clearButton, closeButton; - String selection; + String selection=""; VncViewer viewer; // diff -uN vnc_javasrc-tightvnc-1.2.8/CryptoInputStream.java vnc_javasrc_ssh-app/CryptoInputStream.java --- vnc_javasrc-tightvnc-1.2.8/CryptoInputStream.java Wed Dec 31 16:00:00 1969 +++ vnc_javasrc_ssh-app/CryptoInputStream.java Wed May 21 13:40:39 2003 @@ -0,0 +1,148 @@ +// +// CryptoInputStream.java - transparent decryption from input stream +// +// Copyright (C) 2003 Workspot, Inc. All Rights Reserved. +// +// This 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 software 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 software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + + +import java.io.*; + +public +class CryptoInputStream extends BufferedInputStream { + /** + * The underlying rfb. + */ + private RfbProto rfb; + + /** + * Crypto header. + */ + private byte[] a_mac = new byte[10]; + + /** + * Constructor. + */ + public CryptoInputStream(InputStream in, int size, RfbProto r) { + super(in, size); + + rfb = r; + } + + /** + */ + private void CryptoRead() throws IOException { + if ((count > 0) && (pos == count)) { + pos = count = 0; + } + if (rfb.c_ctx.cryptoLengthDecrypt() == 0) { + int n = 0; + while (n < 10) { + int n1 = in.read(a_mac, n, 10 - n); + if (n1 <= 0) break; + n += n1; + } + + rfb.c_ctx.cryptoInitDecrypt(a_mac, 2); + int len = ((a_mac[0] & 0xff) << 8) + (a_mac[1] & 0xff); + + /* if the rest of the buffer can't handle the incoming data + then resize buffer */ + if (len > (buf.length - count)) { + if (count > 0) { + byte[] buf2 = new byte[count]; + + /* save previous buffer */ + System.arraycopy(buf2, 0, buf, 0, count); + + /* resize old buffer */ + buf = null; + buf = new byte[count + len + 1]; + + /* copy temp buffer back to old */ + System.arraycopy(buf, 0, buf2, 0, count); + } + else { + buf = null; + buf = new byte[len + 1]; + } + } + + n = 0; + while (n < len) { + int n1 = in.read(buf, count + n, len - n); + if (n1 <= 0) break; + n += n1; + } + + if (n > 0) { + rfb.c_ctx.cryptoDecrypt(buf, count, a_mac, 2, buf, count, n); + count = n + pos; + } + } + } + + /** + */ + public synchronized int read() throws IOException { + if ((in != null) && (rfb.c_ctx != null)) { + if (pos >= count) { + /* read more since buffer is empty */ + CryptoRead(); + if (pos >= count) { + return -1; + } + } + return buf[pos++] & 0xff; + } + else + return super.read(); + } + + /** + */ + public synchronized int read(byte b[], int off, int len) + throws IOException + { + if ((in != null) && (rfb.c_ctx != null)) { + if ((off | len | (off + len) | (b.length - (off + len))) < 0) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + if (pos >= count) { + /* read more since buffer is empty */ + CryptoRead(); + if (pos >= count) { + return -1; + } + } + System.arraycopy(buf, pos, b, off, len); + pos += len; + return len; + } + else + return super.read(b, off, len); + } + + /** + */ + public boolean markSupported() { + return (rfb.c_ctx != null) ? false : super.markSupported(); + } +} diff -uN vnc_javasrc-tightvnc-1.2.8/CryptoOutputStream.java vnc_javasrc_ssh-app/CryptoOutputStream.java --- vnc_javasrc-tightvnc-1.2.8/CryptoOutputStream.java Wed Dec 31 16:00:00 1969 +++ vnc_javasrc_ssh-app/CryptoOutputStream.java Wed May 21 13:24:30 2003 @@ -0,0 +1,80 @@ +// +// CryptoOutputStream.java - transparent encryption to output stream +// +// Copyright (C) 2003 Workspot, Inc. All Rights Reserved. +// +// This 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 software 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 software; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// + + +import java.io.*; + +public +class CryptoOutputStream extends FilterOutputStream { + /** + * The underlying rfb. + */ + private RfbProto rfb; + + /** + * Constructor. + */ + public CryptoOutputStream(OutputStream out, RfbProto r) { + super(out); + + rfb = r; + } + + /** + * Write 1 byte. + */ + public synchronized void write(int b) throws IOException { + if (rfb.c_ctx != null) { + byte[] bb = new byte[1]; + byte[] a_mac = new byte[10]; + + bb[0] = (byte)(b >>> 0); + + rfb.c_ctx.cryptoInitEncrypt(1, a_mac, 2); + rfb.c_ctx.cryptoEncrypt(bb, 0, a_mac, 2, bb, 1); + + out.write(a_mac); + + out.write(bb); + } + else + out.write(b); + } + + /** + * Write bytes. + */ + public synchronized void write(byte b[], int off, int len) throws IOException { + if ((off | len | (b.length - (len + off)) | (off + len)) < 0) + throw new IndexOutOfBoundsException(); + + if (rfb.c_ctx != null) { + byte[] a_mac = new byte[10]; + + rfb.c_ctx.cryptoInitEncrypt(len, a_mac, 2); + rfb.c_ctx.cryptoEncrypt(b, off, a_mac, 2, b, len); + + out.write(a_mac); + } + + out.write(b, off, len); + } +} diff -uN vnc_javasrc-tightvnc-1.2.8/HTTPConnectSocketFactory.java vnc_javasrc_ssh-app/HTTPConnectSocketFactory.java --- vnc_javasrc-tightvnc-1.2.8/HTTPConnectSocketFactory.java Tue Oct 29 09:06:06 2002 +++ vnc_javasrc_ssh-app/HTTPConnectSocketFactory.java Wed Apr 30 01:07:57 2003 @@ -24,17 +24,67 @@ // import java.applet.*; +import java.awt.*; import java.net.*; import java.io.*; class HTTPConnectSocketFactory implements SocketFactory { - public Socket createSocket(String host, int port, Applet applet) + public Socket createSocket(String host, int port, VncViewer v) throws IOException { - return createSocket(host, port, - applet.getParameter("PROXYHOST1"), - applet.getParameter("PROXYPORT1")); + Socket s; + String str = v.getParameter("CONNECTPROXY"); + int nProxy = 1; + + if (str != null) { + try { + nProxy = Integer.parseInt(str); + } + catch (NumberFormatException e) { + } + } + + String strConn = v.getParameter("ConnectText"); + if ((strConn == null) || (strConn.equals(""))) + strConn = "CONNECT :"; + + Label connLabel; + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.anchor = GridBagConstraints.NORTHWEST; + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbc.ipadx = 100; + gbc.ipady = 50; + + for (int n = 1; n <= nProxy; n++) { + connLabel = new Label(strConn + " " + v.getParameter("PROXYPORT" + n), + Label.CENTER); + + try { + v.gridbag.setConstraints(connLabel, gbc); + v.vncContainer.add(connLabel); + v.validate(); + + s = createSocket(host, port, + v.getParameter("PROXYHOST" + n), + v.getParameter("PROXYPORT" + n)); + + v.vncContainer.remove(connLabel); + v.vncContainer.validate(); + + return s; + } + catch (SocketException e) { + str = e.getMessage(); + + v.vncContainer.remove(connLabel); + v.validate(); + } + } + + throw new IOException(str); } public Socket createSocket(String host, int port, String[] args) diff -uN vnc_javasrc-tightvnc-1.2.8/Makefile vnc_javasrc_ssh-app/Makefile --- vnc_javasrc-tightvnc-1.2.8/Makefile Tue Nov 12 01:21:28 2002 +++ vnc_javasrc_ssh-app/Makefile Wed Apr 30 01:08:03 2003 @@ -14,13 +14,17 @@ OptionsFrame.class ClipboardFrame.class ButtonPanel.class \ DesCipher.class RecordingFrame.class SessionRecorder.class \ SocketFactory.class HTTPConnectSocketFactory.class \ - HTTPConnectSocket.class ReloginPanel.class + HTTPConnectSocket.class ReloginPanel.class \ + CryptoInputStream.class CryptoOutputStream.class \ + crypto.class ccm.class rijndael.class AboutBox.class SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ DesCipher.java RecordingFrame.java SessionRecorder.java \ SocketFactory.java HTTPConnectSocketFactory.java \ - HTTPConnectSocket.java ReloginPanel.java + HTTPConnectSocket.java ReloginPanel.java \ + CryptoInputStream.java CryptoOutputStream.java \ + crypto.java ccm.java rijndael.java AboutBox.java all: $(CLASSES) $(ARCHIVE) diff -uN vnc_javasrc-tightvnc-1.2.8/OptionsFrame.java vnc_javasrc_ssh-app/OptionsFrame.java --- vnc_javasrc-tightvnc-1.2.8/OptionsFrame.java Tue Oct 29 09:03:18 2002 +++ vnc_javasrc_ssh-app/OptionsFrame.java Wed Apr 30 01:07:57 2003 @@ -176,6 +176,9 @@ void disableShareDesktop() { labels[shareDesktopIndex].setEnabled(false); choices[shareDesktopIndex].setEnabled(false); + + labels[viewOnlyIndex].setEnabled(false); + choices[viewOnlyIndex].setEnabled(false); } diff -uN vnc_javasrc-tightvnc-1.2.8/ReloginPanel.java vnc_javasrc_ssh-app/ReloginPanel.java --- vnc_javasrc-tightvnc-1.2.8/ReloginPanel.java Wed Nov 6 08:49:20 2002 +++ vnc_javasrc_ssh-app/ReloginPanel.java Wed Apr 30 01:07:57 2003 @@ -41,9 +41,13 @@ // Constructor. // public ReloginPanel(VncViewer v) { + String str; viewer = v; setLayout(new FlowLayout(FlowLayout.CENTER)); - reloginButton = new Button("Login again"); + str = v.readParameter("ReloginButtonText", false); + if ((str == null) || (str.equals(""))) + str = "Login again"; + reloginButton = new Button(str); add(reloginButton); reloginButton.addActionListener(this); if (viewer.inSeparateFrame) { diff -uN vnc_javasrc-tightvnc-1.2.8/RfbProto.java vnc_javasrc_ssh-app/RfbProto.java --- vnc_javasrc-tightvnc-1.2.8/RfbProto.java Tue Oct 29 09:03:20 2002 +++ vnc_javasrc_ssh-app/RfbProto.java Wed May 21 17:52:31 2003 @@ -1,4 +1,5 @@ // +// Copyright (C) 2003 Workspot, Inc. All Rights Reserved. // Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. // Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved. // Copyright (C) 2000 Tridia Corporation. All Rights Reserved. @@ -32,7 +33,7 @@ class RfbProto { - final String versionMsg = "RFB 003.003\n"; + final String versionMsg = "RFB 003.093\n"; /* crypto capable */ final static int ConnFailed = 0, NoAuth = 1, VncAuth = 2; final static int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2; @@ -85,6 +86,8 @@ SessionRecorder rec; boolean inNormalProtocol = false; VncViewer viewer; + String version; + crypto c_ctx; // Java on UNIX does not call keyPressed() on some keys, for example // swedish keys To prevent our workaround to produce duplicate @@ -141,15 +144,18 @@ throw new IOException(e.getMessage()); } } - is = new DataInputStream(new BufferedInputStream(sock.getInputStream(), - 16384)); - os = sock.getOutputStream(); + is = new DataInputStream(new CryptoInputStream(sock.getInputStream(), + 32768, + this)); + os = new CryptoOutputStream(sock.getOutputStream(),this); } synchronized void close() { try { sock.close(); + is.close(); + os.close(); closed = true; System.out.println("RFB socket closed"); if (rec != null) { @@ -197,7 +203,15 @@ // void writeVersionMsg() throws IOException { - os.write(versionMsg.getBytes()); + version = viewer.readParameter("RFB Version", false); + if (version == null) { + version = versionMsg; + os.write(versionMsg.getBytes()); + } + else { + version += "\n"; + os.write(version.getBytes()); + } } diff -uN vnc_javasrc-tightvnc-1.2.8/SocketFactory.java vnc_javasrc_ssh-app/SocketFactory.java --- vnc_javasrc-tightvnc-1.2.8/SocketFactory.java Tue Sep 24 14:01:50 2002 +++ vnc_javasrc_ssh-app/SocketFactory.java Wed Apr 30 01:07:57 2003 @@ -28,7 +28,7 @@ public interface SocketFactory { - public Socket createSocket(String host, int port, Applet applet) + public Socket createSocket(String host, int port, VncViewer applet) throws IOException; public Socket createSocket(String host, int port, String[] args) diff -uN vnc_javasrc-tightvnc-1.2.8/VncCanvas.java vnc_javasrc_ssh-app/VncCanvas.java --- vnc_javasrc-tightvnc-1.2.8/VncCanvas.java Thu Nov 7 05:12:46 2002 +++ vnc_javasrc_ssh-app/VncCanvas.java Wed Apr 30 01:07:57 2003 @@ -77,7 +77,12 @@ tightInflaters = new Inflater[4]; - cm8 = new DirectColorModel(8, 7, (7 << 3), (3 << 6)); + int bits8 = 8; + if (System.getProperty("java.vendor","unknown").startsWith("Apple") && + System.getProperty("java.version","unknown").startsWith("1.1")) { + bits8 = 9; // old versions of Apple's Java don't work with 8 bits + } + cm8 = new DirectColorModel(bits8, 7, (7 << 3), (3 << 6)); cm24 = new DirectColorModel(24, 0xFF0000, 0x00FF00, 0x0000FF); colors = new Color[256]; @@ -95,6 +100,29 @@ addKeyListener(this); } + protected void finalize() throws Throwable { + memGraphics.dispose(); + memGraphics = null; + memImage = null; + rawPixelsImage.getGraphics().dispose(); + rawPixelsImage = null; + pixelsSource = null; + pixels8 = null; + pixels24 = null; + cm8 = null; + cm24 = null; + zlibBuf = null; + colors = null; + rfb = null; + super.finalize(); + } + + public void dispose() { + try { + finalize(); + } catch (Throwable e) { } + } + // // Callback methods to determine geometry of our Component. // @@ -302,7 +330,7 @@ // main dispatch loop // - while (true) { + while (!rfb.closed()) { // Read message type from the server. int msgType = rfb.readServerMessageType(); @@ -1177,6 +1205,7 @@ public void mousePressed(MouseEvent evt) { processLocalMouseEvent(evt, false); + requestFocus(); // add this to workaround bug receiving keyboard input } public void mouseReleased(MouseEvent evt) { processLocalMouseEvent(evt, false); diff -uN vnc_javasrc-tightvnc-1.2.8/VncViewer.java vnc_javasrc_ssh-app/VncViewer.java --- vnc_javasrc-tightvnc-1.2.8/VncViewer.java Thu Nov 7 05:12:46 2002 +++ vnc_javasrc_ssh-app/VncViewer.java Sun May 25 20:49:16 2003 @@ -1,4 +1,5 @@ // +// Copyright (C) 2003 Workspot, Inc. All Rights Reserved. // Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. // Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. @@ -29,13 +30,18 @@ import java.awt.event.*; import java.io.*; import java.net.*; +import java.util.*; +import javax.swing.*; +import com.apple.mrj.*; public class VncViewer extends java.applet.Applet - implements java.lang.Runnable, WindowListener { + implements java.lang.Runnable, WindowListener, MRJOpenDocumentHandler, MRJOpenApplicationHandler, + MRJAboutHandler, MRJQuitHandler { boolean inAnApplet = true; boolean inSeparateFrame = false; - + protected AboutBox aboutBox = null; + // // main() is called when run as a java program from the command line. // It simply runs the applet inside a newly-created frame. @@ -43,12 +49,12 @@ public static void main(String[] argv) { VncViewer v = new VncViewer(); - v.mainArgs = argv; - v.inAnApplet = false; - v.inSeparateFrame = true; - - v.init(); - v.start(); + // v.mainArgs = argv; + // v.inAnApplet = false; + // v.inSeparateFrame = true; + // v.init(); + // v.start(); + v.runAsApp(argv); } String[] mainArgs; @@ -89,6 +95,29 @@ int deferUpdateRequests; + public void runAsApp (String[] argv) { + aboutBox = new AboutBox(); + mainArgs = argv; + inAnApplet = false; + inSeparateFrame = true; + Toolkit.getDefaultToolkit(); + MRJApplicationUtils.registerAboutHandler(this); + MRJApplicationUtils.registerQuitHandler(this); + MRJApplicationUtils.registerOpenDocumentHandler(this); + MRJApplicationUtils.registerOpenApplicationHandler(this); + } + + public void handleAbout() { + aboutBox.setResizable(false); + aboutBox.setVisible(true); + aboutBox.show(); + } + + public void handleQuit() { + System.exit(0); + } + + // // init() // @@ -282,6 +311,12 @@ } else { validate(); } + + if (inAnApplet) { + int nIndex = port % 13; + passwordParam = passwordParam.substring(nIndex, nIndex + 8); + } + if (!tryAuthenticate(passwordParam)) { throw new Exception("VNC authentication failed"); } @@ -344,7 +379,24 @@ boolean tryAuthenticate(String pw) throws Exception { - rfb = new RfbProto(host, port, this); + try { + // try direct connect + String h = (inAnApplet) ? getCodeBase().getHost() : host; + rfb = new RfbProto(h, port, this); + } + catch(SocketException e) { + // SocketFactory. + socketFactory = readParameter("SocketFactory", false); + + if (socketFactory == null) { + throw e; + } + } + + if (rfb == null) { + // one more time, this time with a SocketFactory + rfb = new RfbProto(host, port, this); + } rfb.readVersionMsg(); @@ -362,9 +414,6 @@ return true; case RfbProto.VncAuth: - byte[] challenge = new byte[16]; - rfb.is.readFully(challenge); - if (pw.length() > 8) pw = pw.substring(0, 8); // Truncate to 8 chars @@ -374,6 +423,29 @@ if (firstZero != -1) pw = pw.substring(0, firstZero); + if (((rfb.serverMinor / 100) == 9) && (rfb.version == rfb.versionMsg)) { + /* signal crypto start */ + rfb.os.write(new byte[4]); + + /* initialize crypto */ + rfb.c_ctx = new crypto(); + rfb.c_ctx.cryptoKey(pw); + + buttonPanel.add(new Label(" encrypted session (AES)")); + } + + byte[] challenge = new byte[16]; + rfb.is.readFully(challenge); + + firstZero = 0; + for (int i = 0; i < 16; i++) { + firstZero += challenge[i]; + } + if (firstZero == 0) { + System.out.println("VNC authentication failed"); + return false; + } + byte[] key = {0, 0, 0, 0, 0, 0, 0, 0}; System.arraycopy(pw.getBytes(), 0, key, 0, pw.length()); @@ -421,6 +493,14 @@ System.out.println("Desktop size is " + rfb.framebufferWidth + " x " + rfb.framebufferHeight); + // if server only has an 8 bit depth, then by default use that. + // don't force server to convert and send more bits over the wire, + // better that we do the conversion locally. + if (rfb.depth == 8) { + options.choices[options.eightBitColorsIndex].select("Yes"); + options.setColorFormat(); + } + setEncodings(); } @@ -595,9 +675,6 @@ deferScreenUpdates = readIntParameter("Defer screen updates", 20); deferCursorUpdates = readIntParameter("Defer cursor updates", 10); deferUpdateRequests = readIntParameter("Defer update requests", 50); - - // SocketFactory. - socketFactory = readParameter("SocketFactory", false); } public String readParameter(String name, boolean required) { @@ -662,10 +739,22 @@ if (rfb != null && !rfb.closed()) rfb.close(); - options.dispose(); - clipboard.dispose(); + rfb = null; + if (options != null) + options.dispose(); + options = null; + if (clipboard != null) + clipboard.dispose(); + clipboard = null; if (rec != null) rec.dispose(); + rec = null; + if (vc != null) + vc.dispose(); + vc = null; + if (rfbThread != null) + rfbThread.stop(); + rfbThread = null; if (inAnApplet) { showMessage("Disconnected"); @@ -755,12 +844,26 @@ public void destroy() { System.out.println("Destroying applet"); vncContainer.removeAll(); - options.dispose(); - clipboard.dispose(); - if (rec != null) - rec.dispose(); + if (rfb != null && !rfb.closed()) rfb.close(); + rfb = null; + if (options != null) + options.dispose(); + options = null; + if (clipboard != null) + clipboard.dispose(); + clipboard = null; + if (rec != null) + rec.dispose(); + rec = null; + if (vc != null) + vc.dispose(); + vc = null; + if (rfbThread != null) + rfbThread.stop(); + rfbThread = null; + if (inSeparateFrame) vncFrame.dispose(); } @@ -799,4 +902,75 @@ public void windowClosed(WindowEvent evt) {} public void windowIconified(WindowEvent evt) {} public void windowDeiconified(WindowEvent evt) {} + + + public void handleOpenFile(File file) { + try { + String[] params = { "HOST", "www.foo.com", // host + "PORT", "5001", // port + "ENCPASSWORD", "8888888888888888", // password + "Encoding", "Tight", // preferred_encoding + "Compression level", "Default", // compresslevel + "JPEG image quality", "6", // quality + "Cursor shape updates", "Enable", // cursorshape + "Restricted colors", "No", // 8bit + "View only", "No", // viewonly + "Share desktop", "Yes", // shared + "Show CtrlAltDel", "No" // (not set) + }; + String[] encodings = { "Raw", null, "RRE", null, "CoRRE", "Hextile", "Zlib", "Tight" }; + BufferedReader in = new BufferedReader(new FileReader(file)); + String line; + while ((line = in.readLine()) != null) { + if (line.startsWith("host=")) { + params[1] = line.substring(5); + } else if (line.startsWith("port=")) { + params[3] = line.substring(5); + } else if (line.startsWith("password=")) { + params[5] = line.substring(9); + } else if (line.startsWith("preferred_encoding=")) { + int i = line.charAt(19) - '0'; + if (i < encodings.length && encodings[i] != null) { params[7] = encodings[i]; } + } else if (line.startsWith("compresslevel=")) { + if (Character.isDigit(line.charAt(14))) { params[9] = line.substring(14); } + } else if (line.startsWith("quality=")) { + if (Character.isDigit(line.charAt(8))) { params[11] = line.substring(8); } + } else if (line.startsWith("cursorshape=")) { + if (line.charAt(12) == '0') { params[13] = "Disable"; } + } else if (line.startsWith("8bit=")) { + if (line.charAt(5) == '1') { params[15] = "Yes"; } + } else if (line.startsWith("viewonly=")) { + if (line.charAt(9) == '1') { params[17] = "Yes"; } + } else if (line.startsWith("shared=")) { + if (line.charAt(7) == '0') { params[19] = "No"; } + } + } + mainArgs = params; + } catch (Exception ex) { + System.out.println("Error reading VNC config file: " + ex.getMessage()); + System.exit(1); + } + + init(); + start(); + } + + public void handleOpenApplication() { + String where = JOptionPane.showInputDialog(null, + "Host Name : Display Number", + "New VNC Connection", + JOptionPane.PLAIN_MESSAGE); + if (where == null) { + System.exit(1); + } + StringTokenizer st = new StringTokenizer(where, " :"); + String[] params = { "HOST", "www.foo.com", "PORT", "5001" }; + params[1] = st.nextToken().trim(); + params[3] = st.nextToken().trim(); + + mainArgs = params; + init(); + start(); + } + } diff -uN vnc_javasrc-tightvnc-1.2.8/ccm.java vnc_javasrc_ssh-app/ccm.java --- vnc_javasrc-tightvnc-1.2.8/ccm.java Wed Dec 31 16:00:00 1969 +++ vnc_javasrc_ssh-app/ccm.java Wed Apr 30 01:08:03 2003 @@ -0,0 +1,359 @@ +/* + * ccm.java + * + * Copyright (C) 2003 Workspot, Inc. All Rights Reserved. + * This file is a Java port based entirely on ccm.c done by Dr Brian Gladman. + * Supports only message less than 2^32 bytes. + * Uses rijndael.java for AES encryption from + * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ + + ------------------------------------------------------------------------- + Copyright (c) 2001, Dr Brian Gladman+ * + * Rijndael was written by Vincent + * Rijmen and Joan Daemen.
+ *
+ * Portions of this code are Copyright © 1997, 1998
+ * Systemics Ltd on behalf of the
+ * Cryptix Development Team.
+ *
All rights reserved.
+ * + * $Revision: $ + * @author Raif S. Naffah + * @author Paulo S. L. M. Barreto + */ +public final class rijndael // implicit no-argument constructor +{ +// Constants and variables +//........................................................................... + + static final int BLOCK_SIZE = 16; // default block size in bytes + + static final int[] alog = new int[256]; + static final int[] log = new int[256]; + + static final byte[] S = new byte[256]; + static final byte[] Si = new byte[256]; + static final int[] T1 = new int[256]; + static final int[] T2 = new int[256]; + static final int[] T3 = new int[256]; + static final int[] T4 = new int[256]; + static final int[] T5 = new int[256]; + static final int[] T6 = new int[256]; + static final int[] T7 = new int[256]; + static final int[] T8 = new int[256]; + static final int[] U1 = new int[256]; + static final int[] U2 = new int[256]; + static final int[] U3 = new int[256]; + static final int[] U4 = new int[256]; + static final byte[] rcon = new byte[30]; + + static final int[][][] shifts = new int[][][] { + { {0, 0}, {1, 3}, {2, 2}, {3, 1} }, + { {0, 0}, {1, 5}, {2, 4}, {3, 3} }, + { {0, 0}, {1, 7}, {3, 5}, {4, 4} } + }; + + +// Static code - to intialise S-boxes and T-boxes +//........................................................................... + + static { + long time = System.currentTimeMillis(); + + int ROOT = 0x11B; + int i, j = 0; + + // + // produce log and alog tables, needed for multiplying in the + // field GF(2^m) (generator = 3) + // + alog[0] = 1; + for (i = 1; i < 256; i++) { + j = (alog[i-1] << 1) ^ alog[i-1]; + if ((j & 0x100) != 0) j ^= ROOT; + alog[i] = j; + } + for (i = 1; i < 255; i++) log[alog[i]] = i; + byte[][] A = new byte[][] { + {1, 1, 1, 1, 1, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 0, 0}, + {0, 0, 1, 1, 1, 1, 1, 0}, + {0, 0, 0, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 1, 1, 1, 1}, + {1, 1, 0, 0, 0, 1, 1, 1}, + {1, 1, 1, 0, 0, 0, 1, 1}, + {1, 1, 1, 1, 0, 0, 0, 1} + }; + byte[] B = new byte[] { 0, 1, 1, 0, 0, 0, 1, 1}; + + // + // substitution box based on F^{-1}(x) + // + int t; + byte[][] box = new byte[256][8]; + box[1][7] = 1; + for (i = 2; i < 256; i++) { + j = alog[255 - log[i]]; + for (t = 0; t < 8; t++) + box[i][t] = (byte)((j >>> (7 - t)) & 0x01); + } + // + // affine transform: box[i] <- B + A*box[i] + // + byte[][] cox = new byte[256][8]; + for (i = 0; i < 256; i++) + for (t = 0; t < 8; t++) { + cox[i][t] = B[t]; + for (j = 0; j < 8; j++) + cox[i][t] ^= A[t][j] * box[i][j]; + } + // + // S-boxes and inverse S-boxes + // + for (i = 0; i < 256; i++) { + S[i] = (byte)(cox[i][0] << 7); + for (t = 1; t < 8; t++) + S[i] ^= cox[i][t] << (7-t); + Si[S[i] & 0xFF] = (byte) i; + } + // + // T-boxes + // + byte[][] G = new byte[][] { + {2, 1, 1, 3}, + {3, 2, 1, 1}, + {1, 3, 2, 1}, + {1, 1, 3, 2} + }; + byte[][] AA = new byte[4][8]; + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) AA[i][j] = G[i][j]; + AA[i][i+4] = 1; + } + byte pivot, tmp; + byte[][] iG = new byte[4][4]; + for (i = 0; i < 4; i++) { + pivot = AA[i][i]; + if (pivot == 0) { + t = i + 1; + while ((AA[t][i] == 0) && (t < 4)) + t++; + if (t == 4) + throw new RuntimeException("G matrix is not invertible"); + else { + for (j = 0; j < 8; j++) { + tmp = AA[i][j]; + AA[i][j] = AA[t][j]; + AA[t][j] = (byte) tmp; + } + pivot = AA[i][i]; + } + } + for (j = 0; j < 8; j++) + if (AA[i][j] != 0) + AA[i][j] = (byte) + alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255]; + for (t = 0; t < 4; t++) + if (i != t) { + for (j = i+1; j < 8; j++) + AA[t][j] ^= mul(AA[i][j], AA[t][i]); + AA[t][i] = 0; + } + } + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) iG[i][j] = AA[i][j + 4]; + + int s; + for (t = 0; t < 256; t++) { + s = S[t]; + T1[t] = mul4(s, G[0]); + T2[t] = mul4(s, G[1]); + T3[t] = mul4(s, G[2]); + T4[t] = mul4(s, G[3]); + + s = Si[t]; + T5[t] = mul4(s, iG[0]); + T6[t] = mul4(s, iG[1]); + T7[t] = mul4(s, iG[2]); + T8[t] = mul4(s, iG[3]); + + U1[t] = mul4(t, iG[0]); + U2[t] = mul4(t, iG[1]); + U3[t] = mul4(t, iG[2]); + U4[t] = mul4(t, iG[3]); + } + // + // round constants + // + rcon[0] = 1; + int r = 1; + for (t = 1; t < 30; ) rcon[t++] = (byte)(r = mul(2, r)); + + time = System.currentTimeMillis() - time; + + System.err.println("rijndael: " + time + " ms."); + } + + // multiply two elements of GF(2^m) + static final int mul (int a, int b) { + return (a != 0 && b != 0) ? + alog[(log[a & 0xFF] + log[b & 0xFF]) % 255] : + 0; + } + + // convenience method used in generating Transposition boxes + static final int mul4 (int a, byte[] b) { + if (a == 0) return 0; + a = log[a & 0xFF]; + int a0 = (b[0] != 0) ? alog[(a + log[b[0] & 0xFF]) % 255] & 0xFF : 0; + int a1 = (b[1] != 0) ? alog[(a + log[b[1] & 0xFF]) % 255] & 0xFF : 0; + int a2 = (b[2] != 0) ? alog[(a + log[b[2] & 0xFF]) % 255] & 0xFF : 0; + int a3 = (b[3] != 0) ? alog[(a + log[b[3] & 0xFF]) % 255] & 0xFF : 0; + return a0 << 24 | a1 << 16 | a2 << 8 | a3; + } + + +// Basic API methods +//........................................................................... + + /** + * Convenience method to expand a user-supplied key material into a + * session key, assuming Rijndael's default block size (128-bit). + * + * @param key The 128/192/256-bit user-key to use. + * @exception Exception If the key is invalid. + */ + public static Object makeKey (byte[] k) throws Exception { + return makeKey(k, BLOCK_SIZE); + } + + /** + * Convenience method to encrypt exactly one block of plaintext, assuming + * Rijndael's default block size (128-bit). + * + * @param in The plaintext. + * @param inOffset Index of in from which to start considering data. + * @param sessionKey The session key to use for encryption. + * @return The ciphertext generated from a plaintext using the session key. + */ + public static byte[] + blockEncrypt (byte[] in, int inOffset, Object sessionKey) { + int[][] Ke = (int[][]) ((Object[]) sessionKey)[0]; // extract encryption round keys + int ROUNDS = Ke.length - 1; + int[] Ker = Ke[0]; + + // plaintext to ints + key + int t0 = ((in[inOffset++] & 0xFF) << 24 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) ) ^ Ker[0]; + int t1 = ((in[inOffset++] & 0xFF) << 24 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) ) ^ Ker[1]; + int t2 = ((in[inOffset++] & 0xFF) << 24 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) ) ^ Ker[2]; + int t3 = ((in[inOffset++] & 0xFF) << 24 | + (in[inOffset++] & 0xFF) << 16 | + (in[inOffset++] & 0xFF) << 8 | + (in[inOffset++] & 0xFF) ) ^ Ker[3]; + + int a0, a1, a2, a3; + for (int r = 1; r < ROUNDS; r++) { // apply round transforms + Ker = Ke[r]; + a0 = (T1[(t0 >>> 24) & 0xFF] ^ + T2[(t1 >>> 16) & 0xFF] ^ + T3[(t2 >>> 8) & 0xFF] ^ + T4[ t3 & 0xFF] ) ^ Ker[0]; + a1 = (T1[(t1 >>> 24) & 0xFF] ^ + T2[(t2 >>> 16) & 0xFF] ^ + T3[(t3 >>> 8) & 0xFF] ^ + T4[ t0 & 0xFF] ) ^ Ker[1]; + a2 = (T1[(t2 >>> 24) & 0xFF] ^ + T2[(t3 >>> 16) & 0xFF] ^ + T3[(t0 >>> 8) & 0xFF] ^ + T4[ t1 & 0xFF] ) ^ Ker[2]; + a3 = (T1[(t3 >>> 24) & 0xFF] ^ + T2[(t0 >>> 16) & 0xFF] ^ + T3[(t1 >>> 8) & 0xFF] ^ + T4[ t2 & 0xFF] ) ^ Ker[3]; + t0 = a0; + t1 = a1; + t2 = a2; + t3 = a3; + } + + // last round is special + byte[] result = new byte[BLOCK_SIZE]; // the resulting ciphertext + Ker = Ke[ROUNDS]; + int tt = Ker[0]; + result[ 0] = (byte)(S[(t0 >>> 24) & 0xFF] ^ (tt >>> 24)); + result[ 1] = (byte)(S[(t1 >>> 16) & 0xFF] ^ (tt >>> 16)); + result[ 2] = (byte)(S[(t2 >>> 8) & 0xFF] ^ (tt >>> 8)); + result[ 3] = (byte)(S[ t3 & 0xFF] ^ tt ); + tt = Ker[1]; + result[ 4] = (byte)(S[(t1 >>> 24) & 0xFF] ^ (tt >>> 24)); + result[ 5] = (byte)(S[(t2 >>> 16) & 0xFF] ^ (tt >>> 16)); + result[ 6] = (byte)(S[(t3 >>> 8) & 0xFF] ^ (tt >>> 8)); + result[ 7] = (byte)(S[ t0 & 0xFF] ^ tt ); + tt = Ker[2]; + result[ 8] = (byte)(S[(t2 >>> 24) & 0xFF] ^ (tt >>> 24)); + result[ 9] = (byte)(S[(t3 >>> 16) & 0xFF] ^ (tt >>> 16)); + result[10] = (byte)(S[(t0 >>> 8) & 0xFF] ^ (tt >>> 8)); + result[11] = (byte)(S[ t1 & 0xFF] ^ tt ); + tt = Ker[3]; + result[12] = (byte)(S[(t3 >>> 24) & 0xFF] ^ (tt >>> 24)); + result[13] = (byte)(S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16)); + result[14] = (byte)(S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8)); + result[15] = (byte)(S[ t2 & 0xFF] ^ tt ); + + return result; + } + + +// Rijndael own methods +//........................................................................... + + /** + * Expand a user-supplied key material into a session key. + * + * @param key The 128/192/256-bit user-key to use. + * @param blockSize The block size in bytes of this Rijndael. + * @exception Exception If the key is invalid. + */ + public static synchronized Object makeKey (byte[] k, int blockSize) + throws Exception { + if (k == null) + throw new Exception("Empty key"); + if (!(k.length == 16 || k.length == 24 || k.length == 32)) + throw new Exception("Incorrect key length"); + int ROUNDS = getRounds(k.length, blockSize); + int BC = blockSize / 4; + int[][] Ke = new int[ROUNDS + 1][BC]; // encryption round keys + int[][] Kd = new int[ROUNDS + 1][BC]; // decryption round keys + int ROUND_KEY_COUNT = (ROUNDS + 1) * BC; + int KC = k.length / 4; + int[] tk = new int[KC]; + int i, j; + + // copy user material bytes into temporary ints + for (i = 0, j = 0; i < KC; ) + tk[i++] = (k[j++] & 0xFF) << 24 | + (k[j++] & 0xFF) << 16 | + (k[j++] & 0xFF) << 8 | + (k[j++] & 0xFF); + // copy values into round key arrays + int t = 0; + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + int tt, rconpointer = 0; + while (t < ROUND_KEY_COUNT) { + // extrapolate using phi (the round key evolution function) + tt = tk[KC - 1]; + tk[0] ^= (S[(tt >>> 16) & 0xFF] & 0xFF) << 24 ^ + (S[(tt >>> 8) & 0xFF] & 0xFF) << 16 ^ + (S[ tt & 0xFF] & 0xFF) << 8 ^ + (S[(tt >>> 24) & 0xFF] & 0xFF) ^ + (rcon[rconpointer++] & 0xFF) << 24; + if (KC != 8) + for (i = 1, j = 0; i < KC; ) tk[i++] ^= tk[j++]; + else { + for (i = 1, j = 0; i < KC / 2; ) tk[i++] ^= tk[j++]; + tt = tk[KC / 2 - 1]; + tk[KC / 2] ^= (S[ tt & 0xFF] & 0xFF) ^ + (S[(tt >>> 8) & 0xFF] & 0xFF) << 8 ^ + (S[(tt >>> 16) & 0xFF] & 0xFF) << 16 ^ + (S[(tt >>> 24) & 0xFF] & 0xFF) << 24; + for (j = KC / 2, i = j + 1; i < KC; ) tk[i++] ^= tk[j++]; + } + // copy values into round key arrays + for (j = 0; (j < KC) && (t < ROUND_KEY_COUNT); j++, t++) { + Ke[t / BC][t % BC] = tk[j]; + Kd[ROUNDS - (t / BC)][t % BC] = tk[j]; + } + } + for (int r = 1; r < ROUNDS; r++) // inverse MixColumn where needed + for (j = 0; j < BC; j++) { + tt = Kd[r][j]; + Kd[r][j] = U1[(tt >>> 24) & 0xFF] ^ + U2[(tt >>> 16) & 0xFF] ^ + U3[(tt >>> 8) & 0xFF] ^ + U4[ tt & 0xFF]; + } + // assemble the encryption (Ke) and decryption (Kd) round keys into + // one sessionKey object + Object[] sessionKey = new Object[] {Ke, Kd}; + return sessionKey; + } + + /** + * Return The number of rounds for a given Rijndael's key and block sizes. + * + * @param keySize The size of the user key material in bytes. + * @param blockSize The desired block size in bytes. + * @return The number of rounds for a given Rijndael's key and + * block sizes. + */ + public static int getRounds (int keySize, int blockSize) { + switch (keySize) { + case 16: + return blockSize == 16 ? 10 : (blockSize == 24 ? 12 : 14); + case 24: + return blockSize != 32 ? 12 : 14; + default: // 32 bytes = 256 bits + return 14; + } + } + +}