# -*- 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): 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): 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)