X-Git-Url: http://git.datanom.net/securemail.git/blobdiff_plain/7ef0042650fe0a5e12373fd6ef438f138afe65b2..5bc1fc471eb0a72f4420b9189c990026e570d52a:/app/backend/cryptonize.py diff --git a/app/backend/cryptonize.py b/app/backend/cryptonize.py new file mode 100644 index 0000000..7a598d3 --- /dev/null +++ b/app/backend/cryptonize.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Michael Rasmussen + +# 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 . + +from nacl import __version__ as NACL_VERSION +from nacl.secret import SecretBox +from nacl.public import PrivateKey, Box +from nacl.utils import random, EncryptedMessage +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) + if NACL_VERSION < "1.1.0": + nonce = random(SecretBox.NONCE_SIZE) + cipher = box.encrypt(plain, nonce) + else: + cipher = box.encrypt(plain) + box = skey = None + + return cipher + + def symmetric_decrypt(self, key, cipher): + skey = self.sanitize_key(key) + box = SecretBox(skey) + plain = box.decrypt(cipher) + box = skey = None + + return plain + + def asymmetric_encrypt(self, privkey, pubkey, plain): + if not isinstance(plain, bytes): + plain = plain.encode('utf-8') + box = Box(privkey, pubkey) + if NACL_VERSION < "1.1.0": + nonce = random(Box.NONCE_SIZE) + cipher = box.encrypt(plain, nonce) + else: + cipher = box.encrypt(plain) + box = None + + return cipher + + def asymmetric_decrypt(self, privkey, pubkey, cipher): + if not isinstance(cipher, bytes): + cipher = cipher.encode('utf-8') + 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 """ + newkey = key + bytes(SecretBox.KEY_SIZE - size) + elif size > SecretBox.KEY_SIZE: + newkey = key[:SecretBox.KEY_SIZE] + 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() + + def create_EncryptedMessage(self, payload): + nonce = payload[:SecretBox.NONCE_SIZE] + ciphertext = payload[SecretBox.NONCE_SIZE:] + + return EncryptedMessage._from_parts( + nonce, ciphertext, nonce + ciphertext)