LOC-13 - Encrypt system message payloads.
LOC-13 - Encrypt system message payloads.

This is done for two main reasons - firstly to minimise the amount of obvious plaintext in memory (though it is still base64 encoded, so limited effect there).

Secondly, and more importantly, it allows us to adjust the client so that it will never honour a plaintext JSON message payload.

--- a/client/LocalChatClient.py
+++ b/client/LocalChatClient.py
@@ -40,6 +40,7 @@
         self.room = False
         self.roompass = False
         self.sesskey = False
+        self.syskey = False
         self.gpg = gnupg.GPG()
     
     
@@ -81,9 +82,10 @@
         # Otherwise, process the messages
         for i in resp["messages"]:
             self.last = i[0]
+            upstruser = i[3]
             
             try:
-                msgbody = json.loads(self.decrypt(i[1]))
+                msgbody = json.loads(self.decrypt(i[1],upstruser))
             except:
                 # Means an invalid message was received - LOC-8
                 to_print.append(['error','Received message which could not be decrypted'])
@@ -93,8 +95,7 @@
             # but not currently including that info in my curl tests. Also means test that part of the next block
             
             color = "green"
-            upstruser = i[3]
-            
+
             if upstruser == self.user:
                 # One of our own, change the color
                 color = "blue"
@@ -233,6 +234,7 @@
         self.last = resp['last']
         self.roompass = p[0] # The room password is the first section of the password
         self.sesskey = resp['session']
+        self.syskey = resp['syskey']
         return True
 
 
@@ -401,17 +403,19 @@
 
 
 
-    def decrypt(self,msg):
+    def decrypt(self,msg,sender):
         ''' Placeholder
         '''
-        
-        try:
-            # Check if it's json as it may be a system message
-            json.loads(msg)
-            return msg
+                
+        try:       
+            key = self.roompass
+            if sender == "SYSTEM":
+                key = self.syskey
+                
+            return str(self.gpg.decrypt(msg.decode("base64"),passphrase=key))
         
         except:
-            return str(self.gpg.decrypt(msg.decode("base64"),passphrase=self.roompass))
+            return False
         
     
 

--- a/server/LocalChat.py
+++ b/server/LocalChat.py
@@ -22,6 +22,7 @@
 import bcrypt
 import random
 import string
+import gnupg
 
 app = Flask(__name__)
 
@@ -56,6 +57,9 @@
     def __init__(self):
         self.conn = False
         self.cursor = False
+        # Generate a key for encryption of SYSTEM messages (LOC-13)
+        self.syskey = self.genpassw(16)
+        self.gpg = gnupg.GPG()
 
 
 
@@ -234,7 +238,7 @@
                 'name' : reqjson['payload']['roomName']
             }
         
-    
+
 
     def closeRoom(self,reqjson):
         ''' Close a room.
@@ -425,7 +429,7 @@
         self.cursor.execute("INSERT INTO sessions (username,sesskey) values (?,?)", (reqjson['payload']['user'],sesskey))
         self.conn.commit()
                 
-        return {"status":"ok","last":last,"session":sesskey}
+        return {"status":"ok","last":last,"session":sesskey,"syskey":self.syskey}
         
         
     def processleaveRoom(self,reqjson):
@@ -651,7 +655,10 @@
             "text":msg,
             "verb":verb
         }
-        self.cursor.execute("INSERT INTO messages (ts,room,msg,user) VALUES (?,?,?,'SYSTEM')",(time.time(),room,json.dumps(m)))
+        
+        m = self.encryptSysMsg(json.dumps(m))
+        
+        self.cursor.execute("INSERT INTO messages (ts,room,msg,user) VALUES (?,?,?,'SYSTEM')",(time.time(),room,m))
         msgid = self.cursor.lastrowid
         self.conn.commit()
         return msgid
@@ -665,7 +672,6 @@
         '''
         self.cursor.execute("INSERT INTO failuremsgs (username,room,expires,msg) values (?,?,?,?)",(user,room,time.time() + 300,msg))
         self.conn.commit()
-        
         
         
 
@@ -698,8 +704,33 @@
         
 
 
+    def encryptSysMsg(self,msg):
+        ''' Encrypt a message from system - LOC-13
+        
+            This isn't so much for protection of the data in memory (as the key is also in memory) as it
+            is to protect against a couple of things you could otherwise do in the client. See LOC-13 for
+            more info.
+        
+        '''
+        
+        crypted = self.gpg.encrypt(msg,None,passphrase=self.syskey,symmetric="AES256",armor=False)
+        return crypted.data.encode('base64')
+        
+
+
     def genSessionKey(self,N=128):
         return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits).encode('utf-8') for _ in range(N))
+
+
+
+    def genpassw(self,N=16):
+        ''' Generate a random string of chars to act as an encryption password
+        '''
+        
+        return ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits).encode('utf-8') for _ in range(N))
+
+    
+
 
 
     def test(self):