From fb6a79296585e92b0bd7e4d3e0b174cdf02755dd Mon Sep 17 00:00:00 2001 From: Romain <> Date: Sun, 21 Feb 2021 20:01:13 +0100 Subject: [PATCH] Snapshot 23797f5059 --- Licence note | 1 + README.md | 64 ++++ client/.classpath | 11 + client/.gitignore | 91 +++++ client/.project | 17 + client/resource/iconCommandPC.png | Bin 0 -> 3403 bytes client/resource/iconCommunication.png | Bin 0 -> 2156 bytes client/resource/iconConnection.png | Bin 0 -> 3618 bytes client/src/bundle/Bundle.properties | 38 +++ client/src/bundle/Bundle_fr.properties | 38 +++ client/src/generic/Status.java | 53 +++ client/src/gui/GUI.java | 173 ++++++++++ client/src/gui/panel/CommunicationPanel.java | 85 +++++ client/src/gui/panel/ConnectionPanel.java | 145 ++++++++ client/src/gui/panel/LogPanel.java | 97 ++++++ client/src/main/Primary.java | 76 +++++ client/src/network/Client.java | 159 +++++++++ client/src/network/CommunicationManager.java | 340 +++++++++++++++++++ img/CommandPC_commandIpconfig.png | Bin 0 -> 84646 bytes img/CommandPC_commandLs.png | Bin 0 -> 26356 bytes img/CommandPC_connectionResult.png | Bin 0 -> 18661 bytes img/CommandPC_systemTrayIcon.png | Bin 0 -> 3448 bytes img/CommandPC_systemTrayIcon2.png | Bin 0 -> 3456 bytes img/CommandPC_systemTrayLinux.png | Bin 0 -> 2443 bytes img/CommandPC_systemTrayWindows.png | Bin 0 -> 2234 bytes server/.classpath | 11 + server/.gitignore | 91 +++++ server/.project | 17 + server/resource/iconStart.png | Bin 0 -> 3448 bytes server/resource/iconStop.png | Bin 0 -> 3456 bytes server/src/bundle/Bundle.properties | 34 ++ server/src/bundle/Bundle_fr.properties | 34 ++ server/src/command/ExecuteCommand.java | 57 ++++ server/src/generic/Status.java | 53 +++ server/src/gui/GUI.java | 140 ++++++++ server/src/main/Primary.java | 48 +++ server/src/network/Client.java | 159 +++++++++ server/src/network/CommunicationManager.java | 333 ++++++++++++++++++ server/src/network/Server.java | 57 ++++ server/src/thread/ClientThread.java | 98 ++++++ server/src/thread/ServerThread.java | 114 +++++++ 41 files changed, 2634 insertions(+) create mode 100644 Licence note create mode 100644 README.md create mode 100644 client/.classpath create mode 100644 client/.gitignore create mode 100644 client/.project create mode 100644 client/resource/iconCommandPC.png create mode 100644 client/resource/iconCommunication.png create mode 100644 client/resource/iconConnection.png create mode 100644 client/src/bundle/Bundle.properties create mode 100644 client/src/bundle/Bundle_fr.properties create mode 100644 client/src/generic/Status.java create mode 100644 client/src/gui/GUI.java create mode 100644 client/src/gui/panel/CommunicationPanel.java create mode 100644 client/src/gui/panel/ConnectionPanel.java create mode 100644 client/src/gui/panel/LogPanel.java create mode 100644 client/src/main/Primary.java create mode 100644 client/src/network/Client.java create mode 100644 client/src/network/CommunicationManager.java create mode 100755 img/CommandPC_commandIpconfig.png create mode 100644 img/CommandPC_commandLs.png create mode 100644 img/CommandPC_connectionResult.png create mode 100644 img/CommandPC_systemTrayIcon.png create mode 100644 img/CommandPC_systemTrayIcon2.png create mode 100644 img/CommandPC_systemTrayLinux.png create mode 100644 img/CommandPC_systemTrayWindows.png create mode 100644 server/.classpath create mode 100644 server/.gitignore create mode 100644 server/.project create mode 100644 server/resource/iconStart.png create mode 100644 server/resource/iconStop.png create mode 100644 server/src/bundle/Bundle.properties create mode 100644 server/src/bundle/Bundle_fr.properties create mode 100644 server/src/command/ExecuteCommand.java create mode 100644 server/src/generic/Status.java create mode 100644 server/src/gui/GUI.java create mode 100644 server/src/main/Primary.java create mode 100644 server/src/network/Client.java create mode 100644 server/src/network/CommunicationManager.java create mode 100644 server/src/network/Server.java create mode 100644 server/src/thread/ClientThread.java create mode 100644 server/src/thread/ServerThread.java diff --git a/Licence note b/Licence note new file mode 100644 index 0000000..01464de --- /dev/null +++ b/Licence note @@ -0,0 +1 @@ +If you find software that doesn’t have a license, that means you have no permission from the creators of the software to use, modify, or share the software. Although a code host such as GitHub may allow you to view and fork the code, this does not imply that you are permitted to use, modify, or share the software for any purpose. diff --git a/README.md b/README.md new file mode 100644 index 0000000..da43e24 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# CommandPC + +CommandPC is a program for executing commands on a remote machine regardless of the operating system. + +## Description + +The too long didn't read version is that: it's like SSH, but less secure and just a fun experimentation with threads, internationalization, encryption and GUI in JAVA. + +Composed of two part, a client and a server, this application allow you to send encrypted command from one machine to another. Both the client and the server can operate with or without a gui. +English and French language are disponible within the application. + +## Instruction + +### Server + +Without the `nogui` argument, the server display its status with a system tray icon. By right-clicking the icon you can interact with it. + +| Server started | Server stopped | +|:--------------:|:--------------:| +|![server-systemTray-icon](img/CommandPC_systemTrayIcon.png)|![server-systemTray-icon](img/CommandPC_systemTrayIcon2.png)||| + +Example: + +- Windows sytem tray: ![server-systemTray-icon](img/CommandPC_systemTrayWindows.png) +- Linux XFCE system tray: ![server-systemTray-icon](img/CommandPC_systemTrayLinux.png) + +Right-clicking on the icon allow you to start and stop the server. The command line argument `port=X` chand the listening port. + +### Client + +The client use a graphical interface to guide the user and is available in both French and English (using the "Français"/"English" button at the bottom) +The interface is composed of two pane: "connection" and "command". + +The "connection" pane allows the connection to a remote server. + +![connection-result](img/CommandPC_connectionResult.png) + +After the connection established, the "command" pane allow to send commands to the server. + +| 'ls /' on a Linux machine | 'ipconfig' on a Windows machine and gui in French for a change | +|:-------------------------:|:-------------------------------:| +|![ls](img/CommandPC_commandLs.png)|![ipconfig](img/CommandPC_commandIpconfig.png)| + +## Security concerns + +**TLDR: Use at your own risk over a secure network.** + +### Command + +No effort is made to check if the command that you send is compatible with the user privilige, exist or is even safe to use. + +### Identity + +No identification of the user or the machine is made. In other words, if a server is running any number of client can connect and run command on it. + +### Encryption + +This software use AES 128 bits encryption, but like too many software (including payed one) it has flaws that make it unsuitable to use over unsecured networks. + +The main issue is the fact that during the first communication between the client and the server, the communication is encrypted via a master key. +This master key, is the same for all firsts exchanges. After that, a new communication key is generated between individual client and the server. +If somebody were to use a packet sniffer on the network, knowing the master key it's possible to get the communication key thus defeating the encryption entirely. + +Side note, AES 128 allow this program to run on any implementation of the Java platform. See the [Cipher documentation](https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html) for the complete list of "safe to use" cipher standard. diff --git a/client/.classpath b/client/.classpath new file mode 100644 index 0000000..fd51525 --- /dev/null +++ b/client/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..ed9b2c9 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,91 @@ +######################## +#JAVA +######################## +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +######################## +# ECLIPSE +######################## +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + diff --git a/client/.project b/client/.project new file mode 100644 index 0000000..1b0fe6e --- /dev/null +++ b/client/.project @@ -0,0 +1,17 @@ + + + client + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/client/resource/iconCommandPC.png b/client/resource/iconCommandPC.png new file mode 100644 index 0000000000000000000000000000000000000000..7fa2e8ef75ddc6d116069261945fff1a061698c9 GIT binary patch literal 3403 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 { + /** Indicate if the operation was a success. By default, false. */ + public boolean success; + /** Response message.*/ + public String message; + /** Response payload.*/ + public T payload; + /** Response error */ + public E error; + + public Status() { + super(); + this.success=false; + } + public Status(boolean success) { + super(); + this.success = success; + } + public Status(boolean success, String message) { + super(); + this.success = success; + this.message = message; + } + public Status(boolean success, String message, T payload) { + super(); + this.success = success; + this.message = message; + this.payload = payload; + } + public Status(boolean success, String message, T payload, E error) { + super(); + this.success = success; + this.message = message; + this.payload = payload; + this.error = error; + } + @Override + public String toString() { + String result="Status [success="+success+", message="+message; + if(payload!=null) { + result+=", payload="+payload.toString(); + } + if(error!=null) { + result+=", error="+error.toString(); + } + return result+"]"; + } +} \ No newline at end of file diff --git a/client/src/gui/GUI.java b/client/src/gui/GUI.java new file mode 100644 index 0000000..c44ae5b --- /dev/null +++ b/client/src/gui/GUI.java @@ -0,0 +1,173 @@ +package gui; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingConstants; +import javax.swing.WindowConstants; + +import generic.Status; +import gui.panel.CommunicationPanel; +import gui.panel.ConnectionPanel; +import network.CommunicationManager; + +public class GUI extends JFrame { + private static final long serialVersionUID = 1L; + private ConnectionPanel connectionPanel; + private CommunicationPanel communicationPanel; + private JPanel languagePanel; + private JButton languageButton; + private JTabbedPane tabbedPane; + + private CommunicationManager communicationManager; + + public GUI(CommunicationManager communicationManager) { + super(); + this.communicationManager=communicationManager; + connectionPanel=new ConnectionPanel(this); + connectionPanel.setAddress(communicationManager.getAddress()); + connectionPanel.setPort(String.valueOf(communicationManager.getPort())); + communicationPanel=new CommunicationPanel(this); + initialize(); + } + + /** + * Initialize the default state of the different GUI elements. + */ + private void initialize() { + this.setTitle("CommandPC - MARTIN Romain"); + this.setIconImage(getToolkit().getImage(getClass().getResource("/iconCommandPC.png"))); + this.setSize(600,300); + this.setResizable(true); + + this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + this.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + communicationManager.disconnect(); + dispose(); + }; + }); + + GridBagLayout gbl_contentPane=new GridBagLayout(); + getContentPane().setLayout(gbl_contentPane); + + tabbedPane=new JTabbedPane(SwingConstants.TOP); + tabbedPane.add("panelConnection",connectionPanel); + tabbedPane.add("panelCommunication",communicationPanel); + tabbedPane.setIconAt(0,new ImageIcon(getClass().getResource("/iconConnection.png"))); + tabbedPane.setIconAt(1,new ImageIcon(getClass().getResource("/iconCommunication.png"))); + tabbedPane.setEnabledAt(1,false); + GridBagConstraints gbc_tabbedPane=new GridBagConstraints(); + gbc_tabbedPane.gridx=0; + gbc_tabbedPane.gridy=0; + gbc_tabbedPane.weightx=1.0d; + gbc_tabbedPane.weighty=1.0d; + gbc_tabbedPane.fill=GridBagConstraints.BOTH; + getContentPane().add(tabbedPane,gbc_tabbedPane); + + GridBagLayout gbl_languagePanel=new GridBagLayout(); + languagePanel=new JPanel(gbl_languagePanel); + GridBagConstraints gbc_languagePanel=new GridBagConstraints(); + gbc_languagePanel.gridx=0; + gbc_languagePanel.gridy=1; + gbc_languagePanel.fill=GridBagConstraints.HORIZONTAL; + + languageButton=new JButton("languageButton"); + languageButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + if(Locale.getDefault().getLanguage().equals(Locale.FRENCH.toString())) { + Locale.setDefault(Locale.ENGLISH); + }else { + Locale.setDefault(Locale.FRENCH); + } + //ResourceBundle.clearCache(); + setText(); + } + }); + languagePanel.add(languageButton); + + getContentPane().add(languagePanel,gbc_languagePanel); + + setText(); + } + + /** + * Set the correct text for all graphical elements according to the default {@link Locale}. + * @see java.util.Locale#getDefault() + */ + private void setText(){ + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + languageButton.setText(resourceBundle.getString("languageAlt")); + tabbedPane.setTitleAt(0,resourceBundle.getString("connection")); + tabbedPane.setTitleAt(1,resourceBundle.getString("command")); + + communicationPanel.setText(); + connectionPanel.setText(); + } + + /** + * Request connection status change. + * @param isConnection true if this is a connection request, false to disconnect. + * @param address address of the remote server. + * @param port port of the remote server. + * @return true if operation successful. + */ + public boolean changeConnectionStatus(boolean isConnection,String address,String port) { + //Disconnection + if(isConnection==false) { + communicationManager.disconnect(); + tabbedPane.setEnabledAt(1,false); + tabbedPane.setSelectedIndex(0); + return true; + } + + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + + if(address.isBlank() || port.isBlank()) { + connectionPanel.addLog(resourceBundle.getString("errorSpecifyAddressAndPort"),true); + return false; + } + + Status result=communicationManager.connect(address,Integer.valueOf(port)); + if(result.success) { + connectionPanel.addLog(resourceBundle.getString("connectedTo")+" "+result.message.toString(),false); + tabbedPane.setEnabledAt(1,true); + tabbedPane.setSelectedIndex(1); + } else { + connectionPanel.addLog(result.error.toString(),true); + } + + return result.success; + } + + /** + * Send command to the server and receive his answer. + * @param text command to send. + */ + public void sendCommand(String text) { + Status resultSend=communicationManager.encryptAndSendString(text); + if(resultSend.success==false) { + communicationPanel.addLog(resultSend.error.toString(), true); + return; + } + Status resultReceive=communicationManager.receiveAndDecryptString(); + if(resultReceive.success) { + if(resultReceive.payload.trim().startsWith("java")) { + communicationPanel.addLog(resultReceive.payload.trim(), true); + } else { + communicationPanel.addLog(resultReceive.payload.trim(), false); + } + } else { + communicationPanel.addLog(resultReceive.error.toString(), true); + } + } +} diff --git a/client/src/gui/panel/CommunicationPanel.java b/client/src/gui/panel/CommunicationPanel.java new file mode 100644 index 0000000..dd32e56 --- /dev/null +++ b/client/src/gui/panel/CommunicationPanel.java @@ -0,0 +1,85 @@ +package gui.panel; + +import java.awt.GridBagConstraints; +import java.awt.event.KeyEvent; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JTextField; + +import gui.GUI; + +/** + *

