diff --git a/Client.jar b/Client.jar
deleted file mode 100644
index cff8ef1..0000000
Binary files a/Client.jar and /dev/null differ
diff --git a/Server.jar b/Server.jar
deleted file mode 100644
index 91ffc7f..0000000
Binary files a/Server.jar and /dev/null differ
diff --git a/src/client/ClientModel.java b/src/client/ClientModel.java
index 3d304b2..ddea348 100644
--- a/src/client/ClientModel.java
+++ b/src/client/ClientModel.java
@@ -2,10 +2,7 @@
 
 import message.Message;
 
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
+import javax.crypto.*;
 import javax.crypto.spec.SecretKeySpec;
 import javax.swing.*;
 import java.io.*;
@@ -69,21 +66,43 @@ public void connect(String username, String serverAddress) throws IOException, C
         //this is so that the server can add them to their online user list
         objectOutputStream.writeObject(username);
 
-        //write the public key to the server so that it can use it to encrypt the secret session key
-        //we will then use the private key to decrypt the session key
-        //the public key is not written in encrypted form, but this is not an issue since it can only be used
-        //for encryption. Only the person with the private key(i.e. client) can decrypt messages encrypted with public key
-        objectOutputStream.writeObject(this.publicKey);
-
-        //Read the encrypted session key which is sent as a message from the server to the client
-        //this is the first message that the server will send from the client
-        Message encryptedSessionKey = (Message) objectInputStream.readObject();
-        //Decrypt the message to obtain a string representation of the unencrypted session key
-        String sessionKey = encryptedSessionKey.decrypt(this.privateKey);
-        //Turn the String representation of the session key into a real AES session key that can
-        //be used for encryption/decryption. Store it in a private field(very important)
-        this.sessionKey = new SecretKeySpec(Base64.getDecoder().decode(sessionKey),"AES");
+        //read the announcement and user list that the server sends to the client
+        //the announcement is sent first
+        Message announcement = (Message) objectInputStream.readObject();
+        messages.add(announcement.toString());
+        clientView.updateMessages();
+        //read the user list, this is sent after the announcement
+        this.onlineUsers = (ArrayList<String>) objectInputStream.readObject();
+        clientView.updateUserList();
+
+        //check if the user list contains only 1 client(yourself) or more than 1 client(yourself + other people)
+        if (this.onlineUsers.size()==1){
+            generateSessionKey();
+        } else {
+            objectOutputStream.writeObject(this.publicKey);
+            //Read the encrypted session key which is sent as a message from the server to the client
+            //this is the first message that the server will send from the client
+            Message encryptedSessionKey = (Message) objectInputStream.readObject();
+            System.out.println(encryptedSessionKey.toString());
+            //Decrypt the message to obtain a string representation of the unencrypted session key
+            String sessionKey = encryptedSessionKey.decrypt(this.privateKey);
+            //Turn the String representation of the session key into a real AES session key that can
+            //be used for encryption/decryption. Store it in a private field(very important)
+            this.sessionKey = new SecretKeySpec(Base64.getDecoder().decode(sessionKey),"AES");
+        }
+    }
 
