69 lines
2.4 KiB
Python
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)
|