Handle the communication with the server

+ *

Allow the user to input and send commands and display their results.

+ */ +public class CommunicationPanel extends LogPanel { + private static final long serialVersionUID = 1L; + private JLabel commandLabel; + private JTextField commandText; + private JButton executeButton; + + private GUI gui; + + public CommunicationPanel(GUI gui) { + super(); + this.gui=gui; + initialize(); + } + + @Override + protected void initialize() { + super.initialize(); + //GridBagLayout gbl_main=new GridBagLayout(); + //this.setLayout(gbl_main); + + commandLabel=new JLabel("labelCommand"); + GridBagConstraints gbc_commandLabel=new GridBagConstraints(); + gbc_commandLabel.gridx=0; + gbc_commandLabel.gridy=0; + gbc_commandLabel.anchor=GridBagConstraints.WEST; + this.add(commandLabel,gbc_commandLabel); + + commandText=new JTextField(); + commandText.addKeyListener(new java.awt.event.KeyAdapter() { + @Override + public void keyPressed(java.awt.event.KeyEvent e) { + if(e.getKeyCode() == KeyEvent.VK_ENTER){ + executeButton.doClick(); + } + } + }); + GridBagConstraints gbc_commandText=new GridBagConstraints(); + gbc_commandText.gridx=0; + gbc_commandText.gridy=1; + gbc_commandText.weightx=1.0d; + gbc_commandText.fill=GridBagConstraints.BOTH; + this.add(commandText,gbc_commandText); + + executeButton=new JButton("executeButton"); + executeButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + if(commandText.getText().isBlank()==false) { + gui.sendCommand(commandText.getText()); + } + } + }); + GridBagConstraints gbc_executeButton=new GridBagConstraints(); + gbc_executeButton.gridx=3; + gbc_executeButton.gridy=1; + this.add(executeButton,gbc_executeButton); + + setText(); + } + + @Override + public void setText() { + super.setText(); + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + commandLabel.setText(resourceBundle.getString("commandToExecute")); + executeButton.setText(resourceBundle.getString("execute")); + } +} \ No newline at end of file diff --git a/client/src/gui/panel/ConnectionPanel.java b/client/src/gui/panel/ConnectionPanel.java new file mode 100644 index 0000000..107d79b --- /dev/null +++ b/client/src/gui/panel/ConnectionPanel.java @@ -0,0 +1,145 @@ +package gui.panel; + +import java.awt.GridBagConstraints; +import java.awt.event.KeyEvent; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.swing.JLabel; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.SwingConstants; + +import gui.GUI; + +/** + * Handle connection state, allowing to set up and establish a connection as well as displaying it status. + */ +public class ConnectionPanel extends LogPanel { + private static final long serialVersionUID = 1L; + private JLabel addressLabel; + private JTextField addressText; + private JLabel portLabel; + private JTextField portText; + private JLabel addressPortSepartatorLabel; + private JToggleButton connectionToggleButton; + + private GUI gui; + + public void setAddress(String address) { + if(addressText!=null) addressText.setText(address); + } + public void setPort(String port) { + if(portText!=null) portText.setText(port); + } + + public ConnectionPanel(GUI gui) { + super(); + this.gui=gui; + initialize(); + } + + @Override + protected void initialize() { + super.initialize(); + /*GridBagLayout gbl_main=new GridBagLayout(); + this.setLayout(gbl_main);*/ + + addressLabel=new JLabel("addressLabel"); + GridBagConstraints gbc_addressLabel=new GridBagConstraints(); + gbc_addressLabel.gridx=0; + gbc_addressLabel.gridy=0; + this.add(addressLabel,gbc_addressLabel); + + addressText=new JTextField(); + addressText.setHorizontalAlignment(SwingConstants.CENTER); + addressText.addKeyListener(new java.awt.event.KeyAdapter() { + @Override + public void keyPressed(java.awt.event.KeyEvent e) { + if(e.getKeyCode() == KeyEvent.VK_ENTER){ + if(connectionToggleButton.isSelected()==false) { + connectionToggleButton.doClick(); + } + } + } + }); + GridBagConstraints gbc_addressText=new GridBagConstraints(); + gbc_addressText.gridx=0; + gbc_addressText.gridy=1; + gbc_addressText.weightx=0.5d; + gbc_addressText.fill=GridBagConstraints.BOTH; + this.add(addressText,gbc_addressText); + + addressPortSepartatorLabel=new JLabel(" : "); + addressPortSepartatorLabel.setHorizontalAlignment(SwingConstants.CENTER); + GridBagConstraints gbc_addressPortSepartatorLabel=new GridBagConstraints(); + gbc_addressPortSepartatorLabel.gridx=1; + gbc_addressPortSepartatorLabel.gridy=1; + this.add(addressPortSepartatorLabel,gbc_addressPortSepartatorLabel); + + portLabel=new JLabel("portLabel"); + GridBagConstraints gbc_portLabel=new GridBagConstraints(); + gbc_portLabel.gridx=2; + gbc_portLabel.gridy=0; + this.add(portLabel,gbc_portLabel); + + portText=new JTextField(); + portText.setHorizontalAlignment(SwingConstants.CENTER); + portText.addKeyListener(new java.awt.event.KeyAdapter() { + @Override + public void keyPressed(java.awt.event.KeyEvent e) { + if(e.getKeyCode() == KeyEvent.VK_ENTER){ + if(connectionToggleButton.isSelected()==false) { + connectionToggleButton.doClick(); + } + } + } + }); + GridBagConstraints gbc_portText=new GridBagConstraints(); + gbc_portText.gridx=2; + gbc_portText.gridy=1; + gbc_portText.weightx=0.5d; + gbc_portText.fill=GridBagConstraints.BOTH; + this.add(portText,gbc_portText); + + connectionToggleButton=new JToggleButton("connectionToggleButton"); + connectionToggleButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + boolean success=gui.changeConnectionStatus(connectionToggleButton.isSelected(),addressText.getText(),portText.getText()); + if(success==false) { + connectionToggleButton.setSelected(false); + } + setTextConnectionToggleButton(); + } + }); + GridBagConstraints gbc_connectionToggleButton=new GridBagConstraints(); + gbc_connectionToggleButton.gridx=3; + gbc_connectionToggleButton.gridy=1; + gbc_connectionToggleButton.fill=GridBagConstraints.HORIZONTAL; + this.add(connectionToggleButton,gbc_connectionToggleButton); + + setText(); + } + + /** + * Set the correct text for toggleButtonConnection regarding the selected language and it's status. + */ + private void setTextConnectionToggleButton() { + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + if(connectionToggleButton.isSelected()) { + connectionToggleButton.setText(resourceBundle.getString("connected")); + }else { + connectionToggleButton.setText(resourceBundle.getString("connection")); + } + } + + @Override + public void setText() { + super.setText(); + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + addressLabel.setText(resourceBundle.getString("address")); + portLabel.setText(resourceBundle.getString("port")); + setTextConnectionToggleButton(); + } +} diff --git a/client/src/gui/panel/LogPanel.java b/client/src/gui/panel/LogPanel.java new file mode 100644 index 0000000..851ca62 --- /dev/null +++ b/client/src/gui/panel/LogPanel.java @@ -0,0 +1,97 @@ +package gui.panel; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextPane; +import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyledDocument; + +public class LogPanel extends JPanel { + private static final long serialVersionUID = 1L; + private JTextPane logTextPane; + private StyledDocument logStyleDocument; + private SimpleAttributeSet normalAttributeSet; + private SimpleAttributeSet errorAttributeSet; + private JScrollPane logScrollPane; + private JButton clearLogButton; + + public LogPanel( ) { + super(); + normalAttributeSet=new SimpleAttributeSet(); + normalAttributeSet.addAttribute(StyleConstants.Foreground,Color.black); + errorAttributeSet=new SimpleAttributeSet(); + errorAttributeSet.addAttribute(StyleConstants.Foreground,Color.red); + // initialize(); + } + + /** + * Initialize the default state of the different GUI elements. + */ + protected void initialize() { + GridBagLayout gbl_main=new GridBagLayout(); + this.setLayout(gbl_main); + + logTextPane=new JTextPane(); + logStyleDocument=logTextPane.getStyledDocument(); + logScrollPane=new JScrollPane(logTextPane); + GridBagConstraints gbc_logScrollPane=new GridBagConstraints(); + gbc_logScrollPane.gridx=0; + gbc_logScrollPane.gridy=2; + gbc_logScrollPane.weightx=1.0d; + gbc_logScrollPane.weighty=1.0d; + gbc_logScrollPane.gridwidth=4; + gbc_logScrollPane.fill=GridBagConstraints.BOTH; + gbc_logScrollPane.insets=new Insets(5,0,0,0); + this.add(logScrollPane,gbc_logScrollPane); + + clearLogButton=new JButton("clearLogButton"); + clearLogButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + logTextPane.setText(""); + } + }); + GridBagConstraints gbc_clearLogButton=new GridBagConstraints(); + gbc_clearLogButton.gridx=3; + gbc_clearLogButton.gridy=3; + gbc_clearLogButton.fill=GridBagConstraints.HORIZONTAL; + this.add(clearLogButton,gbc_clearLogButton); + } + + /** + * Set the correct text for all graphical elements according to the default {@link Locale}. + * @see java.util.Locale#getDefault() + */ + public void setText() { + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + clearLogButton.setText(resourceBundle.getString("clear")); + } + + /** + * Append data to the log. + * @param data message to append. + * @param error indicate if data correspond to an error or not. + */ + public void addLog(String data,Boolean error) { + try { + if(logStyleDocument.getLength()>0) data="\n"+data; + if(error) { + logStyleDocument.insertString(logStyleDocument.getLength(), data, errorAttributeSet); + }else { + logStyleDocument.insertString(logStyleDocument.getLength(), data, normalAttributeSet); + } + }catch(BadLocationException e) { + logTextPane.setText(logTextPane.getText()+"\n"+data.trim().trim()); + } + } +} diff --git a/client/src/main/Primary.java b/client/src/main/Primary.java new file mode 100644 index 0000000..d83ef5c --- /dev/null +++ b/client/src/main/Primary.java @@ -0,0 +1,76 @@ +package main; + +import java.util.Locale; +import java.util.ResourceBundle; + +import generic.Status; +import gui.GUI; +import network.Client; +import network.CommunicationManager; + +public class Primary { + + public static void main(String[] args) { + String serverAddress="127.0.0.1"; + int serverPort=6200; + String command=""; + + //Handle user arguments + if(args.length>0){ + for(int i=0;i connectStatus=communicationManager.connect(); + if(connectStatus.success==false) { + connectStatus.error.toString(); + return; + } + System.out.println(resourceBundle.getString("connectedTo")+": "+serverAddress+":"+serverPort); + + Status sendStatus=communicationManager.encryptAndSendString(command); + if(sendStatus.success) { + Status receiveStatus=communicationManager.receiveAndDecryptString(); + if(receiveStatus.success) { + System.out.println(receiveStatus.payload.trim()); + } else { + receiveStatus.error.toString(); + } + } else { + sendStatus.error.toString(); + } + communicationManager.disconnect(); + System.out.println(resourceBundle.getString("connectionEnded")); + } + +} diff --git a/client/src/network/Client.java b/client/src/network/Client.java new file mode 100644 index 0000000..efd9652 --- /dev/null +++ b/client/src/network/Client.java @@ -0,0 +1,159 @@ +package network; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.PrintStream; +import java.net.Socket; + +import generic.Status; +/** + * TCP client allowing to send and receive Objects. + */ +public class Client { + private int serverPort; + private String serverAddress; + private Socket socket; + private BufferedReader is; + private PrintStream os; + private ObjectInputStream ois; + private ObjectOutputStream oos; + + public Client(){ + serverPort=8033; + serverAddress="127.0.0.1"; + } + public Client(int port){ + serverPort=port; + serverAddress="127.0.0.1"; + } + public Client(int port,String ip){ + serverPort=port; + serverAddress=ip; + } + + public int getServerPort() { + return serverPort; + } + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + public String getServerAddress() { + return serverAddress; + } + public void setServerAddress(String serverAddress) { + this.serverAddress = serverAddress; + } + public Socket getSocket() { + return socket; + } + public void setSocket(Socket socket) { + this.socket = socket; + if(socket!=null) { + try { + setIs(new BufferedReader(new InputStreamReader(socket.getInputStream()))); + setOs(new PrintStream(socket.getOutputStream())); + setOos(new ObjectOutputStream(socket.getOutputStream())); + setOis(new ObjectInputStream(socket.getInputStream())); + } catch (Exception e) { + } + } + } + public BufferedReader getIs() { + return is; + } + public void setIs(BufferedReader is) { + this.is = is; + } + public PrintStream getOs() { + return os; + } + public void setOs(PrintStream os) { + this.os = os; + } + public ObjectInputStream getOis() { + return ois; + } + public void setOis(ObjectInputStream ois) { + this.ois = ois; + } + public ObjectOutputStream getOos() { + return oos; + } + public void setOos(ObjectOutputStream oos) { + this.oos = oos; + } + + public Status connect(){ + Status result=new Status(true); + try { + socket=new Socket(serverAddress,serverPort); + is=new BufferedReader(new InputStreamReader(socket.getInputStream())); + os=new PrintStream(socket.getOutputStream()); + ois=new ObjectInputStream(socket.getInputStream()); + oos=new ObjectOutputStream(socket.getOutputStream()); + result.message=socket.getInetAddress().toString().substring(1)+":"+socket.getPort(); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status sendString(String message){ + Status result=new Status(true); + try { + os.println(message); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status receiveString(){ + Status result=new Status(true); + try { + result.payload=is.readLine(); + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status sendObject(Object object){ + Status result=new Status(true); + try { + oos.writeObject(object); + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status receiveObject(){ + Status result=new Status(true); + try { + result.payload=ois.readObject(); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status close(){ + Status result=new Status(true); + if(this.socket==null) return result; + try { + socket.close(); + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } +} \ No newline at end of file diff --git a/client/src/network/CommunicationManager.java b/client/src/network/CommunicationManager.java new file mode 100644 index 0000000..bd8cd7d --- /dev/null +++ b/client/src/network/CommunicationManager.java @@ -0,0 +1,340 @@ +package network; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import generic.Status; + +public class CommunicationManager { + private Client client; + /** Key used to initialize the connection. */ + private SecretKey masterKey; + /** Communication key between the client and the server. */ + private SecretKey communicationKey; + /** If true then the message will be send using the communicationKey. Otherwise, the masterKey will be used.*/ + private boolean useCommunicationKey; + + public CommunicationManager(Client client) { + this.client=client; + this.masterKey=new SecretKeySpec(new byte[]{-70,-45,-79,-32,-36,108,-117,-7,-97,56,46,-86,-35,-11,-35,-81}, "AES"); + this.useCommunicationKey=false; + } + + public String getAddress() { + if(client!=null) return client.getServerAddress(); + return ""; + } + public int getPort() { + if(client!=null) return client.getServerPort(); + return 0; + } + + /** + * Establish connection with the server set in the {@link #client}. + * If no error, then swap the key from master to communication. + * @return response {@link Status} object. + */ + public Status connect() { + Status status=new Status(true); + + //Stop immediately if already connected + if(client!=null && client.getSocket()!=null && client.getSocket().isConnected()) { + return status; + } + + //Connect to server + status=client.connect(); + if(status.success==false) { + return status; + } + + //Change from master key to a communication key + Status keyStatus=client.receiveString(); + if(keyStatus.success==false) { + status.success=keyStatus.success; + status.error=keyStatus.error; + return status; + } + Status decryptStatus=decryptString(keyStatus.payload, masterKey); + if(decryptStatus.success==false) { + status.success=decryptStatus.success; + status.error=decryptStatus.error; + return status; + } + String[] encodedKeyString=decryptStatus.payload.split(";"); + byte[] encodedKey=new byte[encodedKeyString.length]; + for(int i=0;i connect(String address,int port) { + if(client.getSocket()!=null && client.getSocket().isConnected()) { + disconnect(); + } + this.client=new Client(port, address); + return connect(); + } + + /** + * Encrypt and send data. + * @param data data to send. + * @return response {@link Status} object. + */ + public Status encryptAndSendString(String data) { + String encryptedMessage=""; + if(useCommunicationKey) { + encryptedMessage=encryptString(data, communicationKey).payload; + }else { + encryptedMessage=encryptString(data, masterKey).payload; + } + return client.sendString(encryptedMessage); + } + + /** + * Receive and decrypt data. + * @return response {@link Status} object. + */ + public Status receiveAndDecryptString() { + Status status=client.receiveString(); + if(status.success==false) { + status.success=status.success; + status.error=status.error; + return status; + } + + if(useCommunicationKey) { + status=decryptString(status.payload, communicationKey); + }else { + status=decryptString(status.payload, masterKey); + } + + if(status.success==false) { + status.success=status.success; + status.error=status.error; + } + return status; + } + + /** + * Close the communication socket. + * Inform the remote client of the deconnection. + * @return response {@link Status} object. + */ + public Status disconnect() { + encryptAndSendString("STOPstopSTOP"); + return client.close(); + } + + /** + * Generate and setup a communication key to replace the master key for future communication. + * Send the new key to the client. + */ + public void setupCommunicationKey() { + communicationKey=generateSecretKey(); + String encodedKey=""; + for(int i=0;i encrypt(byte[] data) { + if(useCommunicationKey) { + return encrypt(data,communicationKey); + }else{ + return encrypt(data,masterKey); + } + } + + /** + * Encrypt a message with the specified key. + * @param data message to encrypt. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status encrypt(byte[] data,SecretKey secretKey) { + Status result=new Status(true); + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + byte[] encrypt=cipher.doFinal(data); + /* + * Base64.getEncoder().encode() is here to + * prevent javax.crypto.IllegalBlockSizeException: + * Input length must be multiple of 16 when decrypting with padded cipher + */ + result.payload=Base64.getEncoder().encode(encrypt); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + /** + * Encrypt a message. + * @param data message to encrypt. + * @return response {@link Status} object. + */ + public Status encryptString(String data) { + if(useCommunicationKey) { + return encryptString(data,communicationKey); + }else{ + return encryptString(data,masterKey); + } + } + + /** + * Use {@link #encrypt(String, SecretKey)} to encrypt a message. + * @param data message to encrypt. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status encryptString(String data,SecretKey secretKey) { + Status result=new Status(true); + Status encryptResult=encrypt(data.getBytes(StandardCharsets.UTF_8),secretKey); + + result.message=encryptResult.message; + result.success=encryptResult.success; + result.error=encryptResult.error; + if(encryptResult.success) { + result.payload=new String(encryptResult.payload,StandardCharsets.UTF_8); + } + return result; + } + + /*private String padStringForCrypto (String data) { + //Prevent javax.crypto.IllegalBlockSizeException: + //Input length must be multiple of 16 when decrypting with padded cipher + if(data.length()%16!=0) { + System.out.println("data length="+data.length()); + double dataLengthNeeded=Math.ceil((double)data.length()/16d)*16; + data=String.format("%-"+(int)dataLengthNeeded+"s", data); + System.out.println("data length="+data.length()); + } + return data; + }*/ + + /** + * Decrypt a message. + * @param data encrypted message. + * @return response {@link Status} object. + */ + public Status decrypt(byte[] data){ + if(useCommunicationKey) { + return decrypt(data,communicationKey); + }else{ + return decrypt(data,masterKey); + } + } + + /** + * Decrypt a message with the specified key. + * @param data encrypted message. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status decrypt(byte[] data,SecretKey secretKey) { + Status result=new Status(true); + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + /* + * Base64.getDecoder().decode() is here to + * prevent javax.crypto.IllegalBlockSizeException: + * Input length must be multiple of 16 when decrypting with padded cipher + */ + result.payload=cipher.doFinal(Base64.getDecoder().decode(data)); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + /** + * Decrypt a {@link String}. + * @param data encrypted message. + * @return response {@link Status} object. + */ + public Status decryptString(String data) { + if(useCommunicationKey) { + return decryptString(data,communicationKey); + }else{ + return decryptString(data,masterKey); + } + } + + /** + * Use {@link #encrypt(String, SecretKey)} to decrypt a message. + * @param data encrypted message. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status decryptString(String data,SecretKey secretKey) { + Status result=new Status(true); + + byte[] dataByte; + try { + dataByte=data.getBytes(StandardCharsets.UTF_8); + } catch (NullPointerException e) { + result.error=e; + result.success=false; + return result; + } + + Status decryptResult=decrypt(dataByte,secretKey); + result.message=decryptResult.message; + result.success=decryptResult.success; + result.error=decryptResult.error; + if(decryptResult.success) { + result.payload=new String(decryptResult.payload,StandardCharsets.UTF_8); + } + + return result; + } +} diff --git a/img/CommandPC_commandIpconfig.png b/img/CommandPC_commandIpconfig.png new file mode 100755 index 0000000000000000000000000000000000000000..8201c434bc369954fbaa289493271d747bc3adf4 GIT binary patch literal 84646 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 NN=zPB41NFk{{p<%E1LiS literal 0 HcmV?d00001 diff --git a/img/CommandPC_commandLs.png b/img/CommandPC_commandLs.png new file mode 100644 index 0000000000000000000000000000000000000000..46598cdc668b5993c60bdda215022558df18be11 GIT binary patch literal 26356 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 literal 0 HcmV?d00001 diff --git a/img/CommandPC_connectionResult.png b/img/CommandPC_connectionResult.png new file mode 100644 index 0000000000000000000000000000000000000000..aecaa4e7b0356685dd5d7b43a6dc3fe2fbf04ebf GIT binary patch literal 18661 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 literal 0 HcmV?d00001 diff --git a/img/CommandPC_systemTrayIcon.png b/img/CommandPC_systemTrayIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..39dbcfd952bbd610ec7181013c4b58a0ebbeb451 GIT binary patch literal 3448 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 JPDHLkV1g@j;^_bY literal 0 HcmV?d00001 diff --git a/img/CommandPC_systemTrayWindows.png b/img/CommandPC_systemTrayWindows.png new file mode 100644 index 0000000000000000000000000000000000000000..111f6c90f1e32a10b9c732eac6ab1c5e45ef17dc GIT binary patch literal 2234 zcmV;r2u1gaP)pNY)M2xRCwC$ntM=GRT#i2_x*z1<>9)dA_>aEE{_FdVdbF^2n2$Q z+X8|ZiQyw6E6V}}6EiF!#21J$h2!)TEPIfk6;`Hcs68gf%I(2S&Cnk;Q`6YD9J^ij zvUl$;cd=>Co!^`}dpPILW%==a=W)G6G9?DXE(%o;ptLbdIW0&zZI&;f4hH-JgZ0| zvR& zkegq?vV!Yt)_m|~%g2{n&wl$XaOO%Y)PbQdcbpjBHgK--%?}%TPd=V%Ok^nEwSTT# zr*Lc~hl?7aWNt9(&yI*<+imMNZD!Ny|0D2Ux@GIOxe<{ekZ|W{)YF4d*s}wsiR>$Q zVPp@LPp`Ir_*Dyt2o}CE-;dWt_9ABCHM}2^> za4nY7PQl0OHU-U|18MiRnZZ=~5Gf1NSyr&NriLmXiiIc;_MdHheP|=Sg59Hp(QOpDJ*Mx6dEk%Hu#5Chp%P#|8psv1_lXoJQP+Gzba3flY=DB)X%(p3vLtbgFlrS?-_w}Oah zAp+U~5CY#j-`xMvlb~SV2amg?prZupG<8xZl>Py#a9tEZScEQc#w-Y3?kULOi@?15 zYS*{zYUc_>aS6tE`rqa7g*RP6h<^|TA-n-791@9`nxi3PLil7q5evj+6?fD72ZU*( z>=i`*{qg5t2v;qHCyNbHV=Mr@^_w;avk4cAofr zr>z{m?%&%dw*p7{HzyekE-BdD+&nruN;crC)ym;9iZ{31aw{mv8(#}g_z ze7`BYfGJ%6>+k}g1=`(yl#P!(y7A#!mxfRkglk}60L8QG3lV1i5emYx+L3>5D`>YI zY23Q)CN4(^>@u=lB8IeU*Fx>XmV&yNIHwBE4cFbEAYTlVM>!Q}pU6%jFmVNm0}_V& z(kv=SY|1n=ZgI3Jb4PYAWMP?HIhmU>#KS;+ep))(6od=;N9d)|MH8KoZNx+nE>C1( z^rdOEQMPY`mT+A(*F&!<#OcGMA~cU~-_+W(A6QkpS{tPe3k|th3es#!yR2}_%L*E^^6#pcP$W&w$P&nu^enHe;)!HfL5xQf%+4 + + + + + + + + + + diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..ed9b2c9 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,91 @@ +######################## +#JAVA +######################## +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +######################## +# ECLIPSE +######################## +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + diff --git a/server/.project b/server/.project new file mode 100644 index 0000000..33d3613 --- /dev/null +++ b/server/.project @@ -0,0 +1,17 @@ + + + server + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/server/resource/iconStart.png b/server/resource/iconStart.png new file mode 100644 index 0000000000000000000000000000000000000000..39dbcfd952bbd610ec7181013c4b58a0ebbeb451 GIT binary patch literal 3448 zcmV-;4TtiHP)hrGrd@?wKFQM%AiHm zR>Vug#RAnTS4n|_L@8G_NIWDF62e6SgiE*+NJ1cignOXjVvwSUR_t`9olgIR)$@Dz zdG=XnpPg{d323GL@XT6!?X}lh@3WrwU2Cti&kbGwx_HC?GH&=k0WpPNyZL7K(1Q=S zkwc$!!=4!OsbY9)48sc?3pNaX_#uZ)n+`R)oCvt@=Xbkhn~Mz9n~L0$jZdVp;Wt+1 zLv^nvqJ8v)jIpKg=DNp2(ALUrL*0OT`?~YL!$Q4 z{0N{j1Z-`8F(d#mKqJB%Fu<5oAHCTtsN*AQbkKIZS};6YA(`sfb9`<{z^)@{0-1*Il{C0AB$}l*X2A8|`Wvo^>m? zkFr!)z5DlJD%3S)=5=3rAFFnz+XW0>YKW@9R{}92RKb~9SuP+q@CnFE0V3ec-diRP5P+cH{M((P656OqH!P{AiX${3XXXbpdh&Y zP!I%B!6)ScasvfN;zbY`D|(F$J|QAO1eCAIGY0qsFpz^6-mpdiEF-xLBs)Fu_H0Y> z&nR?HssF6n)9htqh8d#e4(vEMEyULLVq5Yyw-p=eTPIl^2;dnJfCBPf1|a|!AO`$; z$Y8^e!H@Nb$A>*0oA0empzTK=84~6nd1P>MH##UQjl;lSKA6UU{%-BAapo3~;42`n zjSvLDSz5?_H8W>*|yCcjdAW*;?tB2&T00?0DWA;%2+tu=QPsO5geE`l1 zbY>7j*QvC8&5-b&opl^zaU1S2P}(77>m0a2!dx&;0sib;AnaU_^-e$^eTo4hfFM}5 z>akd0R3UjbG0Zf^`S*z@ycgJuQFovM-*~AYx(b-_#{>AwV4q?D1YAoOkl#n;fA+6S zvx1)vWYW<;Qvo8N`RKgZeL&s{@DD_yo1rKnisC0f%AYKMNz~>C0)Vc;$%{)e0%OOS zvXt>&06d;10T=GuPVnH&@H~JwL-yHmU=M!m{X|F*{)xN=?kkN#ZE$qO_4?+C8K9i4 zZ4{Kpt^g_d_nCkfr%thlyWU-D%;THC9r=u5#L!V;e)Oo(mLfsTJjPPa>n&*0i!19@iE+B<6#vSQYq@y{9$b zSAeeqUjabI1OHe&Zv{}-bB#{W@fO>-{rLT0ns&3Ve_hY5K;? zZQ|e??h~Ndj!Hi|^B4^vz&1f0^Fso*?d?MhfPnVyC2rrD^0XVIplGapf&!tm0Yet)%c}ux{@ZxBs2Rt~EKB*6xIDMUQn=82o`U zc$CtUfx1VkJkOCQMPYWGY~NBdcu|J&(KSD6e026P9!LQN9g9N%#y6iXGZipUq$v`7 zB2Wrs#TncaXfKMu@I_e!V65-=zWg!Xh)5aV69IXJ6IxR;4~Pu% zzVWn6D#LpsAv*ib`_rk62N>@Yke31=pk~htHYf`)9tju_3^tPl1}{Tpyq`~BCp=Ub zsk9|>F%HB1)c5zO0vg-qg^=+LE%P!6C@2U*!1l8XgY9LqWAYh9r2LZT?2`}}mGII; zNSdDqQkAXek!y^{z$_9{kskQQ1K;o{0XZLt+&`ed5wLRaAIxYOt^uZ15Ckn>1p=-h zF!NeXxRxr?YN!a6AYgPHL`c;Ck-ra!5E*$Z02kmGoMSLZKnZU(7u&DIfHFXgAW+sf z{n0ww(G+}|LY_TDp|DR|lBwFR+gWU>@=?@oo{)tV8^*d7^d9kG!q{hTnbXPwbiA z+O$KJ9Pe>pgH3zhIpRLm4<&E=(GT2+p+nt^lS|x7GfLd-mtVHjFnzM!yXCf9VwbDy z;!Dv72Ho$L*VMS}Tei5}I~&}thL$khTwm{Ms;V7zuG>##ae+6>D_r&BN+Y6n<%%$^ zs;;qn#E{DM%dbxb@bSaK(ghhPFI$*#O$;b`efIT90Ktg}AATe?b85y%Q{1BtUwvG6 z1h5KVAd#M^KVj_Ha0L)pApmvnyyJHFnJ0j#k540OzS;&dvUt+dSr7?)8D3QMus!>; zpZ?JBnIPah-};6F7|vR*!3&fLx{jvN`~Ed;fB$>mb^kR4eC3Nbx^I8;>ozD2_>S9e zwLB#7RTzHGriQ>)(@4`>(HAf-?K1MuZ9-RQ0v0d&TD zG@SvA^7DW?7_DpJYRlH|6VRuT{o`Bv6fb(b!9JQz%7(f++fTE0vrJLGcJ*re%oX2e z?dG2u?BZC{S?Y-7l8JfJ~3#}EdM0_aqOW^kGX)hACm>p%H*wKXgF!~Y6Jj1i(DW@OJB>mE-W)(FkCNVDFC8#rJ<}2YAn|h?Qnb(OBfrSBw1gxvK zS=9hxwsihH%QGO$C+je92F+lotLO1i@|0tc>X64@d6u_9)$!Y;9rCCG@-VV__iiH{ zk#oL`3lljm6mDcO>@{*tqgk+cDL zmU})FhZwW(u7Ex@PE8nUS-Pdx^-2J;f`HRqT?QJW0rFDCh4bf)RT%&9(j~)t7cLm0 zdFtvqn!nI}(emAIp9`(1}v^9v+Iv9U(P^FbCZ?RE^dRO zdnJJFru{0Enkfb$dHQ+OpuE5{N(p#Ui{Q^tbhecGiqXt#6;XYu3>8ra6%wlJFiay1f+b*uU4NdpFJvo8_OFv1RCwC$n`w|#)ftBQoun!z@kgvIRY|3isw_sMrphHz$$*HU z-~c+qB8i!3Y726bXWcDB=Qf!z~IT)QAO?N(3QNn59xD z{e0c;?bEk!58XY0k>tl)=iGD8_Pyu*zH{!Go*pk9+1KNL89n|_Kt$nJF1WzmaD8t# zvV4deI=J)`#jw;Ih7~y%Y#7+@28T@#KC{{7MZmQ`xzas7tjzFad6|3S*1-X`-g2vz z`B2@{iSQV?;LlBXeDI(E^tI!*a#wQARc_VR4fzp3)eS zK3udk1IHIP1u6JjV`GpP!fgP39ga6-;Jv!~1RC6-+WG(oYU%>KGkdn{oPJk;y;E!4 zTd~=OH>zd?cxB=Y_v-j+BZ5U;z3un;6EH1SWgULh*zS%tw7TO7kOvu5kCRPpLH?u0wg5hHK2Z?!LH%O)emtHcC`ru0nz+G;nKj3~J-ybjcXATg@aTX6 zg%Lny2-p>y6%cUL2xv`MCL>ET4SWI$Qh*5f$Fk+_ zg|RU=ZfvDn)3YSNgC!+y?az`RUkqsL_sJNqRZcXQiBf>Cf^ZxN0;C@YQo*rc0u%(_ zoSF=RsNih5fZRaAk$7Q&kwDxUL$6u>f)%Rpk#_vX&E z6#ooE@09v&)t^=`3yCccL$uw2J(Fhy*i{{~E${V7F~e&UtE~S!opdTz7pMB|Y7Xw^y25K!UG; zf(}9u0Fx(L+6^cHGQgRVe)!Cw^M=1|;tIKfquc;BDGn4(06_`@lD^n}T8$+24@Let zL4Ge|k9xjO5X>~VA>+j82SS|^eFBPh0VcsV_(b_|w{2JwPY=(=bEAe^z{-b!tkn)3 zmP9~T!A}He<-@x{w+N5|jxS$k1Z=wTMz^7F-z+@bZ(xA+H}%bn0MONmQ7Q-%psg_b zJkXG}9V!TR&X|$-7Dy7XW@`}y;Qz(CfQ$twNrwA*rBU+t;S-Q~9uNVGvQC5;4~ljH z#eic=+Rj+;6A4k|`3le%Xwvw`$P-}}0VxGMGO)C81wa7XAFGcFIIeCPd`l!A8-jN(ZZ_{K{G;a$LtpP7We4R$LAK){)F0r`Dc{{L)R zo)!FbA(M{&nF+mpU$;U9yMXQk_D)I?Kp;BRw*c>vKdw?tyztKqiUB^D zhui?1T+p6YK#G8{{BQSpN1^D-ZMaKYhffNDSjzoY`5#Spq0z`;yrKvPor#+eg|Kyj01PBO7 zNCiNV@b-*Fw)&v6I$Hq+U5Ky?5cp&~L?A;+QRf4beoOZCxQ@_iV%j5B;79gcd%mv# zUj@DbfQ$$JwRph_Ft$7bFn)cnzII^&xSR+>ml(P@;e<#mkh@4F7<{ygRqx6Lj?8Wf z6kuDRCx6ldlNXu__EpCXx)v|`KH$}=neOny7W?avovkO;nzVodO&ItfDbnBV)Fw6c2{;I20+03@q69Dx|XyXq@ZZ5bAke4a;4id;zTaP zeFCD0@C^qjARPSsm6!1%;H`=C+?!Q3#czWzBDhiOC#_H`!72*j=p#f1*qt zrQ|YD??{!W9eGj|X3vTKEyduv<_zP*dw$sX@akhckOGRj7KZ?g-(TBkDqx~WQzZCA zpcKf8GB_9LFAOtW2>HA3_rClw-iSyUpNoKkUEsy>Q*GrTfK*^27#$`cY*;~t$Gufg zrSHye&N3QU2%UI;%|c}0ONh2goAZWkxIZ2h>-DzQf0!Sl+2SvCiA}W z^h+wkbCD2U{r!{Dsf-60?-Njv0wCb2ad+CJEWmgqV1P|_P9_OVUWUqeKc9YX^3ZCe z(wE4^I1Kkw-`~Ru=&Y&_AmjIrug@T$s2~UdZ`LhI9xoFElg}U`<(EWfpM<1QOSxXjK-r-!j2%FB@-Q7r>^x3Hb8)=i4u< z_@x*PVK0n6J+F2pS6`D%6Loy>_c_W9i9G#Oj;pY{IexIjA5e0E3scm`_|}gH#uNPK zsQCr+OpT9Czj*Ff5+|ij=Y`$hF^L4kE~5s zecGi;p6|G@!KOd%+TlLYA4*>QgYUWF<>hYHlp1%}>>4-s?z=5D%$#EHF1+}{$nEN! z_@!v?zP;RiD^|D-4?W~I{b8efc;l8J{oT5CZbf^Cqs}?|Q(0W#o|abEv8>IASoy18 z25Ec83VTNkY5VPc=cWSq@xzja#TjU6T$1rj45<0}+;fuvf)f#bN-SomuALU-0q>~8 zuRhK>0@wvGkVsF|ubMC+*Z~A~2teJ-FT2Ej>Iop~!8LJ+V1(Con!^_J0 zS=%39`hCNvf`D&*<7*CJID5G!FHk1vIh=;y`_J_K-S2$c{nrrirO%(|zWMd9+N3n$ z%PzUd@{qu$UVD|D59k-yAZ1Mc2jGieIM1Ci z0vL?%Xa)lq<>vu)Fj~*T>6WcOCSXh>`-c~GD_-P$!8w{k%9>TH>^#lh%{E2(1NYzW zs_%@MZ?kvvpBbFu*wfkSh~$)0m*^g^t1%*JdJri?&Hoh1$PQ_;V-ZHw#z)Kfe9 zpq$nI+-E;ysqzrRT)4kr4%Az;V6g>T&KEpG(B_x7xq=CpKX0COj8Pa%r{po13G+uv z4mS);8Sls|9W`v2RLY~P&81;$fr~y!pick>!QpThpgZ`u-l~bSo^sPW0 ztuB32S1T_vm=AMR8&;h>^Wk{SoKbP!1RxoVqa!8{=#arNgh`_S2GyjQoK`{g$y3h$ zPk!~v6*gHuhA77{#u3T1p)GmJ8AmJ0xQwY)MGcBc%!_Xc>ddQM5FD|oM@pXs-3Sp_ zm~cSA>UFlNnjp+J%&)gR6S91w4ijh6OoqB@kB^e49D`JcJpM{sz6Mpt?~{JWqYB8w z$VWGAGSV@g#lmGUly}UHR56PbLd=B|yUHmEP{4U?%b(n~$F~M6{p|J~)|n>5fYhT7 zDbM72PoDN7;mOCh2jxtjJkq8g`lc?a@({#3^(P{EM|<9phb(BIDIUr6+^GH6R1 z>Ob?;Q$YYfB?0&;D~Yj^HF-K?Vw3@lVFHx@qNB|QrJTCtDc6bujPvU-Ve+(Pl9DZX z8!xf?7)c+1w!HJ9IK-TNcLj{8d1}E>%kqa-x-JPoRuJ&YOD`Gdhz`h06?=B?HdbML ze`lv*@18w|aGtt)4(Ip0zR&Wn|K*L~nLO=eJmWH!B#sgx3j%mY88Kj4Yok3MJa8Zb zTONJH%IO!kLD5|jz;TnHrIlh5lBb_X4ay6&QA)s*S_FTE!mFj!SBzF(yNK#bWvGZc zsKA12V&Qz?g8nnEf(rbrv8>Nkf*+OfJ%PZYz^7;b{h5I73iK>jAZUimA*8vf+44%m zpbqW~S^kw<1_A7~oV?Bk2uOvLpRO_4K65I77x!&mlNWyd$lAQ?7Sac0;c}k&km~Mu i^uZrUU-_^zAmBgE%V;-)ztq(L0000 executeCommand(String command){ + Status result=new Status(false); + + String responseLine; + try { + Process execution=runtime.exec(command); + bufferReader=new BufferedReader(new InputStreamReader(execution.getInputStream())); + while ((responseLine = bufferReader.readLine()) != null){ + if(!(responseLine.isEmpty())){ + if(result.payload==null || result.payload.isBlank()) { + result.payload=responseLine; + }else { + result.payload=result.payload+"\n"+responseLine; + } + } + } + result.success=true; + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } +} \ No newline at end of file diff --git a/server/src/generic/Status.java b/server/src/generic/Status.java new file mode 100644 index 0000000..abfdaf0 --- /dev/null +++ b/server/src/generic/Status.java @@ -0,0 +1,53 @@ +package generic; + +/** + * Generic response class. + */ +public class Status { + /** Indicate if the operation was a success. By default, false. */ + public boolean success; + /** Response message.*/ + public String message; + /** Response payload.*/ + public T payload; + /** Response error */ + public E error; + + public Status() { + super(); + this.success=false; + } + public Status(boolean success) { + super(); + this.success = success; + } + public Status(boolean success, String message) { + super(); + this.success = success; + this.message = message; + } + public Status(boolean success, String message, T payload) { + super(); + this.success = success; + this.message = message; + this.payload = payload; + } + public Status(boolean success, String message, T payload, E error) { + super(); + this.success = success; + this.message = message; + this.payload = payload; + this.error = error; + } + @Override + public String toString() { + String result="Status [success="+success+", message="+message; + if(payload!=null) { + result+=", payload="+payload.toString(); + } + if(error!=null) { + result+=", error="+error.toString(); + } + return result+"]"; + } +} \ No newline at end of file diff --git a/server/src/gui/GUI.java b/server/src/gui/GUI.java new file mode 100644 index 0000000..a781202 --- /dev/null +++ b/server/src/gui/GUI.java @@ -0,0 +1,140 @@ +package gui; + +import java.awt.AWTException; +import java.awt.Image; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.SystemTray; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.event.ActionEvent; +import java.net.InetAddress; +import java.util.Locale; +import java.util.ResourceBundle; + +import thread.ServerThread; + +public class GUI { + private TrayIcon trayIcon; + private Image iconServerStart; + private Image iconServerStop; + private PopupMenu trayPopupMenu; + private MenuItem trayPopupItemQuit; + private MenuItem trayPopupItemToggleServerState; + private boolean serverStarted; + + private ServerThread serverThread; + + public GUI(ServerThread serverThread) { + serverStarted=false; + this.serverThread=serverThread; + initialize(); + } + + public void show() { + try { + SystemTray.getSystemTray().add(trayIcon); + } catch (AWTException e) { + e.printStackTrace(); + } + } + + public void hide() { + SystemTray.getSystemTray().remove(trayIcon); + } + + private void initialize() { + if(SystemTray.isSupported()==false) { + return; + } + + //Setup TrayIcon image + iconServerStart=Toolkit.getDefaultToolkit().getImage(getClass().getResource("/iconStart.png")); + iconServerStop=Toolkit.getDefaultToolkit().getImage(getClass().getResource("/iconStop.png")); + + //Setup popup menu + trayPopupItemQuit=new MenuItem("trayPopupItemQuit"); + trayPopupItemQuit.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + serverThread.stopServerSocket(); + serverThread.stopClientsSocket(); + hide(); + } + }); + trayPopupItemToggleServerState=new MenuItem("trayPopupItemToggleServerState"); + trayPopupItemToggleServerState.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if(serverStarted) { + serverThread.stopServerSocket(); + serverThread.stopClientsSocket(); + } else { + if(serverThread.isAlive()==false) { + serverThread=new ServerThread(serverThread.getServer(), serverThread.getGui()); + serverThread.start(); + } + } + } + }); + trayPopupMenu=new PopupMenu(); + trayPopupMenu.add(trayPopupItemToggleServerState); + trayPopupMenu.addSeparator(); + trayPopupMenu.add(trayPopupItemQuit); + + trayIcon=new TrayIcon(iconServerStop,"CommandPC",trayPopupMenu); + trayIcon.setImageAutoSize(true); + + setText(); + } + + /** + * Set the correct text for all graphical elements according to the default {@link Locale}. + * @see java.util.Locale#getDefault() + */ + private void setText() { + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + trayPopupItemQuit.setLabel(resourceBundle.getString("quit")); + setTextServerState(); + } + + /** + * Set the correct text related to server state. + */ + private void setTextServerState() { + ResourceBundle resourceBundle=ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()); + if(serverStarted) { + trayPopupItemToggleServerState.setLabel(resourceBundle.getString("serverEndAction")); + } else { + trayPopupItemToggleServerState.setLabel(resourceBundle.getString("serverStartAction")); + } + } + + /** + * Indicate to the user that the server has started. + */ + public void displayServerStart() { + serverStarted=true; + trayIcon.setImage(iconServerStart); + setTextServerState(); + } + + /** + * Indicate to the user that the server has stop. + */ + public void displayServerStop() { + serverStarted=false; + trayIcon.setImage(iconServerStop); + setTextServerState(); + } + + /** + * Indicate to the user that a new client is connected. + * @param inetAddress client address + * @param port client port + * @param localPort local port + */ + public void displayStartConnection(InetAddress inetAddress, int port, int localPort) { + // TODO displayStartConnection() + } +} diff --git a/server/src/main/Primary.java b/server/src/main/Primary.java new file mode 100644 index 0000000..110e73d --- /dev/null +++ b/server/src/main/Primary.java @@ -0,0 +1,48 @@ +package main; + +import java.util.Locale; +import java.util.ResourceBundle; + +import gui.GUI; +import network.Server; +import thread.ServerThread; + +public class Primary { + + public static void main(String[] args) { + int port=6200; + boolean showGUI=true; + + //Handle user arguments + if(args.length>0){ + for(int i=0;i connect(){ + Status result=new Status(true); + try { + socket=new Socket(serverAddress,serverPort); + is=new BufferedReader(new InputStreamReader(socket.getInputStream())); + os=new PrintStream(socket.getOutputStream()); + ois=new ObjectInputStream(socket.getInputStream()); + oos=new ObjectOutputStream(socket.getOutputStream()); + result.message=socket.getInetAddress().toString().substring(1)+":"+socket.getPort(); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status sendString(String message){ + Status result=new Status(true); + try { + os.println(message); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status receiveString(){ + Status result=new Status(true); + try { + result.payload=is.readLine(); + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status sendObject(Object object){ + Status result=new Status(true); + try { + oos.writeObject(object); + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status receiveObject(){ + Status result=new Status(true); + try { + result.payload=ois.readObject(); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + public Status close(){ + Status result=new Status(true); + if(this.socket==null) return result; + try { + socket.close(); + } catch (IOException e) { + result.success=false; + result.error=e; + } + return result; + } +} \ No newline at end of file diff --git a/server/src/network/CommunicationManager.java b/server/src/network/CommunicationManager.java new file mode 100644 index 0000000..4ac3003 --- /dev/null +++ b/server/src/network/CommunicationManager.java @@ -0,0 +1,333 @@ +package network; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import generic.Status; + +public class CommunicationManager { + private Client client; + /** Key used to initialize the connection. */ + private SecretKey masterKey; + /** Communication key between the client and the server. */ + private SecretKey communicationKey; + /** If true then the message will be send using the communicationKey. Otherwise, the masterKey will be used.*/ + private boolean useCommunicationKey; + + public CommunicationManager(Client client) { + this.client=client; + this.masterKey=new SecretKeySpec(new byte[]{-70,-45,-79,-32,-36,108,-117,-7,-97,56,46,-86,-35,-11,-35,-81}, "AES"); + this.useCommunicationKey=false; + } + + public String getAddress() { + if(client!=null) return client.getServerAddress(); + return ""; + } + public int getPort() { + if(client!=null) return client.getServerPort(); + return 0; + } + + /** + * Establish connection with the server set in the {@link #client}. + * If no error, then swap the key from master to communication. + * @return response {@link Status} object. + */ + public Status connect() { + Status status=new Status(true); + + //Stop immediately if already connected + if(client!=null && client.getSocket()!=null && client.getSocket().isConnected()) { + return status; + } + + //Connect to server + status=client.connect(); + if(status.success==false) { + return status; + } + + //Change from master key to a communication key + Status keyStatus=client.receiveString(); + if(keyStatus.success==false) { + status.success=keyStatus.success; + status.error=keyStatus.error; + return status; + } + Status decryptStatus=decryptString(keyStatus.payload, masterKey); + if(decryptStatus.success==false) { + status.success=decryptStatus.success; + status.error=decryptStatus.error; + return status; + } + String[] encodedKeyString=decryptStatus.payload.split(";"); + byte[] encodedKey=new byte[encodedKeyString.length]; + for(int i=0;i connect(String address,int port) { + if(client.getSocket()!=null && client.getSocket().isConnected()) { + disconnect(); + } + this.client=new Client(port, address); + return connect(); + } + + /** + * Encrypt and send data. + * @param data data to send. + * @return response {@link Status} object. + */ + public Status encryptAndSendString(String data) { + String encryptedMessage=""; + if(useCommunicationKey) { + encryptedMessage=encryptString(data, communicationKey).payload; + }else { + encryptedMessage=encryptString(data, masterKey).payload; + } + return client.sendString(encryptedMessage); + } + + /** + * Receive and decrypt data. + * @return response {@link Status} object. + */ + public Status receiveAndDecryptString() { + Status status=client.receiveString(); + if(status.success==false) { + status.success=status.success; + status.error=status.error; + return status; + } + + if(useCommunicationKey) { + status=decryptString(status.payload, communicationKey); + }else { + status=decryptString(status.payload, masterKey); + } + + if(status.success==false) { + status.success=status.success; + status.error=status.error; + } + return status; + } + + /** + * Close the communication socket. + * Inform the remote client of the deconnection. + * @return response {@link Status} object. + */ + public Status disconnect() { + encryptAndSendString("STOPstopSTOP"); + return client.close(); + } + + /** + * Generate and setup a communication key to replace the master key for future communication. + * Send the new key to the client. + */ + public void setupCommunicationKey() { + communicationKey=generateSecretKey(); + String encodedKey=""; + for(int i=0;i encrypt(byte[] data) { + if(useCommunicationKey) { + return encrypt(data,communicationKey); + }else{ + return encrypt(data,masterKey); + } + } + + /** + * Encrypt a message with the specified key. + * @param data message to encrypt. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status encrypt(byte[] data,SecretKey secretKey) { + Status result=new Status(true); + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + byte[] encrypt=cipher.doFinal(data); + /* + * Base64.getEncoder().encode() is here to + * prevent javax.crypto.IllegalBlockSizeException: + * Input length must be multiple of 16 when decrypting with padded cipher + */ + result.payload=Base64.getEncoder().encode(encrypt); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + /** + * Encrypt a message. + * @param data message to encrypt. + * @return response {@link Status} object. + */ + public Status encryptString(String data) { + if(useCommunicationKey) { + return encryptString(data,communicationKey); + }else{ + return encryptString(data,masterKey); + } + } + + /** + * Use {@link #encrypt(String, SecretKey)} to encrypt a message. + * @param data message to encrypt. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status encryptString(String data,SecretKey secretKey) { + Status result=new Status(true); + Status encryptResult=encrypt(data.getBytes(StandardCharsets.UTF_8),secretKey); + + result.message=encryptResult.message; + result.success=encryptResult.success; + result.error=encryptResult.error; + if(encryptResult.success) { + result.payload=new String(encryptResult.payload,StandardCharsets.UTF_8); + } + return result; + } + + /*private String padStringForCrypto (String data) { + //Prevent javax.crypto.IllegalBlockSizeException: + //Input length must be multiple of 16 when decrypting with padded cipher + if(data.length()%16!=0) { + System.out.println("data length="+data.length()); + double dataLengthNeeded=Math.ceil((double)data.length()/16d)*16; + data=String.format("%-"+(int)dataLengthNeeded+"s", data); + System.out.println("data length="+data.length()); + } + return data; + }*/ + + /** + * Decrypt a message. + * @param data encrypted message. + * @return response {@link Status} object. + */ + public Status decrypt(byte[] data){ + if(useCommunicationKey) { + return decrypt(data,communicationKey); + }else{ + return decrypt(data,masterKey); + } + } + + /** + * Decrypt a message with the specified key. + * @param data encrypted message. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status decrypt(byte[] data,SecretKey secretKey) { + Status result=new Status(true); + try { + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, secretKey); + /* + * Base64.getDecoder().decode() is here to + * prevent javax.crypto.IllegalBlockSizeException: + * Input length must be multiple of 16 when decrypting with padded cipher + */ + result.payload=cipher.doFinal(Base64.getDecoder().decode(data)); + } catch (Exception e) { + result.success=false; + result.error=e; + } + return result; + } + + /** + * Decrypt a {@link String}. + * @param data encrypted message. + * @return response {@link Status} object. + */ + public Status decryptString(String data) { + if(useCommunicationKey) { + return decryptString(data,communicationKey); + }else{ + return decryptString(data,masterKey); + } + } + + /** + * Use {@link #encrypt(String, SecretKey)} to decrypt a message. + * @param data encrypted message. + * @param secretKey secret key to use. + * @return response {@link Status} object. + */ + private Status decryptString(String data,SecretKey secretKey) { + Status result=new Status(true); + + byte[] dataByte=data.getBytes(StandardCharsets.UTF_8); + + Status decryptResult=decrypt(dataByte,secretKey); + result.message=decryptResult.message; + result.success=decryptResult.success; + result.error=decryptResult.error; + if(decryptResult.success) { + result.payload=new String(decryptResult.payload,StandardCharsets.UTF_8); + } + + return result; + } +} diff --git a/server/src/network/Server.java b/server/src/network/Server.java new file mode 100644 index 0000000..299be30 --- /dev/null +++ b/server/src/network/Server.java @@ -0,0 +1,57 @@ +package network; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; + +import generic.Status; +/** + * TCP server allowing to send and receive Objects. + */ +public class Server { + private int serverPort; + private ServerSocket serverSocket; + private List clientSocket; + + public Server(int serverPort) { + super(); + this.serverPort = serverPort; + clientSocket=new ArrayList(); + } + + public Status start() { + Status result=new Status(true); + try { + serverSocket=new ServerSocket(serverPort); + result.payload=serverSocket.getLocalPort(); + } catch (IOException e) { + result.success=false; + result.error=e; + }; + return result; + } + + public Status accept() { + Status result=new Status(true); + try { + Socket client=serverSocket.accept(); + clientSocket.add(client); + result.payload=client; + } catch (IOException e) { + result.success=false; + result.error=e; + }; + return result; + } + + public void stop() { + try { + serverSocket.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/server/src/thread/ClientThread.java b/server/src/thread/ClientThread.java new file mode 100644 index 0000000..a5421b2 --- /dev/null +++ b/server/src/thread/ClientThread.java @@ -0,0 +1,98 @@ +package thread; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.Socket; +import java.util.Locale; +import java.util.ResourceBundle; + +import command.ExecuteCommand; +import generic.Status; +import network.Client; +import network.CommunicationManager; + +/** + * Thread dedicated to handling a communication with a client. + */ +public class ClientThread extends Thread{ + private CommunicationManager communicationManager; + private Client client; + private ExecuteCommand executeCommand; + private boolean run; + private boolean osIsWindows; + + public boolean isRun() { + return run; + } + public void setRun(boolean run) { + this.run = run; + } + + public ClientThread(Socket socket) { + super(); + this.client=new Client(); + this.client.setSocket(socket); + this.communicationManager=new CommunicationManager(client); + this.executeCommand=new ExecuteCommand(); + this.run=true; + this.osIsWindows=System.getProperty("os.name").toLowerCase().startsWith("windows"); + } + + private void closeConnection() { + communicationManager.encryptAndSendString("STOPstopSTOP"); + client.close(); + run=false; + } + + @Override + public void run() { + communicationManager.setupCommunicationKey(); + + Status status; + while(run) { + status=client.receiveString(); + if(status.success && status.payload==null && status.error==null) { + //Client is probably disconnected and client.receiveString() is just "purging" buffer + closeConnection(); + } + + if(run && status.success) { + status=communicationManager.decryptString(status.payload); + } + + if(run) { + if(status.success) { + if(status.payload.compareTo("STOPstopSTOP")==0) { + closeConnection(); + }else { + System.out.println( + ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("message") + +": "+status.payload + ); + + Status resultCommand=executeCommand.executeCommand(status.payload); + if(resultCommand.success) { + if(osIsWindows) { + try { + resultCommand.payload=new String(resultCommand.payload.getBytes(),"Cp850"); + } catch (UnsupportedEncodingException e) { + //If encoding fail do nothing as the text will still be mostly legible + } + } + communicationManager.encryptAndSendString(resultCommand.payload); + }else{ + communicationManager.encryptAndSendString(resultCommand.error.toString()); + } + } + }else { + System.out.println( + ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("messageFail") + +": "+status.error.toString() + ); + status.error.printStackTrace(); + } + } + } + System.out.println(ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("clientConnectionStop")); + } +} \ No newline at end of file diff --git a/server/src/thread/ServerThread.java b/server/src/thread/ServerThread.java new file mode 100644 index 0000000..668dd3e --- /dev/null +++ b/server/src/thread/ServerThread.java @@ -0,0 +1,114 @@ +package thread; + +import java.io.IOException; +import java.net.Socket; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +import generic.Status; +import gui.GUI; +import network.Server; + +/** + * Thread dedicated to create {@link ClientThread} upon client connection. + */ +public class ServerThread extends Thread{ + private Server server; + private Boolean accept; + private GUI gui; + private List clients; + + public Server getServer() { + return server; + } + public void setServer(Server server) { + this.server = server; + } + public GUI getGui() { + return gui; + } + public void setGui(GUI gui) { + this.gui = gui; + } + public Boolean getAccept() { + return accept; + } + public void setAccept(Boolean accept) { + this.accept = accept; + } + + public ServerThread(Server server){ + super(); + this.clients=new ArrayList(); + this.server=server; + this.accept=true; + this.gui=null; + } + public ServerThread(Server server,GUI gui){ + super(); + this.server=server; + this.accept=true; + this.gui=gui; + } + + @Override + public void run(){ + accept=true; + Status serverStartStatus=server.start(); + if(serverStartStatus.success) { + System.out.println(ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("serverStart")); + if(gui!=null) gui.displayServerStart(); + while(accept) { + Status connectionAttempt=server.accept(); + if(connectionAttempt.success) { + Socket client=connectionAttempt.payload; + System.out.println( + ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("clientConnection") + +" "+client.getInetAddress()+":"+client.getPort() + +" (" + +ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("localPort") + +": "+client.getLocalPort() + +")" + ); + if(gui!=null) gui.displayStartConnection(client.getInetAddress(),client.getPort(),client.getLocalPort()); + ClientThread ct=new ClientThread(client); + clients.add(ct); + ct.start(); + }else { + if(accept) { + System.out.println(ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("clientConnectionFail")); + } + } + } + }else { + System.out.println(ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("serverStartFail")); + System.out.println(serverStartStatus.error.toString()); + return; + } + if(gui!=null) gui.displayServerStop(); + System.out.println(ResourceBundle.getBundle("bundle/Bundle",Locale.getDefault()).getString("serverEnd")); + } + + /** + * Stop the current server from accepting new connection. + * Old connection will remain active. + * @see #stopClientsSocket() + */ + public void stopServerSocket() { + server.stop(); + accept=false; + } + + /** + * Stop all the client connection. + * New connection are still possible. + * @see #stopServerSocket() + */ + public void stopClientsSocket() { + for(int i=0;i