]> git.datanom.net - securemail.git/commitdiff
Basic framework finished
authorMichael Rasmussen <mir@datanom.net>
Sun, 5 Aug 2018 04:38:18 +0000 (06:38 +0200)
committerMichael Rasmussen <mir@datanom.net>
Sun, 5 Aug 2018 04:38:18 +0000 (06:38 +0200)
cryptonize.py [new file with mode: 0644]
db.py [new file with mode: 0644]
user.py [new file with mode: 0644]

diff --git a/cryptonize.py b/cryptonize.py
new file mode 100644 (file)
index 0000000..9cc4631
--- /dev/null
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018  Michael Rasmussen <mir@datanom.net>
+# This file is part of SecureMail.
+
+# SecureMail is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# SecureMail is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with SecureMail.  If not, see <https://www.gnu.org/licenses/>.
+
+from nacl.secret import SecretBox
+from nacl.public import PrivateKey, Box
+from nacl.utils import random
+from nacl.encoding import HexEncoder
+import nacl.hash
+
+class Cryptonize:
+    """
+    Encrypt and decrypt objects
+    """
+    
+    def symmetric_encrypt(self, key, plain):
+        skey = self.sanitize_key(key)
+        box = SecretBox(skey)
+        cipher = box.encrypt(plain)
+        box = None
+        
+        return cipher
+        
+    def symmetric_decrypt(self, key, cipher):
+        skey = self.sanitize_key(key)
+        box = SecretBox(skey)
+        plain = box.decrypt(cipher)
+        box = None
+        
+        return plain
+        
+    def asymmetric_encrypt(self, privkey, pubkey, plain):
+        box = Box(privkey, pubkey)
+        cipher = box.encrypt(plain)
+        box = None
+        
+        return cipher
+        
+    def asymmetric_decrypt(self, privkey, pubkey, cipher):
+        box = Box(privkey, pubkey)
+        plain = box.decrypt(cipher)
+        box = None
+        
+        return plain
+        
+    def get_random_key(self):
+        return random(SecretBox.KEY_SIZE)
+        
+    def sanitize_key(self, key):
+        if not isinstance(key, bytes):
+            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
+        else:
+            newkey = key
+        
+                
+        return newkey
+        
+    def get_key_pair(self):
+        privkey = PrivateKey.generate()
+        pubkey = privkey.public_key
+        
+        return (privkey, pubkey)
+
+    def generate_hash(self, key):
+        if not isinstance(key, bytes):
+            key = key.encode('utf-8')
+        HASHER = nacl.hash.sha512
+        digest = HASHER(key, encoder=HexEncoder)
+
+        return digest.decode()
+
+        
diff --git a/db.py b/db.py
new file mode 100644 (file)
index 0000000..e904fb1
--- /dev/null
+++ b/db.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018  Michael Rasmussen <mir@datanom.net>
+# This file is part of SecureMail.
+
+# SecureMail is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# SecureMail is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with SecureMail.  If not, see <https://www.gnu.org/licenses/>.
+
+from config import DBTYPE, DBHOST, DBPORT, DBUID, DBPWD, DBNAME
+
+class Singleton:
+    def __init__(self, klass):
+        self.klass = klass
+        self.instance = None
+
+    def __call__(self, *args, **kwargs):
+        if self.instance == None:
+            self.instance = self.klass(*args, **kwargs)
+        return self.instance
+
+@Singleton
+class DB:
+    conn = None
+
+    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)
+            elif DBTYPE == 'postgresql':
+                import psycopg2
+                self.conn = psycopg2.connect(host=DBHOST, port=DBPORT, user=DBUID, password=DBPWD, dbname=DBNAME)
+        return self.conn
+        
+    def __del__(self):
+        if self.conn is not None:
+            self.conn.close()
+
+class DBInterface:
+    @staticmethod
+    def load_user(key):
+        conn = DB().get_connection()
+        cursor = conn.cursor()
+        cursor.execute("select a.cipher from account a where id = '{0}'".format(key))
+        row = cursor.fetchone()
+        if row is None:
+            obj = None
+        else:
+            obj = row[0].tobytes()
+        cursor.close()
+        
+        return obj
+        
+    @staticmethod
+    def store_user(key, cipher):
+        conn = DB().get_connection()
+        cursor = conn.cursor()
+        cursor.execute("insert into account(id, cipher) values(%s, %s)", (key, cipher))
+        conn.commit()
+        cursor.close()
diff --git a/user.py b/user.py
new file mode 100644 (file)
index 0000000..3b4c051
--- /dev/null
+++ b/user.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018  Michael Rasmussen <mir@datanom.net>
+# This file is part of SecureMail.
+
+# SecureMail is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# SecureMail is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# 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
+from db import DBInterface as DBI
+from cryptonize import Cryptonize
+
+class NoSuchUserException(Exception):
+    pass
+
+class User:
+    """
+    Class implementing the backend users
+    """
+    def __init__(self, key=None):
+        if key is not None:
+            self.load(key)
+
+    def store(self, key):
+        crypto = Cryptonize()
+        cipher = crypto.symmetric_encrypt(key, pickle.dumps(self.__dict__))
+        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))
+        plain = crypto.symmetric_decrypt(key, cipher)
+        try:
+            obj = pickle.loads(plain)
+            self.__dict__.update(obj)
+        except pickle.UnpicklingError as e:
+            raise NoSuchUserException(e)
+            
+    @property
+    def name(self):
+        return self._name
+
+    @name.setter
+    def name(self, name):
+        self._name = name
+
+    @property
+    def email(self):
+        return self.email
+
+    @email.setter
+    def email(self, email):
+        self._email = email
+
+
+if __name__ == '__main__':
+    try:
+        u = User('test')
+        for attr, value in u.__dict__.items():
+            print ('{0}: {1}'.format(attr, value))
+        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:
+        u = User()
+        u.name = 'testname'
+        u.email = 'testname@securemail.icu'
+        u.store('test')
+    except Exception as e:
+        print (e)
This page took 0.041382 seconds and 5 git commands to generate.