]> git.datanom.net - securemail.git/commitdiff
First working beta
authorMichael Rasmussen <mir@datanom.net>
Fri, 10 Aug 2018 22:26:21 +0000 (00:26 +0200)
committerMichael Rasmussen <mir@datanom.net>
Fri, 10 Aug 2018 22:26:21 +0000 (00:26 +0200)
cryptonize.py
db.py
user.py

index 9cc463120804f83d6a7295b4565107d609748d3b..d375f2300b07b09d3299b9a783e6fc8e802fb133 100644 (file)
@@ -19,7 +19,7 @@
 
 from nacl.secret import SecretBox
 from nacl.public import PrivateKey, Box
-from nacl.utils import random
+from nacl.utils import random, EncryptedMessage
 from nacl.encoding import HexEncoder
 import nacl.hash
 
@@ -32,7 +32,7 @@ class Cryptonize:
         skey = self.sanitize_key(key)
         box = SecretBox(skey)
         cipher = box.encrypt(plain)
-        box = None
+        box = skey = None
         
         return cipher
         
@@ -40,7 +40,7 @@ class Cryptonize:
         skey = self.sanitize_key(key)
         box = SecretBox(skey)
         plain = box.decrypt(cipher)
-        box = None
+        box = skey = None
         
         return plain
         
@@ -66,14 +66,10 @@ class Cryptonize:
             key = key.encode('utf-8')
         size = len(key)
         if size < SecretBox.KEY_SIZE:
-            """We must pad"""
-            pad = None
-            for i in range(SecretBox.KEY_SIZE - size):
-                if pad is None:
-                    pad = b'\0'
-                else:
-                    pad += b'\0'
-            newkey = key + pad
+            """ We must pad """
+            newkey = key + bytes(SecretBox.KEY_SIZE - size)
+        elif size > SecretBox.KEY_SIZE:
+            newkey = key[:SecretBox.KEY_SIZE]
         else:
             newkey = key
         
@@ -94,4 +90,9 @@ class Cryptonize:
 
         return digest.decode()
 
+    def create_EncryptedMessage(self, payload):
+        nonce = payload[:SecretBox.NONCE_SIZE]
+        ciphertext = payload[SecretBox.NONCE_SIZE:]
         
+        return EncryptedMessage._from_parts(
+            nonce, ciphertext,  nonce + ciphertext)
diff --git a/db.py b/db.py
index e904fb190c0096bf440c8fa639c21adeb14d9e8c..1d545b1a31c950b16c831a478384875b2a7b402e 100644 (file)
--- a/db.py
+++ b/db.py
 # You should have received a copy of the GNU General Public License
 # along with SecureMail.  If not, see <https://www.gnu.org/licenses/>.
 
+# mysql
+# create table account (
+# id int auto_increment,
+# token char(128) unique not null,
+# cipher blob not null,
+# primary key (id));
+#
+# postgresql
+# create table account (
+# id serial,
+# token char(128) unique not null,
+# cipher bytea not null,
+# primary key (id));
+
+import base64
 from config import DBTYPE, DBHOST, DBPORT, DBUID, DBPWD, DBNAME
+from cryptonize import Cryptonize
 
 class Singleton:
     def __init__(self, klass):
@@ -36,11 +52,14 @@ class DB:
     def get_connection(self):
         if self.conn is None:
             if DBTYPE == 'mysql':
-                import mysql.connector
-                self.conn = mysql.connector.connect(host=DBHOST, port=DBPORT, user=DBUID, password=DBPWD, database=DBNAME)
+                #import MySQLdb
+                import MySQLdb
+                self.conn = MySQLdb.connect(host=DBHOST, port=DBPORT, user=DBUID, password=DBPWD, database=DBNAME)
             elif DBTYPE == 'postgresql':
                 import psycopg2
                 self.conn = psycopg2.connect(host=DBHOST, port=DBPORT, user=DBUID, password=DBPWD, dbname=DBNAME)
+            else:
+                raise ValueError('{0}: Unsupported database'.format(DBTYPE))
         return self.conn
         
     def __del__(self):
@@ -52,20 +71,33 @@ class DBInterface:
     def load_user(key):
         conn = DB().get_connection()
         cursor = conn.cursor()
-        cursor.execute("select a.cipher from account a where id = '{0}'".format(key))
+        cursor.execute("select a.cipher from account a where token = '{0}'".format(key))
         row = cursor.fetchone()
         if row is None:
             obj = None
         else:
-            obj = row[0].tobytes()
+            c = Cryptonize()
+            msg = base64.b64decode(row[0])
+            obj = c.create_EncryptedMessage(msg)
         cursor.close()
         
         return obj
         
     @staticmethod
     def store_user(key, cipher):
+        if DBTYPE == 'mysql':
+            from MySQLdb import Error as DBError
+        elif DBTYPE == 'postgresql':
+            from psycopg2 import Error as DBError
         conn = DB().get_connection()
         cursor = conn.cursor()
