├── .gitignore ├── src └── com │ └── VPN │ ├── GUIInterface.java │ ├── Helpers.java │ ├── Client │ ├── ClientInterface.java │ └── Client.java │ ├── Server │ ├── ServerInterface.java │ └── Server.java │ ├── CryptoInterface.java │ ├── MainUI.java │ ├── ServerClientStub.java │ ├── DiffieHellmanHelper.java │ ├── ServerUI.java │ └── ClientUI.java └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /src/com/VPN/GUIInterface.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | 4 | 5 | public interface GUIInterface 6 | { 7 | public void printf( String s ); //Prints to screen 8 | public void connectionReady(); //Connection is ready for messages 9 | public void connectionClosed(); //Connection is terminated 10 | } -------------------------------------------------------------------------------- /src/com/VPN/Helpers.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | import javax.xml.bind.DatatypeConverter; 4 | 5 | public class Helpers { 6 | 7 | public static String ByteToString(byte[] arr) 8 | { 9 | /*String s = ""; 10 | for(int i = 0; i < arr.length; i++ ) 11 | { 12 | s += ((int)arr[i]) + ", "; 13 | } 14 | return s;*/ 15 | return DatatypeConverter.printHexBinary(arr); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/VPN/Client/ClientInterface.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3.Client; 2 | 3 | public interface ClientInterface { 4 | 5 | //boolean return type signifies if call succeeded in performing expected work. 6 | public boolean startClient( String host, int port, String sharedKey ); //Start client and do handshake. Expected call GUIInterface.connectionReady() 7 | public void endConnection(); //End connection 8 | public boolean sendMessage( String s ); //sends a message 9 | public void receiveMessages(); //infinite blocking loop for receiving messages 10 | } 11 | -------------------------------------------------------------------------------- /src/com/VPN/Server/ServerInterface.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3.Server; 2 | 3 | public interface ServerInterface { 4 | 5 | //boolean return type signifies if call succeeded in performing expected work. 6 | public boolean startServer( int port, String sharedKey ); //Start server and wait for client connections 7 | public void endConnection(); //End connection 8 | public void closeServer(); //shutdown server 9 | public boolean sendMessage( String s ); //sends a message 10 | public void acceptConnection(); //blocking call to accept connections to server. 11 | public void receiveMessages(); //infinite blocking loop for receiving messages. 12 | } 13 | -------------------------------------------------------------------------------- /src/com/VPN/CryptoInterface.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | public interface CryptoInterface { 4 | 5 | //boolean return type signifies if call succeeded in performing expected work. 6 | 7 | public boolean startServer( int port, String sharedKey ); //Start server and wait for client connections 8 | public boolean startClient( String host, int port, String sharedKey ); //Start client and do handshake. Expected call GUIInterface.connectionReady() 9 | public void endConnection(); //End connection 10 | public void closeServer(); //shutdown server 11 | public boolean sendMessage( String s ); //sends a message 12 | public void acceptConnection(); 13 | public void receiveMessages(); 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple-VPN 2 | ========== 3 | 4 | This is a demo implementation of a simple VPN to send data from one computer to another over a protected channel. The channel establishes a shared secret key using the Diffie Hellman key exchange. This shared secret key is then used to encrypt all further communication, thus resulting in a secure VPN connection, and the public network it uses becomes a protected channel. 5 | 6 | The encryption protocols used here are PBE with MD5 and DES. This is done to keep the implementation simple. As mentioned above, this is simply a demo, we are assuming that the encryption algorithm used is secure. 7 | 8 | The Java AWT and Swing libraries are used to create the user interface, and the Java security and crypto libraries to implement the protocol and key exchange. 9 | 10 | This was a class project at UBC and fellow students Audun Indergaard, Dhruv Raturi, and Denis Abalakov have also contributed to this project. 11 | -------------------------------------------------------------------------------- /src/com/VPN/MainUI.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | import java.awt.FlowLayout; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | 7 | import javax.swing.JButton; 8 | import javax.swing.JFrame; 9 | import javax.swing.SwingUtilities; 10 | 11 | @SuppressWarnings("serial") 12 | public class MainUI extends JFrame implements ActionListener { 13 | 14 | private JButton m_btnClient; 15 | private JButton m_btnServer; 16 | 17 | public MainUI() 18 | { 19 | super("Title"); 20 | this.setSize(300,300); 21 | this.setLocationRelativeTo(null); 22 | this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 23 | this.setLayout(new FlowLayout()); 24 | this.setVisible(true); 25 | 26 | m_btnClient = new JButton("Client"); 27 | m_btnServer = new JButton("Server"); 28 | 29 | m_btnClient.addActionListener(this); 30 | m_btnServer.addActionListener(this); 31 | 32 | this.add(m_btnClient); 33 | this.add(m_btnServer); 34 | displayClient(); 35 | } 36 | 37 | public void actionPerformed( ActionEvent e ) 38 | { 39 | if(e.getSource() == m_btnClient) displayClient(); 40 | if(e.getSource() == m_btnServer) displayServer(); 41 | } 42 | 43 | private void displayClient() 44 | { 45 | SwingUtilities.invokeLater( new Runnable(){ 46 | public void run() { 47 | new ClientUI(); 48 | } 49 | }); 50 | } 51 | 52 | private void displayServer() 53 | { 54 | SwingUtilities.invokeLater( new Runnable(){ 55 | public void run() { 56 | new ServerUI(); 57 | } 58 | 59 | }); 60 | } 61 | /** 62 | * @param args 63 | */ 64 | public static void main(String[] args) { 65 | 66 | SwingUtilities.invokeLater( new Runnable(){ 67 | public void run() { 68 | new MainUI(); 69 | } 70 | 71 | }); 72 | } 73 | } -------------------------------------------------------------------------------- /src/com/VPN/ServerClientStub.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | 4 | public class ServerClientStub implements CryptoInterface { 5 | 6 | private static ServerClientStub s_server; 7 | private static ServerClientStub s_client; 8 | 9 | private GUIInterface m_gui; 10 | public ServerClientStub(GUIInterface gui) 11 | { 12 | m_gui = gui; 13 | } 14 | @Override 15 | public void receiveMessages(){} 16 | @Override 17 | public void acceptConnection(){} 18 | @Override 19 | public void closeServer() 20 | { 21 | if( this != s_server) return; 22 | ServerClientStub server = s_server; 23 | s_server = null; 24 | server.endConnection(); 25 | if( s_client != null )s_client.endConnection(); 26 | 27 | } 28 | @Override 29 | public void endConnection() { 30 | 31 | if( this == s_server) 32 | { 33 | if(s_client != null )s_client.endConnection(); 34 | } 35 | else if( this == s_client) 36 | { 37 | s_client = null; 38 | if( s_server != null )s_server.endConnection(); 39 | } 40 | m_gui.connectionClosed(); 41 | } 42 | protected void receiveMessage(String s) 43 | { 44 | m_gui.printf(s); 45 | } 46 | 47 | @Override 48 | public boolean sendMessage(String s) { 49 | 50 | if( this == s_server && s_client != null ) 51 | { 52 | s_client.receiveMessage(s); 53 | return true; 54 | } 55 | else if( this == s_client && s_server != null ) 56 | { 57 | s_server.receiveMessage(s); 58 | return true; 59 | } 60 | return false; 61 | } 62 | 63 | @Override 64 | public boolean startClient(String host, int port, String sharedKey) { 65 | 66 | if( s_server == null ) return false; 67 | 68 | s_server.startConnection(); 69 | s_client = this; 70 | startConnection(); 71 | return true; 72 | } 73 | 74 | protected void startConnection() 75 | { 76 | m_gui.connectionReady(); 77 | } 78 | 79 | @Override 80 | public boolean startServer(int port, String sharedKey) { 81 | s_server = this; 82 | return true; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/com/VPN/DiffieHellmanHelper.java: -------------------------------------------------------------------------------- 1 | 2 | package com.EECE412A3; 3 | import java.security.AlgorithmParameterGenerator; 4 | import java.security.AlgorithmParameters; 5 | import java.security.InvalidAlgorithmParameterException; 6 | import java.security.InvalidKeyException; 7 | import java.security.KeyFactory; 8 | import java.security.KeyPair; 9 | import java.security.KeyPairGenerator; 10 | import java.security.NoSuchAlgorithmException; 11 | import java.security.PublicKey; 12 | import java.security.spec.InvalidKeySpecException; 13 | import java.security.spec.InvalidParameterSpecException; 14 | import java.security.spec.X509EncodedKeySpec; 15 | 16 | import javax.crypto.KeyAgreement; 17 | import javax.crypto.spec.DHParameterSpec; 18 | 19 | 20 | public class DiffieHellmanHelper { 21 | 22 | public KeyAgreement keyAgreement; 23 | 24 | // Used source from http://docs.oracle.com/javase/1.4.2/docs/guide/security/jce/JCERefGuide.html to help with DHHandshake 25 | 26 | public DHParameterSpec generateDiffieHellmanParameters() throws NoSuchAlgorithmException, InvalidParameterSpecException { 27 | AlgorithmParameterGenerator paramGen = AlgorithmParameterGenerator.getInstance("DH"); 28 | paramGen.init(512); 29 | AlgorithmParameters params = paramGen.generateParameters(); 30 | return (DHParameterSpec) params.getParameterSpec(DHParameterSpec.class); 31 | } 32 | 33 | public KeyPair createKeyPair(DHParameterSpec diffieHellmanParameters) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, InvalidKeyException { 34 | KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); 35 | keyPairGenerator.initialize(diffieHellmanParameters); 36 | KeyPair keyPair = keyPairGenerator.generateKeyPair(); 37 | setKeyAgreement(KeyAgreement.getInstance("DH")); 38 | getKeyAgreement().init(keyPair.getPrivate()); 39 | return keyPair; 40 | } 41 | 42 | public PublicKey getUnencodedPublicKey(byte[] publicKeyEncoded) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IllegalStateException { 43 | KeyFactory keyFactory = KeyFactory.getInstance("DH"); 44 | X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyEncoded); 45 | return keyFactory.generatePublic(x509EncodedKeySpec); 46 | } 47 | 48 | public KeyAgreement getKeyAgreement() { 49 | return keyAgreement; 50 | } 51 | 52 | public void setKeyAgreement(KeyAgreement keyAgreement) { 53 | this.keyAgreement = keyAgreement; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/com/VPN/ServerUI.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | import java.awt.TextField; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | import java.io.IOException; 7 | import java.net.ServerSocket; 8 | 9 | import javax.swing.JButton; 10 | import javax.swing.JFrame; 11 | import javax.swing.JLabel; 12 | import javax.swing.JScrollPane; 13 | import javax.swing.JTextArea; 14 | import javax.swing.SpringLayout; 15 | 16 | import com.EECE412A3.Server.Server; 17 | 18 | @SuppressWarnings("serial") 19 | public class ServerUI extends JFrame implements ActionListener, GUIInterface { 20 | 21 | //Port 22 | private JLabel m_lblPort; 23 | private TextField m_txtPort; 24 | 25 | //Shared Key 26 | private JLabel m_lblSharedKey; 27 | private TextField m_txtSharedKey; 28 | 29 | //Start / Stop 30 | private JButton m_btnStart; 31 | private JButton m_btnStop; 32 | 33 | //Data to be Sent 34 | private JLabel m_lblInput; 35 | private TextField m_txtInput; 36 | private JButton m_btnInput; 37 | 38 | //Data as Received 39 | private JLabel m_lblConsole; 40 | private JTextArea m_txtConsole; 41 | 42 | private CryptoInterface m_crypto; 43 | 44 | public ServerUI() 45 | { 46 | super("Server"); 47 | this.setSize(500,800); 48 | this.setLocationRelativeTo(null); 49 | this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 50 | SpringLayout layout = new SpringLayout(); 51 | this.setLayout( layout ); 52 | this.setVisible(true); 53 | 54 | 55 | //Port 56 | m_lblPort = new JLabel("Port:"); 57 | m_txtPort = new TextField(10); 58 | 59 | //Shared Key 60 | m_lblSharedKey = new JLabel("Shared Key:"); 61 | m_txtSharedKey = new TextField(25); 62 | 63 | 64 | //Start / Stop 65 | m_btnStart = new JButton("Start Server"); 66 | m_btnStop = new JButton("Stop Server"); 67 | m_btnStop.setEnabled(false); 68 | m_btnStart.addActionListener(this); 69 | m_btnStop.addActionListener(this); 70 | 71 | //Data to be Sent 72 | m_lblInput = new JLabel("Data to be Sent:"); 73 | m_txtInput = new TextField(); 74 | m_btnInput = new JButton("Send"); 75 | m_txtInput.setEditable(false); 76 | m_btnInput.setEnabled(false); 77 | m_btnInput.addActionListener(this); 78 | 79 | //Data as Received 80 | m_lblConsole = new JLabel("Data as Received:"); 81 | m_txtConsole = new JTextArea(); 82 | m_txtConsole.setEditable(false); 83 | JScrollPane txtConsoleScroll = new JScrollPane(m_txtConsole); 84 | 85 | //Port 86 | layout.putConstraint(SpringLayout.WEST, m_txtPort, 110, SpringLayout.WEST, this.getContentPane()); 87 | layout.putConstraint(SpringLayout.EAST, m_lblPort, -5, SpringLayout.WEST, m_txtPort); 88 | 89 | //Shared Key 90 | layout.putConstraint(SpringLayout.WEST, m_txtSharedKey, 0, SpringLayout.WEST, m_txtPort ); 91 | layout.putConstraint(SpringLayout.NORTH, m_txtSharedKey, 5, SpringLayout.SOUTH, m_txtPort ); 92 | layout.putConstraint(SpringLayout.EAST, m_txtSharedKey, -5, SpringLayout.EAST, this.getContentPane()); 93 | 94 | layout.putConstraint(SpringLayout.EAST, m_lblSharedKey, -5, SpringLayout.WEST, m_txtPort ); 95 | layout.putConstraint(SpringLayout.NORTH, m_lblSharedKey, 5, SpringLayout.SOUTH, m_txtPort ); 96 | 97 | 98 | //Start / Stop 99 | layout.putConstraint(SpringLayout.NORTH, m_btnStart, 5, SpringLayout.SOUTH, m_txtSharedKey); 100 | layout.putConstraint(SpringLayout.WEST, m_btnStart, 0, SpringLayout.WEST, m_txtSharedKey); 101 | 102 | layout.putConstraint(SpringLayout.NORTH, m_btnStop, 5, SpringLayout.SOUTH, m_txtSharedKey); 103 | layout.putConstraint(SpringLayout.WEST, m_btnStop, 5, SpringLayout.EAST, m_btnStart); 104 | 105 | //Data to be Sent 106 | layout.putConstraint(SpringLayout.WEST, m_txtInput, 0, SpringLayout.WEST, m_btnStart ); 107 | layout.putConstraint(SpringLayout.NORTH, m_txtInput, 5, SpringLayout.SOUTH, m_btnStart ); 108 | layout.putConstraint(SpringLayout.EAST, m_txtInput, -74, SpringLayout.EAST, this.getContentPane()); 109 | 110 | layout.putConstraint(SpringLayout.EAST, m_lblInput, -5, SpringLayout.WEST, m_btnStart); 111 | layout.putConstraint(SpringLayout.NORTH, m_lblInput, 5, SpringLayout.SOUTH, m_btnStart ); 112 | 113 | layout.putConstraint(SpringLayout.WEST, m_btnInput, 5, SpringLayout.EAST, m_txtInput ); 114 | layout.putConstraint(SpringLayout.NORTH, m_btnInput, 5, SpringLayout.SOUTH, m_btnStart ); 115 | 116 | 117 | //Data as Received 118 | layout.putConstraint(SpringLayout.WEST, txtConsoleScroll, 0, SpringLayout.WEST, m_txtInput ); 119 | layout.putConstraint(SpringLayout.NORTH, txtConsoleScroll, 5, SpringLayout.SOUTH, m_txtInput ); 120 | layout.putConstraint(SpringLayout.SOUTH, txtConsoleScroll, -5, SpringLayout.SOUTH, this.getContentPane()); 121 | layout.putConstraint(SpringLayout.EAST, txtConsoleScroll, -5, SpringLayout.EAST, this.getContentPane()); 122 | 123 | layout.putConstraint(SpringLayout.EAST, m_lblConsole, -5, SpringLayout.WEST, txtConsoleScroll ); 124 | layout.putConstraint(SpringLayout.NORTH, m_lblConsole, 5, SpringLayout.SOUTH, m_txtInput ); 125 | 126 | 127 | //Port 128 | this.add(m_lblPort); 129 | this.add(m_txtPort); 130 | 131 | //Shared Key 132 | this.add(m_lblSharedKey); 133 | this.add(m_txtSharedKey); 134 | 135 | //Start / Stop 136 | this.add(m_btnStart); 137 | this.add(m_btnStop); 138 | 139 | //Data to be Sent 140 | this.add(m_lblInput); 141 | this.add(m_txtInput); 142 | this.add(m_btnInput); 143 | 144 | //Data as Received 145 | this.add(m_lblConsole); 146 | this.add(txtConsoleScroll); 147 | 148 | m_crypto = new Server(this); 149 | } 150 | 151 | public void actionPerformed( ActionEvent e ) 152 | { 153 | if(e.getSource() == m_btnStart) start(); 154 | else if(e.getSource() == m_btnStop) stop(); 155 | else if(e.getSource() == m_btnInput ) send(); 156 | } 157 | 158 | private void send() 159 | { 160 | String data = m_txtInput.getText(); 161 | //printf("Sending message: " + data); 162 | if(m_crypto.sendMessage( data )) 163 | { 164 | //printf("Sucessfully sent message"); 165 | } 166 | else 167 | { 168 | printf("Unable to send message"); 169 | } 170 | } 171 | private void stop() 172 | { 173 | m_crypto.closeServer(); 174 | printf("Server Stopped."); 175 | m_btnStop.setEnabled(false); 176 | m_btnStart.setEnabled(true); 177 | } 178 | private void start() 179 | { 180 | int port; 181 | String sharedKey = m_txtSharedKey.getText(); 182 | try 183 | { 184 | port = Integer.valueOf(m_txtPort.getText()); 185 | } 186 | catch( NumberFormatException e) 187 | { 188 | printf("Port is not a valid number"); 189 | return; 190 | } 191 | 192 | if( sharedKey.length() == 0 ) 193 | { 194 | printf("Shared Key can not be empty"); 195 | return; 196 | } 197 | 198 | m_btnStart.setEnabled(false); 199 | if(m_crypto.startServer(port, sharedKey)) 200 | { 201 | 202 | printf("Started Server.\n Waiting for connections..."); 203 | Thread t = new Thread(new Runnable(){ 204 | public void run() { 205 | m_crypto.acceptConnection(); 206 | } 207 | }); 208 | t.start(); 209 | } 210 | else 211 | { 212 | printf("Server unable to start."); 213 | m_btnStart.setEnabled(true); 214 | } 215 | } 216 | 217 | @Override 218 | public void printf(String s) 219 | { 220 | m_txtConsole.setText(m_txtConsole.getText() + s + "\n" ); 221 | } 222 | 223 | @Override 224 | public void connectionReady() { 225 | printf("Connection established."); 226 | m_txtInput.setEditable(true); 227 | m_btnInput.setEnabled(true); 228 | m_btnStop.setEnabled(true); 229 | m_btnStart.setEnabled(false); 230 | Thread t = new Thread(new Runnable(){ 231 | public void run(){ 232 | m_crypto.receiveMessages(); 233 | } 234 | }); 235 | t.start(); 236 | } 237 | @Override 238 | public void connectionClosed() 239 | { 240 | printf("Conection closed"); 241 | m_txtInput.setEditable(false); 242 | m_btnInput.setEnabled(false); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/com/VPN/ClientUI.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3; 2 | 3 | import java.awt.TextField; 4 | import java.awt.event.ActionEvent; 5 | import java.awt.event.ActionListener; 6 | 7 | import javax.swing.JButton; 8 | import javax.swing.JFrame; 9 | import javax.swing.JLabel; 10 | import javax.swing.JScrollPane; 11 | import javax.swing.JTextArea; 12 | import javax.swing.SpringLayout; 13 | 14 | import com.EECE412A3.Client.Client; 15 | import com.EECE412A3.Client.ClientInterface; 16 | 17 | 18 | 19 | @SuppressWarnings("serial") 20 | public class ClientUI extends JFrame implements ActionListener, GUIInterface { 21 | 22 | //Host 23 | private JLabel m_lblHost; 24 | private TextField m_txtHost; 25 | 26 | //Port 27 | private JLabel m_lblPort; 28 | private TextField m_txtPort; 29 | 30 | //Shared Key 31 | private JLabel m_lblSharedKey; 32 | private TextField m_txtSharedKey; 33 | 34 | //Start / Stop 35 | private JButton m_btnStart; 36 | private JButton m_btnStop; 37 | 38 | //Data to be Sent 39 | private JLabel m_lblInput; 40 | private TextField m_txtInput; 41 | private JButton m_btnInput; 42 | 43 | //Data as Received 44 | private JLabel m_lblConsole; 45 | private JTextArea m_txtConsole; 46 | 47 | private ClientInterface m_crypto; 48 | 49 | public ClientUI() 50 | { 51 | super("Client"); 52 | this.setSize(500,800); 53 | this.setLocationRelativeTo(null); 54 | this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 55 | SpringLayout layout = new SpringLayout(); 56 | this.setLayout( layout ); 57 | this.setVisible(true); 58 | 59 | //Host 60 | m_lblHost = new JLabel("Host:"); 61 | m_txtHost = new TextField(25); 62 | 63 | //Port 64 | m_lblPort = new JLabel("Port:"); 65 | m_txtPort = new TextField(10); 66 | 67 | //Shared Key 68 | m_lblSharedKey = new JLabel("Shared Key:"); 69 | m_txtSharedKey = new TextField(25); 70 | 71 | 72 | //Start / Stop 73 | m_btnStart = new JButton("Connect"); 74 | m_btnStop = new JButton("Disconnect"); 75 | m_btnStop.setEnabled(false); 76 | m_btnStart.addActionListener(this); 77 | m_btnStop.addActionListener(this); 78 | 79 | //Data to be Sent 80 | m_lblInput = new JLabel("Data to be Sent:"); 81 | m_txtInput = new TextField(); 82 | m_btnInput = new JButton("Send"); 83 | m_txtInput.setEditable(false); 84 | m_btnInput.setEnabled(false); 85 | m_btnInput.addActionListener(this); 86 | 87 | //Data as Received 88 | m_lblConsole = new JLabel("Data as Received:"); 89 | m_txtConsole = new JTextArea(); 90 | m_txtConsole.setEditable(false); 91 | JScrollPane txtConsoleScroll = new JScrollPane(m_txtConsole); 92 | 93 | //Host 94 | layout.putConstraint(SpringLayout.WEST, m_txtHost, 110, SpringLayout.WEST, this.getContentPane()); 95 | layout.putConstraint(SpringLayout.EAST, m_txtHost, -5, SpringLayout.EAST, this.getContentPane()); 96 | 97 | layout.putConstraint(SpringLayout.EAST, m_lblHost, -5, SpringLayout.WEST, m_txtHost); 98 | 99 | //Port 100 | layout.putConstraint(SpringLayout.WEST, m_txtPort, 0, SpringLayout.WEST, m_txtHost); 101 | layout.putConstraint(SpringLayout.NORTH, m_txtPort, 5, SpringLayout.SOUTH, m_txtHost ); 102 | 103 | layout.putConstraint(SpringLayout.EAST, m_lblPort, -5, SpringLayout.WEST, m_txtPort); 104 | layout.putConstraint(SpringLayout.NORTH, m_lblPort, 5, SpringLayout.SOUTH, m_txtHost ); 105 | 106 | //Shared Key 107 | layout.putConstraint(SpringLayout.WEST, m_txtSharedKey, 0, SpringLayout.WEST, m_txtPort ); 108 | layout.putConstraint(SpringLayout.NORTH, m_txtSharedKey, 5, SpringLayout.SOUTH, m_txtPort ); 109 | layout.putConstraint(SpringLayout.EAST, m_txtSharedKey, -5, SpringLayout.EAST, this.getContentPane()); 110 | 111 | layout.putConstraint(SpringLayout.EAST, m_lblSharedKey, -5, SpringLayout.WEST, m_txtPort ); 112 | layout.putConstraint(SpringLayout.NORTH, m_lblSharedKey, 5, SpringLayout.SOUTH, m_txtPort ); 113 | 114 | 115 | //Start / Stop 116 | layout.putConstraint(SpringLayout.NORTH, m_btnStart, 5, SpringLayout.SOUTH, m_txtSharedKey); 117 | layout.putConstraint(SpringLayout.WEST, m_btnStart, 0, SpringLayout.WEST, m_txtSharedKey); 118 | 119 | layout.putConstraint(SpringLayout.NORTH, m_btnStop, 5, SpringLayout.SOUTH, m_txtSharedKey); 120 | layout.putConstraint(SpringLayout.WEST, m_btnStop, 5, SpringLayout.EAST, m_btnStart); 121 | 122 | //Data to be Sent 123 | layout.putConstraint(SpringLayout.WEST, m_txtInput, 0, SpringLayout.WEST, m_btnStart ); 124 | layout.putConstraint(SpringLayout.NORTH, m_txtInput, 5, SpringLayout.SOUTH, m_btnStart ); 125 | layout.putConstraint(SpringLayout.EAST, m_txtInput, -74, SpringLayout.EAST, this.getContentPane()); 126 | 127 | layout.putConstraint(SpringLayout.EAST, m_lblInput, -5, SpringLayout.WEST, m_btnStart); 128 | layout.putConstraint(SpringLayout.NORTH, m_lblInput, 5, SpringLayout.SOUTH, m_btnStart ); 129 | 130 | layout.putConstraint(SpringLayout.WEST, m_btnInput, 5, SpringLayout.EAST, m_txtInput ); 131 | layout.putConstraint(SpringLayout.NORTH, m_btnInput, 5, SpringLayout.SOUTH, m_btnStart ); 132 | 133 | 134 | //Data as Received 135 | layout.putConstraint(SpringLayout.WEST, txtConsoleScroll, 0, SpringLayout.WEST, m_txtInput ); 136 | layout.putConstraint(SpringLayout.NORTH, txtConsoleScroll, 5, SpringLayout.SOUTH, m_txtInput ); 137 | layout.putConstraint(SpringLayout.SOUTH, txtConsoleScroll, -5, SpringLayout.SOUTH, this.getContentPane()); 138 | layout.putConstraint(SpringLayout.EAST, txtConsoleScroll, -5, SpringLayout.EAST, this.getContentPane()); 139 | 140 | layout.putConstraint(SpringLayout.EAST, m_lblConsole, -5, SpringLayout.WEST, txtConsoleScroll ); 141 | layout.putConstraint(SpringLayout.NORTH, m_lblConsole, 5, SpringLayout.SOUTH, m_txtInput ); 142 | 143 | //Host 144 | this.add(m_lblHost); 145 | this.add(m_txtHost); 146 | 147 | //Port 148 | this.add(m_lblPort); 149 | this.add(m_txtPort); 150 | 151 | //Shared Key 152 | this.add(m_lblSharedKey); 153 | this.add(m_txtSharedKey); 154 | 155 | //Start / Stop 156 | this.add(m_btnStart); 157 | this.add(m_btnStop); 158 | 159 | //Data to be Sent 160 | this.add(m_lblInput); 161 | this.add(m_txtInput); 162 | this.add(m_btnInput); 163 | 164 | //Data as Received 165 | this.add(m_lblConsole); 166 | this.add(txtConsoleScroll); 167 | 168 | m_crypto = new Client(this); 169 | } 170 | 171 | public void actionPerformed( ActionEvent e ) 172 | { 173 | if(e.getSource() == m_btnStart) start(); 174 | else if(e.getSource() == m_btnStop) stop(); 175 | else if(e.getSource() == m_btnInput ) send(); 176 | } 177 | 178 | private void send() 179 | { 180 | String data = m_txtInput.getText(); 181 | //printf("Sending message: " + data); 182 | if(m_crypto.sendMessage( data )) 183 | { 184 | //printf("Sucessfully sent message"); 185 | } 186 | else 187 | { 188 | printf("Unable to send message"); 189 | } 190 | } 191 | private void stop() 192 | { 193 | m_crypto.endConnection(); 194 | 195 | } 196 | private void start() 197 | { 198 | int port; 199 | String sharedKey = m_txtSharedKey.getText(); 200 | String host = m_txtHost.getText(); 201 | if( host.length() == 0 ) 202 | { 203 | printf("Host can not be empty"); 204 | return; 205 | } 206 | 207 | try 208 | { 209 | port = Integer.valueOf(m_txtPort.getText()); 210 | } 211 | catch( NumberFormatException e) 212 | { 213 | printf("Port is not a valid number"); 214 | return; 215 | } 216 | 217 | if( sharedKey.length() == 0 ) 218 | { 219 | printf("Shared Key can not be empty"); 220 | return; 221 | } 222 | 223 | m_btnStart.setEnabled(false); 224 | if(!m_crypto.startClient(host, port, sharedKey)) 225 | { 226 | printf("Unable to establish connection to server."); 227 | m_btnStart.setEnabled(true); 228 | } 229 | } 230 | 231 | @Override 232 | public void printf(String s) 233 | { 234 | m_txtConsole.setText(m_txtConsole.getText() + s + "\n" ); 235 | } 236 | 237 | @Override 238 | public void connectionReady() { 239 | printf("Connection established."); 240 | m_txtInput.setEditable(true); 241 | m_btnInput.setEnabled(true); 242 | m_btnStop.setEnabled(true); 243 | m_btnStart.setEnabled(false); 244 | Thread t = new Thread(new Runnable(){ 245 | public void run(){ 246 | m_crypto.receiveMessages(); 247 | } 248 | }); 249 | t.start(); 250 | } 251 | @Override 252 | public void connectionClosed() 253 | { 254 | printf("Client Stopped."); 255 | m_txtInput.setEditable(false); 256 | m_btnInput.setEnabled(false); 257 | m_btnStop.setEnabled(false); 258 | m_btnStart.setEnabled(true); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/com/VPN/Client/Client.java: -------------------------------------------------------------------------------- 1 | package com.EECE412A3.Client; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStream; 8 | import java.net.Socket; 9 | import java.nio.ByteBuffer; 10 | import java.security.InvalidAlgorithmParameterException; 11 | import java.security.InvalidKeyException; 12 | import java.security.KeyPair; 13 | import java.security.NoSuchAlgorithmException; 14 | import java.security.PublicKey; 15 | import java.security.spec.InvalidKeySpecException; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.Cipher; 19 | import javax.crypto.IllegalBlockSizeException; 20 | import javax.crypto.NoSuchPaddingException; 21 | import javax.crypto.SecretKey; 22 | import javax.crypto.SecretKeyFactory; 23 | import javax.crypto.interfaces.DHPublicKey; 24 | import javax.crypto.spec.DHParameterSpec; 25 | import javax.crypto.spec.PBEKeySpec; 26 | import javax.crypto.spec.PBEParameterSpec; 27 | import javax.xml.bind.DatatypeConverter; 28 | 29 | import com.EECE412A3.CryptoInterface; 30 | import com.EECE412A3.DiffieHellmanHelper; 31 | import com.EECE412A3.GUIInterface; 32 | import com.EECE412A3.Helpers; 33 | 34 | 35 | public class Client implements ClientInterface { 36 | 37 | //Encryption Constants 38 | private static final byte[] SALT = {(byte) 0xa0, (byte) 0x4e, (byte) 0x2b, (byte) 0x92, (byte) 0x4a, (byte) 0xd6, (byte) 0x59, (byte) 0x86}; 39 | private static final int ITERATION_COUNT = 25; 40 | 41 | private static PBEParameterSpec pbeParamSpec; 42 | 43 | private static final String SERVER_IDENTIFICATION = "server"; 44 | private static final String CLIENT_IDENTIFICATION = "client"; 45 | 46 | private GUIInterface m_gui; 47 | 48 | //communication streams 49 | private OutputStream out; 50 | private InputStream in; 51 | 52 | private String sharedSecret; //shared key 53 | private SecretKey DESK; //session key 54 | 55 | public Client(GUIInterface gui) 56 | { 57 | m_gui = gui; 58 | } 59 | 60 | 61 | @Override 62 | public void endConnection() 63 | { 64 | } 65 | 66 | @Override 67 | public void receiveMessages() 68 | { 69 | while(true) 70 | { 71 | try 72 | { 73 | byte[] input = read(in); 74 | m_gui.printf("Receiving encrypted bytes: " + Helpers.ByteToString(input)); 75 | String modifiedSentence = new String(decryptDES(DESK, input)); 76 | m_gui.printf(SERVER_IDENTIFICATION + " > " + modifiedSentence); 77 | 78 | } 79 | catch(Exception e) 80 | {} 81 | } 82 | } 83 | 84 | @Override 85 | public boolean sendMessage(String s) 86 | { 87 | try 88 | { 89 | m_gui.printf("Sending message: " + s ); 90 | byte[] output = s.getBytes(); 91 | m_gui.printf("Bytes: " + Helpers.ByteToString(output)); 92 | byte[] encrypted = encryptDES(DESK, output); 93 | m_gui.printf("Sending Encrypted bytes: " + Helpers.ByteToString(encrypted)); 94 | write(out, encrypted); 95 | m_gui.printf(CLIENT_IDENTIFICATION + " > " + s); 96 | } 97 | catch(Exception e ) 98 | { 99 | return false; 100 | } 101 | return true; 102 | } 103 | 104 | @Override 105 | public boolean startClient(String host, int port, String sharedKey) 106 | { 107 | sharedSecret = sharedKey; 108 | try 109 | { 110 | Socket clientSocket = new Socket(host,port); 111 | 112 | DiffieHellmanHelper helpme = new DiffieHellmanHelper(); 113 | 114 | BufferedReader userdata = new BufferedReader(new InputStreamReader(System.in)); 115 | out = clientSocket.getOutputStream(); 116 | in = clientSocket.getInputStream(); 117 | 118 | //start the handshake 119 | String clientChallenge = java.util.UUID.randomUUID().toString(); 120 | String phase1 = CLIENT_IDENTIFICATION+","+ clientChallenge; 121 | 122 | m_gui.printf("Sending handshake message: " + phase1 ); 123 | 124 | write(out, phase1.getBytes()); 125 | m_gui.printf("Waiting for Server respond with its challenge..."); 126 | 127 | //read the server's public key 128 | // char[] serverPublicKeyEncoded = new char[255]; 129 | // inFromServer.read(serverPublicKeyEncoded); 130 | byte[] serverChallenge = read(in); 131 | 132 | byte[] serverid = encryptHandshake(sharedSecret, read(in), Cipher.DECRYPT_MODE); 133 | byte[] clientChallengeFromServerBytes = encryptHandshake(sharedSecret, read(in), Cipher.DECRYPT_MODE); 134 | byte[] serverPublickKeyEnc = encryptHandshake(sharedSecret, read(in), Cipher.DECRYPT_MODE); 135 | 136 | m_gui.printf("Challenge From Server: " + new String(serverChallenge)); 137 | //CHECK IF THE VALUES RECIEVED MATCH THE ORIGINAL VLUES!!!!!!!!! 138 | String clientChallengeFromServer = new String(clientChallengeFromServerBytes); 139 | 140 | if (!clientChallengeFromServer.equals(clientChallenge)) { 141 | m_gui.printf("Server returned incorrect challenge, terminating program"); 142 | return false; 143 | } 144 | 145 | String serverIdentification = new String(serverid); 146 | m_gui.printf("Sever id: " + serverIdentification); 147 | if (!serverIdentification.equals(SERVER_IDENTIFICATION)) { 148 | m_gui.printf("Connected to incorrect server, terminating program"); 149 | 150 | return false; 151 | } 152 | m_gui.printf("Connection to "+ serverIdentification + " has been established. Completing handshake protocol.."); 153 | 154 | // instantiate a DH public key from the encoded key material and get key parameters. 155 | PublicKey serverPubK = helpme.getUnencodedPublicKey(serverPublickKeyEnc); 156 | DHParameterSpec DHParams = ((DHPublicKey)serverPubK).getParams(); 157 | 158 | //Generate client key pair using the params from the servers key 159 | KeyPair clientKeyPair = helpme.createKeyPair(DHParams); 160 | m_gui.printf("sending client session Key: " + clientKeyPair); 161 | //encode pubk and send it over to server 162 | byte[] clientEncPubk = clientKeyPair.getPublic().getEncoded(); 163 | m_gui.printf("Encoded pubk(client): " + DatatypeConverter.printHexBinary(clientEncPubk)); 164 | 165 | //Return to the server with client Authentication 166 | 167 | //client id 168 | write(out, encryptHandshake(sharedSecret, "client".getBytes(), Cipher.ENCRYPT_MODE)); 169 | //return the challenge sent from the server 170 | write(out, encryptHandshake(sharedSecret, serverChallenge, Cipher.ENCRYPT_MODE)); 171 | //send client Public key 172 | write(out, encryptHandshake(sharedSecret, clientEncPubk, Cipher.ENCRYPT_MODE)); 173 | 174 | //Set serverPubK in the agreement 175 | helpme.keyAgreement.doPhase(serverPubK, true); 176 | 177 | //generate the secret symmetric key 178 | byte[] sharedSecretKey = helpme.keyAgreement.generateSecret(); 179 | 180 | m_gui.printf("shared k(client): " + DatatypeConverter.printHexBinary(sharedSecretKey)); 181 | 182 | 183 | //since the Key Agreement object was reset we regen it 184 | helpme.keyAgreement.doPhase(serverPubK, true); 185 | DESK = helpme.keyAgreement.generateSecret("DES"); 186 | m_gui.connectionReady(); 187 | } 188 | catch(Exception e) 189 | { 190 | return false; 191 | } 192 | return true; 193 | } 194 | 195 | public byte[] read(InputStream in) throws IOException{ 196 | byte[] lenPackage = new byte[4]; 197 | in.read(lenPackage, 0, 4); 198 | ByteBuffer bb = ByteBuffer.wrap(lenPackage); 199 | int actuallen = bb.getInt(); 200 | byte[] finalbb = new byte[actuallen]; 201 | in.read(finalbb); 202 | return finalbb; 203 | } 204 | 205 | public void write(OutputStream out, byte[] towrite) throws IOException{ 206 | ByteBuffer bb = ByteBuffer.allocate(4); 207 | bb.putInt(towrite.length); 208 | out.write(bb.array()); 209 | out.write(towrite); 210 | out.flush(); 211 | } 212 | 213 | public byte[] encryptDES(SecretKey k,byte[] plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ 214 | // Create PBE Cipher 215 | Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 216 | // Initialize PBE Cipher with key and parameters 217 | desCipher.init(Cipher.ENCRYPT_MODE, k); 218 | // Encrypt the cleartext 219 | return desCipher.doFinal(plaintext); 220 | } 221 | 222 | public byte[] decryptDES(SecretKey k, byte[] plaintext) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ 223 | // Create PBE Cipher 224 | Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 225 | // Initialize PBE Cipher with key and parameters 226 | desCipher.init(Cipher.DECRYPT_MODE, k); 227 | // Encrypt the cleartext 228 | return desCipher.doFinal(plaintext); 229 | } 230 | 231 | public byte[] encryptHandshake(String sharedSecretKey, byte[] plainText, int encryption_mode) throws NoSuchAlgorithmException, 232 | InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { 233 | PBEParameterSpec handshakeParamSpec = new PBEParameterSpec(SALT, ITERATION_COUNT); 234 | PBEKeySpec handshakeKeySpec = new PBEKeySpec(sharedSecretKey.toCharArray()); 235 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); 236 | SecretKey pbeKey = keyFactory.generateSecret(handshakeKeySpec); 237 | Cipher handshakeCipher = Cipher.getInstance("PBEWithMD5AndDES"); 238 | handshakeCipher.init(encryption_mode, pbeKey, handshakeParamSpec); 239 | return handshakeCipher.doFinal(plainText); 240 | } 241 | 242 | } 243 | -------------------------------------------------------------------------------- /src/com/VPN/Server/Server.java: -------------------------------------------------------------------------------- 1 | 2 | package com.EECE412A3.Server; 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | import java.nio.ByteBuffer; 9 | import java.security.InvalidAlgorithmParameterException; 10 | import java.security.InvalidKeyException; 11 | import java.security.KeyPair; 12 | import java.security.NoSuchAlgorithmException; 13 | import java.security.PublicKey; 14 | import java.security.spec.InvalidKeySpecException; 15 | 16 | import javax.crypto.BadPaddingException; 17 | import javax.crypto.Cipher; 18 | import javax.crypto.IllegalBlockSizeException; 19 | import javax.crypto.NoSuchPaddingException; 20 | import javax.crypto.SecretKey; 21 | import javax.crypto.SecretKeyFactory; 22 | import javax.crypto.spec.DHParameterSpec; 23 | import javax.crypto.spec.PBEKeySpec; 24 | import javax.crypto.spec.PBEParameterSpec; 25 | import javax.xml.bind.DatatypeConverter; 26 | 27 | import com.EECE412A3.CryptoInterface; 28 | import com.EECE412A3.DiffieHellmanHelper; 29 | import com.EECE412A3.GUIInterface; 30 | import com.EECE412A3.Helpers; 31 | 32 | public class Server implements CryptoInterface { 33 | 34 | private GUIInterface m_gui; 35 | 36 | private static final String SERVER_IDENTIFICATION = "server"; 37 | 38 | private static final byte[] SALT = {(byte)0xa0, (byte)0x4e, (byte)0x2b, (byte)0x92, (byte)0x4a, (byte)0xd6, (byte)0x59, (byte)0x86}; 39 | 40 | private static final int ITERATION_COUNT = 25; 41 | private Socket connectionSocket = null; 42 | private ServerSocket serverSocket =null; 43 | private String sharedSecretKey; 44 | private Cipher communicationEncryptionCipher; 45 | private Cipher communicationDecryptionCipher; 46 | private InputStream inputStream; 47 | private OutputStream outputStream; 48 | private String clientId; 49 | 50 | public Server(GUIInterface gui) 51 | { 52 | m_gui = gui; 53 | } 54 | 55 | @Override 56 | public void closeServer() 57 | { 58 | } 59 | 60 | @Override 61 | public void endConnection() 62 | { 63 | } 64 | @Override 65 | public void receiveMessages() 66 | { 67 | while(true) 68 | { 69 | try 70 | { 71 | byte[] clientInput = readFromClient(inputStream); 72 | m_gui.printf("Receiving encrypted bytes: " + Helpers.ByteToString(clientInput)); 73 | String clientInputDecrypted = new String(communicationDecryptionCipher.doFinal(clientInput)); 74 | m_gui.printf( clientId + " > " + clientInputDecrypted); 75 | } 76 | catch(Exception e ) 77 | { 78 | 79 | } 80 | } 81 | } 82 | 83 | @Override 84 | public boolean sendMessage(String s) 85 | { 86 | try 87 | { 88 | m_gui.printf("Sending Message: " + s ); 89 | byte[] bytes = s.getBytes(); 90 | m_gui.printf("Bytes: " + Helpers.ByteToString(bytes) ); 91 | byte[] encrypted = communicationEncryptionCipher.doFinal(bytes); 92 | m_gui.printf("Sending Encrypted bytes: " + Helpers.ByteToString(encrypted) ); 93 | writeToClient(outputStream, encrypted); 94 | m_gui.printf(SERVER_IDENTIFICATION + " > " + s); 95 | } 96 | catch(Exception e ) 97 | { 98 | return false; 99 | } 100 | return true; 101 | } 102 | 103 | @Override 104 | public boolean startClient(String host, int port, String sharedKey) 105 | { 106 | throw new RuntimeException("Not Implemented"); 107 | } 108 | 109 | /*protected void startConnection() 110 | { 111 | m_gui.connectionReady(); 112 | }*/ 113 | 114 | @Override 115 | public boolean startServer(int port, String sharedKey) { 116 | 117 | try 118 | { 119 | sharedSecretKey = sharedKey; 120 | serverSocket = new ServerSocket(port); 121 | } 122 | catch(IOException e) 123 | { 124 | m_gui.printf("Server Error: " + e.getMessage() ); 125 | return false; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | @Override 132 | public void acceptConnection() 133 | { 134 | 135 | try 136 | { 137 | if( serverSocket != null ) 138 | connectionSocket = serverSocket.accept(); 139 | 140 | if(connectionSocket == null ) m_gui.connectionClosed(); 141 | 142 | inputStream = connectionSocket.getInputStream(); 143 | outputStream = connectionSocket.getOutputStream(); 144 | //BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in)); 145 | 146 | DiffieHellmanHelper diffieHellmanHelper = new DiffieHellmanHelper(); 147 | 148 | // Receive identification data from client. 149 | byte[] identificationData = readFromClient(inputStream); 150 | String identificationString = new String(identificationData); 151 | m_gui.printf("Receiving handshake message: " + identificationString); 152 | 153 | String[] identificationArray = identificationString.split(",");; 154 | clientId = identificationArray[0]; 155 | String clientChallenge = identificationArray[1]; 156 | m_gui.printf(clientId + " has connected"); 157 | m_gui.printf("Client challenge" + clientChallenge); 158 | 159 | // Generate Diffie-Hellman keypair, and send data to client to continue handshake. 160 | DHParameterSpec diffieHellmanParameters = diffieHellmanHelper.generateDiffieHellmanParameters(); 161 | m_gui.printf("Generating Diffie Hellman key pair for server"); 162 | KeyPair serverKeyPair = diffieHellmanHelper.createKeyPair(diffieHellmanParameters); 163 | 164 | byte[] serverPublicKeyEncoded = serverKeyPair.getPublic().getEncoded(); 165 | 166 | String serverChallenge = java.util.UUID.randomUUID().toString(); 167 | m_gui.printf("Sending server challenge: " + serverChallenge); 168 | byte[] encryptedServerIdentification = encryptHandshake(sharedSecretKey, SERVER_IDENTIFICATION.getBytes(), Cipher.ENCRYPT_MODE); 169 | writeToClient(outputStream, serverChallenge.getBytes()); 170 | m_gui.printf("Sending id: " + SERVER_IDENTIFICATION); 171 | writeToClient(outputStream, encryptedServerIdentification); 172 | m_gui.printf("Sending client challenge: " + clientChallenge); 173 | writeToClient(outputStream, encryptHandshake(sharedSecretKey, clientChallenge.getBytes(), Cipher.ENCRYPT_MODE)); 174 | m_gui.printf("Sending server session Key Pair: " + serverKeyPair); 175 | writeToClient(outputStream, encryptHandshake(sharedSecretKey, serverPublicKeyEncoded, Cipher.ENCRYPT_MODE)); 176 | 177 | byte[] identificationData2 = readFromClient(inputStream); 178 | byte[] serverChallengeData = readFromClient(inputStream); 179 | byte[] clientPublicKeyBytesEncoded = readFromClient(inputStream); 180 | 181 | String clientId2 = new String(encryptHandshake(sharedSecretKey, identificationData2, Cipher.DECRYPT_MODE)); 182 | if (!clientId2.equals(clientId)) { 183 | m_gui.printf("Incorrect client has connected, terminating program"); 184 | m_gui.connectionClosed(); 185 | } 186 | String serverChallengeReturned = new String(encryptHandshake(sharedSecretKey, serverChallengeData, Cipher.DECRYPT_MODE)); 187 | if (!serverChallengeReturned.equals(serverChallenge)) { 188 | m_gui.printf("Incorrect server challenge returned, terminating program"); 189 | m_gui.connectionClosed(); 190 | } 191 | byte[] unencryptedEncodedPublicKeyBytes = encryptHandshake(sharedSecretKey, clientPublicKeyBytesEncoded, Cipher.DECRYPT_MODE); 192 | PublicKey clientPublicKey = diffieHellmanHelper.getUnencodedPublicKey(unencryptedEncodedPublicKeyBytes); 193 | diffieHellmanHelper.getKeyAgreement().doPhase(clientPublicKey, true); 194 | 195 | byte[] serverSharedKey = diffieHellmanHelper.getKeyAgreement().generateSecret(); 196 | m_gui.printf("The shared key is: "); 197 | m_gui.printf(DatatypeConverter.printHexBinary(serverSharedKey)); 198 | 199 | // Handshake is done, now encrypt all user input in DES format using shared secret key. 200 | diffieHellmanHelper.getKeyAgreement().doPhase(clientPublicKey, true); 201 | SecretKey serverDESKey = diffieHellmanHelper.getKeyAgreement().generateSecret("DES"); 202 | communicationEncryptionCipher = getCommunicationCipher(Cipher.ENCRYPT_MODE, serverDESKey); 203 | communicationDecryptionCipher = getCommunicationCipher(Cipher.DECRYPT_MODE, serverDESKey); 204 | m_gui.connectionReady(); 205 | 206 | } 207 | catch(Exception e ) 208 | { 209 | m_gui.connectionClosed();; 210 | } 211 | } 212 | 213 | /*public static void main(String args[]) throws Exception { 214 | 215 | String userInput; 216 | while (true) { 217 | byte[] clientInput = readFromClient(inputStream); 218 | String clientInputDecrypted = new String(communicationDecryptionCipher.doFinal(clientInput)); 219 | System.out.println(clientId + " sent: " + clientInputDecrypted); 220 | System.out.println(">>"); 221 | userInput = userInputReader.readLine(); 222 | writeToClient(outputStream, communicationEncryptionCipher.doFinal(userInput.getBytes())); 223 | } 224 | 225 | }*/ 226 | 227 | private byte[] readFromClient(InputStream inputStream) throws IOException { 228 | byte[] lenMetaData = new byte[4]; 229 | inputStream.read(lenMetaData, 0, 4); 230 | ByteBuffer metaDataBuffer = ByteBuffer.wrap(lenMetaData); 231 | int lengthMetaDataInt = metaDataBuffer.getInt(); 232 | byte[] dataBuffer = new byte[lengthMetaDataInt]; 233 | inputStream.read(dataBuffer); 234 | return dataBuffer; 235 | } 236 | 237 | private void writeToClient(OutputStream outputStream, byte[] dataBuffer) throws IOException { 238 | ByteBuffer metaDataBuffer = ByteBuffer.allocate(4); 239 | metaDataBuffer.putInt(dataBuffer.length); 240 | outputStream.write(metaDataBuffer.array()); 241 | outputStream.write(dataBuffer); 242 | outputStream.flush(); 243 | } 244 | 245 | // Taken from http://docs.oracle.com/javase/1.4.2/docs/guide/security/jce/JCERefGuide.html#PBEEx 246 | private byte[] encryptHandshake(String sharedSecretKey, byte[] plainText, int encryption_mode) throws InvalidKeySpecException, NoSuchAlgorithmException, 247 | NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { 248 | PBEParameterSpec handshakeParamSpec = new PBEParameterSpec(SALT, ITERATION_COUNT); 249 | PBEKeySpec handshakeKeySpec = new PBEKeySpec(sharedSecretKey.toCharArray()); 250 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); 251 | SecretKey pbeKey = keyFactory.generateSecret(handshakeKeySpec); 252 | Cipher handshakeCipher = Cipher.getInstance("PBEWithMD5AndDES"); 253 | handshakeCipher.init(encryption_mode, pbeKey, handshakeParamSpec); 254 | return handshakeCipher.doFinal(plainText); 255 | } 256 | 257 | private Cipher getCommunicationCipher(int encryption_mode, SecretKey secretKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException { 258 | Cipher serverCipherForEncryption = Cipher.getInstance("DES/ECB/PKCS5Padding"); 259 | serverCipherForEncryption.init(encryption_mode, secretKey); 260 | return serverCipherForEncryption; 261 | } 262 | } 263 | --------------------------------------------------------------------------------