+    private void generateSessionKey() {
+        //Create a key generator that generates a symmetric AES key
+        KeyGenerator keyGenerator = null;
+        try {
+            keyGenerator = KeyGenerator.getInstance("AES");
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        //Initialize the key size to 256 bits
+        keyGenerator.init(256);
+        this.sessionKey = keyGenerator.generateKey();
     }
 
     public void sendMessage(String message) throws IOException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException, NoSuchAlgorithmException, InvalidKeyException {
@@ -95,10 +114,20 @@ public void readMessage() throws IOException, ClassNotFoundException, NoSuchPadd
         Object obj = objectInputStream.readObject();
         if (obj instanceof Message){
             Message message = (Message) obj;
-            //Decrypt all messages that the server sends to us(client) and add them to the client log in plain text
+            //we need to check if message is announcement or not. Announcements should not be decrypted
+            if (message.isAnnouncement()){
+                messages.add(message.toString());
+            } else {
+                //Decrypt all messages that the server sends to us(client) and add them to the client log in plain text
+                messages.add(message.decrypt(this.sessionKey));
+            }
             //so that the client can read the messages
-            messages.add(message.decrypt(this.sessionKey));
             clientView.updateMessages();
+        } else if (obj instanceof PublicKey){
+          //in case we are the key warden, we will receive the public key as a message
+          PublicKey publicKey = (PublicKey) obj;
+          //we will use the public key to encrypt the session key and send it back to the server
+          objectOutputStream.writeObject(new Message(Base64.getEncoder().encodeToString(sessionKey.getEncoded()),publicKey));
         } else {
             ArrayList<String> onlineUsers = (ArrayList<String>) obj;
             this.onlineUsers = onlineUsers;
diff --git a/src/client/ClientView.form b/src/client/ClientView.form
index 1713e93..9883d0d 100644
--- a/src/client/ClientView.form
+++ b/src/client/ClientView.form
@@ -88,7 +88,7 @@
               <grid row="8" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
             </constraints>
             <properties>
-              <icon value="simple_chat_logo.jpg"/>
+              <icon value="end_to_end_encrypted_chat_logo.jpg"/>
               <text value=""/>
             </properties>
           </component>
diff --git a/src/encrypted_chat.jpg b/src/encrypted_chat.jpg
new file mode 100644
index 0000000..e20bf97
Binary files /dev/null and b/src/encrypted_chat.jpg differ
diff --git a/src/end_to_end_encrypted_chat_logo.jpg b/src/end_to_end_encrypted_chat_logo.jpg
new file mode 100644
index 0000000..d8b664e
Binary files /dev/null and b/src/end_to_end_encrypted_chat_logo.jpg differ
diff --git a/src/message/Message.java b/src/message/Message.java
index d7cac7e..a085688 100644
--- a/src/message/Message.java
+++ b/src/message/Message.java
@@ -16,12 +16,19 @@
 public class Message implements Serializable {
 
     private final String message;
+    //this indicates if the message is an encrypted session key. In this case, the client handler
+    //should not broadcast it, but forward it to the key receiver.
+    private boolean isSessionKey;
+    private boolean isAnnouncement;
+
 
     /**
      * Prepends the current time to the string and stores it.
      * @param message given String
      */
     public Message(String message) {
+        //an unencrypted message will be an announcement
+        this.isAnnouncement = true;
         String time;
         DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm:ss");
         LocalDateTime now = LocalDateTime.now();
@@ -49,6 +56,8 @@ public Message(String message, SecretKey sessionKey) throws IllegalBlockSizeExce
      * @param publicKey An assymetric Public Key generated by the client and shared with the server
      */
     public Message(String message, PublicKey publicKey) throws NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, InvalidKeyException {
+        //the only thing that is encrypted with public key is the session key so set this to be true
+        this.isSessionKey = true;
         this.message = encrypt(message,publicKey);
     }
 
@@ -131,9 +140,6 @@ public String decrypt(PrivateKey privateKey) throws NoSuchPaddingException, NoSu
         return new String(decryptedBytes);
     }
 
-
-
-
     /**
      * Returns the encapsulated String message
      * @return String object message
@@ -146,4 +152,11 @@ public String getMessagePart(){
         return message.substring(message.indexOf(">")+1);
     }
 
+    public boolean isSessionKey() {
+        return this.isSessionKey;
+    }
+
+    public boolean isAnnouncement() {
+        return this.isAnnouncement;
+    }
 }
\ No newline at end of file
diff --git a/src/server/ClientHandler.java b/src/server/ClientHandler.java
index 68036f4..8daf2fc 100644
--- a/src/server/ClientHandler.java
+++ b/src/server/ClientHandler.java
@@ -26,12 +26,14 @@ public class ClientHandler implements Runnable{
     private static ArrayList<ClientHandler> clientHandlers = new ArrayList<>();
     private ServerModel serverModel;
     private SecretKey sessionKey;
+    //this will be the client Handler that the key warden will send the key back to
+    private ClientHandler keyReceiver;
 
     public ClientHandler(Socket clientConnection, ServerModel serverModel) throws IOException, ClassNotFoundException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, InvalidKeyException {
         this.clientSocket = clientConnection;
         this.serverModel = serverModel;
         //the session key will be sent to the client
-        this.sessionKey = serverModel.getSessionKey();
+        //this.sessionKey = serverModel.getSessionKey();
 
         clientHandlers.add(this);
 
@@ -40,20 +42,44 @@ public ClientHandler(Socket clientConnection, ServerModel serverModel) throws IO
 
         //read the username that the client sends to the server, this is the first item that client sends
         this.username = (String) objectInputStream.readObject();
-        //Read the public key that the client sends to the server. This is the second item that the client sends
+
+/*        //Read the public key that the client sends to the server. This is the second item that the client sends
         PublicKey publicKey = (PublicKey) objectInputStream.readObject();
         //write the secret session key to the client and encrypt it with the public key that you read from the client.
-        objectOutputStream.writeObject(new Message(Base64.getEncoder().encodeToString(sessionKey.getEncoded()),publicKey));
+        objectOutputStream.writeObject(new Message(Base64.getEncoder().encodeToString(sessionKey.getEncoded()),publicKey));*/
 
         serverModel.addOnlineUser(username);
-        serverModel.addMessage(new Message("SERVER: "+username+" has connected to the server"));
-
-        //encrypt all messages(Message class) that the server sends with session key
-        //otherwise the client will try to decrypt a message that can not be decrypted and it will raise an error
-        broadCastMessage(new Message("SERVER: "+username+" has connected to the server",this.sessionKey));
+        Message announcement = new Message("SERVER: "+username+" has connected to the server");
+        serverModel.addMessage(announcement);
+        broadCastMessage(announcement);
         broadCastUsers(serverModel.getOnlineUsers());
 
+        if (serverModel.getOnlineUsers().size() > 1){
+            //read the public key that the client sends to the server
+            PublicKey publicKey = (PublicKey) objectInputStream.readObject();
+            //we need to send the public key to the key warden so they can encrypt the
+            //session key and send it back to the client(key receiver).
+            ClientHandler keyWarden = getKeyWarden();
+            if (keyWarden != null) {
+                //send the public key to the client that is the key warden. Here we use their public key.
+                keyWarden.objectOutputStream.writeObject(publicKey);
+                //we also need to make the keywarden client handler know who to send the key back to
+                keyWarden.setKeyReceiver(this);
+            }
+        }
+    }
+
+    private void setKeyReceiver(ClientHandler clientHandler) {
+        this.keyReceiver = clientHandler;
+    }
+
 
+    private ClientHandler getKeyWarden() {
+        if (!clientHandlers.isEmpty()){
+            return clientHandlers.get(0);
+        } else {
+            return null;
+        }
     }
 
     private void broadCastUsers(ArrayList<String> onlineUsers) throws IOException {
@@ -85,10 +111,19 @@ public void sendMessage(Message message) throws IOException {
     public void readMessage() throws IOException, ClassNotFoundException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
         while (true){
             Message message = (Message) objectInputStream.readObject();
-            broadCastMessage(message);
-            //we need to decrypt the message that server receives from client before we add it to server log
-            //otherwise we can not read it
-            serverModel.addEncryptedMessage(message);
+            //we only want to broadcast the message if it is a regular message. If it is a session key, we forward
+            //it to the key receiver
+            if (message.isSessionKey()){
+                this.keyReceiver.objectOutputStream.writeObject(message);
+            } else {
+                broadCastMessage(message);
+                serverModel.addMessage(message);
+                //we need to decrypt the message that server receives from client before we add it to server log
+                //otherwise we can not read it
+                //this method decrypts messages before adding them to the server log
+                //since the server does not know of the encryption key, this should not be used
+                //serverModel.addEncryptedMessage(message);
+            }
         }
     }
 
@@ -131,20 +166,10 @@ private void closeConnection() {
             //remove the username and update the server online user list
             serverModel.removeUser(username);
             serverModel.addMessage(new Message("SERVER: " + username + " has disconnected from the server"));
-            broadCastMessage(new Message("SERVER: " + username + " has disconnected from the server",this.sessionKey));
+            broadCastMessage(new Message("SERVER: " + username + " has disconnected from the server"));
             broadCastUsers(serverModel.getOnlineUsers());
         } catch (IOException e){
             e.printStackTrace();
-        } catch (IllegalBlockSizeException e) {
-            e.printStackTrace();
-        } catch (NoSuchPaddingException e) {
-            e.printStackTrace();
-        } catch (BadPaddingException e) {
-            e.printStackTrace();
-        } catch (NoSuchAlgorithmException e) {
-            e.printStackTrace();
-        } catch (InvalidKeyException e) {
-            e.printStackTrace();
         }
     }
 
diff --git a/src/server/ServerModel.java b/src/server/ServerModel.java
index 6866e55..70bee63 100644
--- a/src/server/ServerModel.java
+++ b/src/server/ServerModel.java
@@ -81,7 +81,13 @@ public ArrayList<String> getOnlineUsers(){
     }
 
     public void addMessage(Message message) {
-        messages.add(message.toString());
+        if (message.isAnnouncement()) {
+            messages.add(message.toString());
+        } else {
+            //this will make each encrypted message on a new line since they do not have new line character once they
+            //are encrypted unless they are decrypted
+            messages.add(message.toString()+"\n");
+        }
         serverView.updateMessages();
     }
 