-        cursor.execute("insert into account(id, cipher) values(%s, %s)", (key, cipher))
-        conn.commit()
-        cursor.close()
+        raw = base64.b64encode(cipher)
+        try:
+            cursor.execute("insert into account(token, cipher) values(%s, %s)", (key, raw))
+            conn.commit()
+        except DBError as e:
+            print (e)
+            conn.rollback()
+            raise e
+        finally:
+            cursor.close()
diff --git a/user.py b/user.py
index 3b4c051fb006078587a9adf111c4e63e15f20771..64673c7c7ce58f5484d271cb7f85c9f5623221c3 100644 (file)
--- a/user.py
+++ b/user.py
 # You should have received a copy of the GNU General Public License
 # along with SecureMail.  If not, see <https://www.gnu.org/licenses/>.
 
-try:
-    import cPickle as pickle
-except:
-    import pickle
+import pickle
 from db import DBInterface as DBI
 from cryptonize import Cryptonize
+from nacl.public import PublicKey
 
-class NoSuchUserException(Exception):
+class NoSuchUser(Exception):
     pass
 
 class User:
@@ -34,24 +32,48 @@ class User:
     def __init__(self, key=None):
         if key is not None:
             self.load(key)
+        else:
+            self.pubkeys = {}
 
     def store(self, key):
         crypto = Cryptonize()
-        cipher = crypto.symmetric_encrypt(key, pickle.dumps(self.__dict__))
+        cipher = crypto.symmetric_encrypt(key, pickle.dumps(self))
         DBI.store_user(crypto.generate_hash(key), cipher)
 
     def load(self, key):
         crypto = Cryptonize()
         cipher = DBI.load_user(crypto.generate_hash(key))
         if cipher is None:
-            raise NoSuchUserException('{0}: User not found'.format(key))
+            raise NoSuchUser('{0}: User not found'.format(key))
         plain = crypto.symmetric_decrypt(key, cipher)
         try:
             obj = pickle.loads(plain)
-            self.__dict__.update(obj)
+            self.__dict__.update(obj.__dict__)
         except pickle.UnpicklingError as e:
-            raise NoSuchUserException(e)
-            
+            raise e
+    
+    def add_pubkey(self, email, key):
+        if email not in self.pubkeys:
+            self.pubkeys[email] = key.encode()
+        else:
+            raise KeyError('{0}: Exists'.format(email))
+    
+    def update_pubkey(self, email, key):
+        self.pubkeys[email] = key.encode()
+
+    def delete_pubkey(self, email):
+        if email in self.pubkeys:
+            del self.pubkeys[email]
+
+    def get_pubkey(self, email):
+        if email in self.pubkeys:
+            key = self.pubkeys[email]
+            key = PublicKey(key)
+        else:
+            key = None
+        
+        return key
+
     @property
     def name(self):
         return self._name
@@ -62,25 +84,63 @@ class User:
 
     @property
     def email(self):
-        return self.email
+        return self._email
 
     @email.setter
     def email(self, email):
         self._email = email
 
+    @property
+    def pubkeys(self):
+        return self._pubkeys
+
+    @pubkeys.setter
+    def pubkeys(self, pubkeys):
+        if type(pubkeys) is not type({}):
+            raise ValueError('Not dictionary')
+        self._pubkeys = pubkeys
 
 if __name__ == '__main__':
     try:
         u = User('test')
         for attr, value in u.__dict__.items():
             print ('{0}: {1}'.format(attr, value))
+        print ('{0} - {1} - {2}'.format(u.name, u.email, u.pubkeys))
+        key = ''
+        for i in range(40):
+            key += '{0}'.format(i)
+        u = User()
+        u.name = 'testname1'
+        u.email = 'testname1@securemail.icu'
+        u.pubkeys = {'test': 'some test', 'test1': 'some test 1'}
+        try:
+            u.store(key)
+        except:
+            u = User(key)
+            for attr, value in u.__dict__.items():
+                print ('{0}: {1}'.format(attr, value))
+            print ('{0} - {1} - {2}'.format(u.name, u.email, u.pubkeys))
+        from nacl.public import Box
         c = Cryptonize()
-        key = 'æselØre' #c.get_random_key()
-        cipher = c.symmetric_encrypt(key, pickle.dumps(u))
-        obj = pickle.loads(c.symmetric_decrypt(key, cipher))
-        for attr, value in obj.__dict__.items():
-            print ('{0}: {1}'.format(attr, value))
-    except NoSuchUserException:
+        keypair1 = c.get_key_pair()
+        keypair2 = c.get_key_pair()
+        try:
+            u.add_pubkey('test', keypair2[1])
+        except KeyError:
+            u.update_pubkey('test', keypair2[1])
+        bob_box = Box(keypair1[0], u.get_pubkey('test'))
+        message = "Kill all humans æøåÅØÆ"
+        encrypted = bob_box.encrypt(message.encode())
+        alice_box = Box(keypair2[0], keypair1[1])
+        plaintext = alice_box.decrypt(encrypted)
+        print (plaintext.decode())
+#        c = Cryptonize()
+#        key = 'æselØre' #c.get_random_key()
+#        cipher = c.symmetric_encrypt(key, pickle.dumps(u))
+#        obj = pickle.loads(c.symmetric_decrypt(key, cipher))
+#        for attr, value in obj.__dict__.items():
+#            print ('{0}: {1}'.format(attr, value))
+    except NoSuchUser:
         u = User()
         u.name = 'testname'
         u.email = 'testname@securemail.icu'
This page took 0.043916 seconds and 5 git commands to generate.