easywks/easywks/crypto.py
2021-09-26 09:01:18 +02:00

69 lines
2.4 KiB
Python

import os
import stat
from pgpy import PGPKey, PGPUID, PGPMessage, PGPSignature
from pgpy.constants import PubKeyAlgorithm, KeyFlags, SymmetricKeyAlgorithm, HashAlgorithm, CompressionAlgorithm
from .config import Config
def _keyfile(domain: str) -> str:
return os.path.join(Config.working_directory, domain, 'key.pgp')
class PrivateKey:
def __init__(self, domain: str):
key, _ = PGPKey.from_file(_keyfile(domain))
self.key: PGPKey = key
self.passphrase: str = Config[domain].passphrase
self.context = None
def __enter__(self):
if self.key.is_protected:
self.context = self.key.unlock(self.passphrase)
self.context.__enter__()
return self.key
def __exit__(self, exc_type, exc_val, exc_tb):
if self.context:
self.context.__exit__(exc_type, exc_val, exc_tb)
self.context = None
def create_pgp_key(domain: str):
keyfile = _keyfile(domain)
if os.path.exists(keyfile):
return
# Generate RSA key and UID
key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 3072)
subkey = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 3072)
uid = PGPUID.new(pn='', comment='', email=Config[domain].submission_address)
key.add_uid(uid, selfsign=True, primary=True, key_expiration=None,
usage={KeyFlags.Sign, KeyFlags.Certify},
hashes=[HashAlgorithm.SHA512, HashAlgorithm.SHA256],
ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.Camellia256],
compression=[CompressionAlgorithm.BZ2, CompressionAlgorithm.Uncompressed])
key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications})
passphrase = Config[domain].passphrase
if passphrase is not None and len(passphrase) > 0:
key.protect(passphrase, SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256)
with open(keyfile, 'wb') as f:
os.chmod(keyfile, stat.S_IRUSR | stat.S_IWUSR)
f.write(bytes(key))
def privkey_to_pubkey(domain: str) -> PGPKey:
keyfile = _keyfile(domain)
key, _ = PGPKey.from_file(keyfile)
return key.pubkey
def pgp_decrypt(domain: str, message: PGPMessage) -> PGPMessage:
with PrivateKey(domain) as key:
return key.decrypt(message)
def pgp_sign(domain: str, message: PGPMessage) -> PGPSignature:
with PrivateKey(domain) as key:
return key.sign(message)