1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
# Copyright (C) 2017 Jan Jancar
#
# This file is a part of the Mailman PGP plugin.
#
# This program 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.
#
# This program 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
# this program. If not, see <http://www.gnu.org/licenses/>.
"""List key generator runs in a separate process to not block for the
potentially long key generation operation."""
import multiprocessing as mp
from os.path import exists, isfile
from flufl.lock import Lock
from pgpy import PGPKey, PGPUID
from pgpy.constants import (
CompressionAlgorithm, HashAlgorithm, KeyFlags, SymmetricKeyAlgorithm)
class ListKeyGenerator(mp.Process):
"""A multiprocessing list key generator."""
def __init__(self, keypair_config, display_name, posting_address,
request_address, key_path):
super().__init__(
target=self.generate,
args=(keypair_config, display_name, posting_address,
request_address, key_path))
def generate(self, keypair_config, display_name, posting_address,
request_address, key_path):
"""
Generate the list keypair and save it, if it does not exist.
:param keypair_config:
:param display_name:
:param posting_address:
:param request_address:
:param key_path:
"""
with Lock(key_path + '.lock'):
if exists(key_path) and isfile(key_path):
return
key = self._create(keypair_config, display_name, posting_address,
request_address)
self._save(key, key_path)
def _create(self, config, display_name, posting_address, request_address):
"""
Generate the list `PGPKey` keypair, with posting and request UIDs.
Use a Sign+Certify main key and Encrypt subkey.
:param config:
:param display_name:
:param posting_address:
:param request_address:
:return: `PGPKey`
"""
# Generate the Sign + Certify primary key.
key_type = config['key_type']
key_length = config['key_length']
key = PGPKey.new(key_type, key_length)
key_params = dict(usage={KeyFlags.Sign, KeyFlags.Certify},
hashes=[HashAlgorithm.SHA256,
HashAlgorithm.SHA384,
HashAlgorithm.SHA512,
HashAlgorithm.SHA224],
ciphers=[SymmetricKeyAlgorithm.AES256,
SymmetricKeyAlgorithm.AES192,
SymmetricKeyAlgorithm.AES128],
compression=[CompressionAlgorithm.ZLIB,
CompressionAlgorithm.BZ2,
CompressionAlgorithm.ZIP,
CompressionAlgorithm.Uncompressed],
primary=True)
# Generate the posting + request uids.
main_uid = PGPUID.new(display_name, email=posting_address)
request_uid = PGPUID.new(display_name,
email=request_address)
# Generate the Encrypt subkey.
subkey_type = config['subkey_type']
subkey_length = config['subkey_length']
subkey = PGPKey.new(subkey_type, subkey_length)
subkey_params = dict(
usage={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage},
primary=False
)
# Put it all together.
key.add_uid(main_uid, **key_params)
key.add_uid(request_uid, **key_params)
key.add_subkey(subkey, **subkey_params)
return key
def _save(self, key, key_path):
"""
Save the generated key.
:param key:
:param key_path:
"""
with open(key_path, 'w') as key_file:
key_file.write(str(key))
|