ccssh 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccssh/__init__.py +21 -0
- ccssh/__main__.py +5 -0
- ccssh/algs.py +290 -0
- ccssh/async_client.py +419 -0
- ccssh/auth.py +170 -0
- ccssh/certs.py +283 -0
- ccssh/chacha.py +117 -0
- ccssh/channel.py +124 -0
- ccssh/chansock.py +227 -0
- ccssh/cli.py +889 -0
- ccssh/client.py +1274 -0
- ccssh/crypto.py +316 -0
- ccssh/dh_groups.py +92 -0
- ccssh/forward.py +872 -0
- ccssh/gcm.py +87 -0
- ccssh/hostcheck.py +217 -0
- ccssh/hostkeys.py +250 -0
- ccssh/kex.py +222 -0
- ccssh/kex_ext.py +429 -0
- ccssh/mldsa.py +210 -0
- ccssh/mlkem.py +367 -0
- ccssh/mux.py +301 -0
- ccssh/sftp.py +270 -0
- ccssh/shell.py +257 -0
- ccssh/sk.py +224 -0
- ccssh/sntrup.py +325 -0
- ccssh/stub.py +710 -0
- ccssh/transport.py +737 -0
- ccssh/umac.py +262 -0
- ccssh/wire.py +199 -0
- ccssh-1.0.0.dist-info/METADATA +442 -0
- ccssh-1.0.0.dist-info/RECORD +36 -0
- ccssh-1.0.0.dist-info/WHEEL +5 -0
- ccssh-1.0.0.dist-info/entry_points.txt +2 -0
- ccssh-1.0.0.dist-info/licenses/LICENSE +21 -0
- ccssh-1.0.0.dist-info/top_level.txt +1 -0
ccssh/crypto.py
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Symmetric packet protection: AES-CTR + HMAC, key derivation, framing helpers.
|
|
3
|
+
|
|
4
|
+
Primitives come from `cryptography`; all protocol framing is ours.
|
|
5
|
+
Covers RFC 4253 section 6 (binary packet protocol) and section 7.2 (KDF),
|
|
6
|
+
plus OpenSSH *-etm modes (length sent in the clear, see packet.c).
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
import hashlib
|
|
10
|
+
import os
|
|
11
|
+
import struct
|
|
12
|
+
|
|
13
|
+
from cryptography.hazmat.primitives import hashes, hmac
|
|
14
|
+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def HASH_sha256(data: bytes) -> bytes:
|
|
18
|
+
return hashlib.sha256(data).digest()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def kdf(hash_fn, K_encoded: bytes, H: bytes, session_id: bytes, letter: bytes, out_len: int) -> bytes:
|
|
22
|
+
"""
|
|
23
|
+
RFC 4253 section 7.2 key expansion.
|
|
24
|
+
|
|
25
|
+
K1 = HASH(K || H || X || session_id), Kn+1 = HASH(K || H || K1 || .. || Kn).
|
|
26
|
+
``hash_fn`` must be the *key exchange* hash (e.g. SHA-256 for
|
|
27
|
+
curve25519-sha256), never derived from the cipher/MAC choice.
|
|
28
|
+
"""
|
|
29
|
+
if len(letter) != 1:
|
|
30
|
+
raise ValueError("letter must be a single byte")
|
|
31
|
+
if not 0 < out_len <= 1024:
|
|
32
|
+
raise ValueError("kdf out_len out of range")
|
|
33
|
+
out = hash_fn(K_encoded + H + letter + session_id)
|
|
34
|
+
while len(out) < out_len:
|
|
35
|
+
out += hash_fn(K_encoded + H + out)
|
|
36
|
+
return out[:out_len]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
CIPHER_SPECS = {
|
|
40
|
+
"aes128-ctr": {"key_len": 16, "iv_len": 16, "block": 16},
|
|
41
|
+
"aes192-ctr": {"key_len": 24, "iv_len": 16, "block": 16},
|
|
42
|
+
"aes256-ctr": {"key_len": 32, "iv_len": 16, "block": 16},
|
|
43
|
+
}
|
|
44
|
+
"""
|
|
45
|
+
Legacy chained-IV CBC (RFC 4253 section 6): disabled by default, see
|
|
46
|
+
algs.LEGACY_CIPHERS. Same framing as CTR; only the crypt operation differs.
|
|
47
|
+
"""
|
|
48
|
+
CBC_SPECS = {
|
|
49
|
+
"aes128-cbc": {"prim": "aes", "key_len": 16, "iv_len": 16, "block": 16},
|
|
50
|
+
"aes192-cbc": {"prim": "aes", "key_len": 24, "iv_len": 16, "block": 16},
|
|
51
|
+
"aes256-cbc": {"prim": "aes", "key_len": 32, "iv_len": 16, "block": 16},
|
|
52
|
+
"3des-cbc": {"prim": "3des", "key_len": 24, "iv_len": 8, "block": 8},
|
|
53
|
+
}
|
|
54
|
+
MAC_SPECS = {
|
|
55
|
+
"hmac-sha2-256": {"key_len": 32, "out_len": 32, "etm": False},
|
|
56
|
+
"hmac-sha2-512": {"key_len": 64, "out_len": 64, "etm": False},
|
|
57
|
+
"hmac-sha1": {"key_len": 20, "out_len": 20, "etm": False},
|
|
58
|
+
"hmac-sha2-256-etm@openssh.com": {"key_len": 32, "out_len": 32, "etm": True},
|
|
59
|
+
"hmac-sha2-512-etm@openssh.com": {"key_len": 64, "out_len": 64, "etm": True},
|
|
60
|
+
"hmac-sha1-etm@openssh.com": {"key_len": 20, "out_len": 20, "etm": True},
|
|
61
|
+
"hmac-sha1-96": {"key_len": 20, "out_len": 12, "etm": False},
|
|
62
|
+
"hmac-sha1-96-etm@openssh.com": {"key_len": 20, "out_len": 12, "etm": True},
|
|
63
|
+
"hmac-md5": {"key_len": 16, "out_len": 16, "etm": False},
|
|
64
|
+
"hmac-md5-etm@openssh.com": {"key_len": 16, "out_len": 16, "etm": True},
|
|
65
|
+
"hmac-md5-96": {"key_len": 16, "out_len": 12, "etm": False},
|
|
66
|
+
"hmac-md5-96-etm@openssh.com": {"key_len": 16, "out_len": 12, "etm": True},
|
|
67
|
+
"umac-64@openssh.com": {"key_len": 16, "out_len": 8, "etm": False},
|
|
68
|
+
"umac-128@openssh.com": {"key_len": 16, "out_len": 16, "etm": False},
|
|
69
|
+
"umac-64-etm@openssh.com": {"key_len": 16, "out_len": 8, "etm": True},
|
|
70
|
+
"umac-128-etm@openssh.com": {"key_len": 16, "out_len": 16, "etm": True},
|
|
71
|
+
}
|
|
72
|
+
_HASH_BY_MAC = {
|
|
73
|
+
"hmac-sha2-256": hashlib.sha256,
|
|
74
|
+
"hmac-sha2-256-etm@openssh.com": hashlib.sha256,
|
|
75
|
+
"hmac-sha2-512": hashlib.sha512,
|
|
76
|
+
"hmac-sha2-512-etm@openssh.com": hashlib.sha512,
|
|
77
|
+
"hmac-sha1": hashlib.sha1,
|
|
78
|
+
"hmac-sha1-etm@openssh.com": hashlib.sha1,
|
|
79
|
+
"hmac-sha1-96": hashlib.sha1,
|
|
80
|
+
"hmac-sha1-96-etm@openssh.com": hashlib.sha1,
|
|
81
|
+
"hmac-md5": hashlib.md5,
|
|
82
|
+
"hmac-md5-etm@openssh.com": hashlib.md5,
|
|
83
|
+
"hmac-md5-96": hashlib.md5,
|
|
84
|
+
"hmac-md5-96-etm@openssh.com": hashlib.md5,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _kdf_hash(cipher: str, mac: str, hashfn):
|
|
89
|
+
"""
|
|
90
|
+
Resolve the KDF hash: explicit KEX hash wins, else MAC-implied (legacy).
|
|
91
|
+
|
|
92
|
+
Production callers always pass the KEX hash (RFC 4253 section 7.2);
|
|
93
|
+
the fallback exists for the test stub and ad-hoc callers, which only
|
|
94
|
+
use SHA-256 KEX methods there.
|
|
95
|
+
"""
|
|
96
|
+
if hashfn is not None:
|
|
97
|
+
return hashfn
|
|
98
|
+
digestmod = _HASH_BY_MAC.get(mac, hashlib.sha256)
|
|
99
|
+
return lambda d: digestmod(d).digest()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def derive_keys(K_encoded: bytes, H: bytes, session_id: bytes, cipher: str, mac: str, hashfn=None) -> dict[str, bytes]:
|
|
103
|
+
"""Derive the six direction keys (A..F). Prefer passing the KEX hash."""
|
|
104
|
+
try:
|
|
105
|
+
cs = CIPHER_SPECS[cipher]
|
|
106
|
+
except KeyError:
|
|
107
|
+
try:
|
|
108
|
+
cs = CBC_SPECS[cipher]
|
|
109
|
+
except KeyError as e:
|
|
110
|
+
raise ValueError(f"unsupported cipher {cipher}") from e
|
|
111
|
+
try:
|
|
112
|
+
ms = MAC_SPECS[mac]
|
|
113
|
+
except KeyError as e:
|
|
114
|
+
raise ValueError(f"unsupported mac {mac}") from e
|
|
115
|
+
hf = _kdf_hash(cipher, mac, hashfn)
|
|
116
|
+
return {
|
|
117
|
+
"iv_c2s": kdf(hf, K_encoded, H, session_id, b"A", cs["iv_len"]),
|
|
118
|
+
"iv_s2c": kdf(hf, K_encoded, H, session_id, b"B", cs["iv_len"]),
|
|
119
|
+
"enc_c2s": kdf(hf, K_encoded, H, session_id, b"C", cs["key_len"]),
|
|
120
|
+
"enc_s2c": kdf(hf, K_encoded, H, session_id, b"D", cs["key_len"]),
|
|
121
|
+
"mac_c2s": kdf(hf, K_encoded, H, session_id, b"E", ms["key_len"]),
|
|
122
|
+
"mac_s2c": kdf(hf, K_encoded, H, session_id, b"F", ms["key_len"]),
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
try:
|
|
127
|
+
from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES
|
|
128
|
+
except ImportError: # older cryptography: pre-move location (warns, still works)
|
|
129
|
+
from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES
|
|
130
|
+
|
|
131
|
+
_HASH_CLASSES = {
|
|
132
|
+
"hmac-sha2-256": hashes.SHA256,
|
|
133
|
+
"hmac-sha2-256-etm@openssh.com": hashes.SHA256,
|
|
134
|
+
"hmac-sha2-512": hashes.SHA512,
|
|
135
|
+
"hmac-sha2-512-etm@openssh.com": hashes.SHA512,
|
|
136
|
+
"hmac-sha1": hashes.SHA1,
|
|
137
|
+
"hmac-sha1-etm@openssh.com": hashes.SHA1,
|
|
138
|
+
"hmac-sha1-96": hashes.SHA1,
|
|
139
|
+
"hmac-sha1-96-etm@openssh.com": hashes.SHA1,
|
|
140
|
+
"hmac-md5": hashes.MD5,
|
|
141
|
+
"hmac-md5-etm@openssh.com": hashes.MD5,
|
|
142
|
+
"hmac-md5-96": hashes.MD5,
|
|
143
|
+
"hmac-md5-96-etm@openssh.com": hashes.MD5,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class SshMac:
|
|
148
|
+
"""
|
|
149
|
+
Packet MAC shared by the CTR and CBC direction contexts: HMAC-*
|
|
150
|
+
(plain and -etm, full and -96 truncated) or UMAC-64/128
|
|
151
|
+
(draft-miller-secsh-umac-01, seq as uint64 nonce).
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
def __init__(self, mac: str, mac_key: bytes):
|
|
155
|
+
try:
|
|
156
|
+
ms = MAC_SPECS[mac]
|
|
157
|
+
except KeyError as e:
|
|
158
|
+
raise ValueError(f"unsupported mac: {mac}") from e
|
|
159
|
+
if len(mac_key) != ms["key_len"]:
|
|
160
|
+
raise ValueError(f"bad mac key length for {mac}")
|
|
161
|
+
self.mac, self.mac_len, self.etm = mac, ms["out_len"], ms["etm"]
|
|
162
|
+
self._mac_key = mac_key
|
|
163
|
+
self._umac = None
|
|
164
|
+
self._hcls = None
|
|
165
|
+
if mac.startswith("umac-"):
|
|
166
|
+
from ccssh import umac as _umac_mod
|
|
167
|
+
self._umac = _umac_mod.UMacCtx(mac_key, ms["out_len"])
|
|
168
|
+
else:
|
|
169
|
+
try:
|
|
170
|
+
self._hcls = _HASH_CLASSES[mac]
|
|
171
|
+
except KeyError as e:
|
|
172
|
+
raise ValueError(f"unsupported mac: {mac}") from e
|
|
173
|
+
|
|
174
|
+
def mac_of(self, seq: int, data: bytes) -> bytes:
|
|
175
|
+
if not 0 <= seq < 2**32:
|
|
176
|
+
raise ValueError("sequence number out of range")
|
|
177
|
+
if self._umac is not None:
|
|
178
|
+
return self._umac.tag(seq, data)
|
|
179
|
+
h = hmac.HMAC(self._mac_key, self._hcls())
|
|
180
|
+
h.update(struct.pack(">I", seq) + data)
|
|
181
|
+
return h.finalize()[:self.mac_len]
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class AesCtrHmacCtx:
|
|
185
|
+
"""
|
|
186
|
+
One direction of AES-CTR + MAC. Stateful CTR via a held encryptor.
|
|
187
|
+
|
|
188
|
+
``etm`` switches the MAC input from plaintext to ciphertext; the caller
|
|
189
|
+
(transport) owns framing for both cases.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
def __init__(self, cipher: str, mac: str, enc_key: bytes, iv: bytes, mac_key: bytes):
|
|
193
|
+
try:
|
|
194
|
+
cs = CIPHER_SPECS[cipher]
|
|
195
|
+
except KeyError as e:
|
|
196
|
+
raise ValueError(f"unsupported cipher/mac: {cipher}/{mac}") from e
|
|
197
|
+
if len(enc_key) != cs["key_len"] or len(iv) != cs["iv_len"]:
|
|
198
|
+
raise ValueError(f"bad enc/iv lengths for {cipher}")
|
|
199
|
+
self.cipher, self.mac = cipher, mac
|
|
200
|
+
self._mac = SshMac(mac, mac_key)
|
|
201
|
+
self.etm = self._mac.etm
|
|
202
|
+
self.mac_len = self._mac.mac_len
|
|
203
|
+
self.block_size = cs["block"]
|
|
204
|
+
enc = Cipher(algorithms.AES(enc_key), modes.CTR(iv)).encryptor()
|
|
205
|
+
dec = Cipher(algorithms.AES(enc_key), modes.CTR(iv)).decryptor()
|
|
206
|
+
self._enc, self._dec = enc, dec
|
|
207
|
+
|
|
208
|
+
def mac_of(self, seq: int, data: bytes) -> bytes:
|
|
209
|
+
return self._mac.mac_of(seq, data)
|
|
210
|
+
|
|
211
|
+
def encrypt_stream(self, data: bytes) -> bytes:
|
|
212
|
+
return self._enc.update(data)
|
|
213
|
+
|
|
214
|
+
def decrypt_stream(self, data: bytes) -> bytes:
|
|
215
|
+
return self._dec.update(data)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class CbcHmacCtx:
|
|
219
|
+
"""
|
|
220
|
+
One direction of chained-IV CBC + MAC (legacy: aes*-cbc, 3des-cbc).
|
|
221
|
+
|
|
222
|
+
SSH CBC chains the IV across packets (RFC 4253 section 6), so the
|
|
223
|
+
encryptor/decryptor are held like the CTR ones. Disabled by default
|
|
224
|
+
(see algs.LEGACY_CIPHERS); force explicitly to interoperate.
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
def __init__(self, cipher: str, mac: str, enc_key: bytes, iv: bytes, mac_key: bytes):
|
|
228
|
+
try:
|
|
229
|
+
cs = CBC_SPECS[cipher]
|
|
230
|
+
except KeyError as e:
|
|
231
|
+
raise ValueError(f"unsupported cipher/mac: {cipher}/{mac}") from e
|
|
232
|
+
if len(enc_key) != cs["key_len"] or len(iv) != cs["iv_len"]:
|
|
233
|
+
raise ValueError(f"bad enc/iv lengths for {cipher}")
|
|
234
|
+
self.cipher, self.mac = cipher, mac
|
|
235
|
+
self._mac = SshMac(mac, mac_key)
|
|
236
|
+
self.etm = self._mac.etm
|
|
237
|
+
self.mac_len = self._mac.mac_len
|
|
238
|
+
self.block_size = cs["block"]
|
|
239
|
+
if cs["prim"] == "3des":
|
|
240
|
+
enc = Cipher(TripleDES(enc_key), modes.CBC(iv)).encryptor()
|
|
241
|
+
dec = Cipher(TripleDES(enc_key), modes.CBC(iv)).decryptor()
|
|
242
|
+
else:
|
|
243
|
+
enc = Cipher(algorithms.AES(enc_key), modes.CBC(iv)).encryptor()
|
|
244
|
+
dec = Cipher(algorithms.AES(enc_key), modes.CBC(iv)).decryptor()
|
|
245
|
+
self._enc, self._dec = enc, dec
|
|
246
|
+
|
|
247
|
+
def mac_of(self, seq: int, data: bytes) -> bytes:
|
|
248
|
+
return self._mac.mac_of(seq, data)
|
|
249
|
+
|
|
250
|
+
def encrypt_stream(self, data: bytes) -> bytes:
|
|
251
|
+
if len(data) % self.block_size != 0:
|
|
252
|
+
raise ValueError("CBC encrypt length must be a block multiple")
|
|
253
|
+
return self._enc.update(data)
|
|
254
|
+
|
|
255
|
+
def decrypt_stream(self, data: bytes) -> bytes:
|
|
256
|
+
if len(data) % self.block_size != 0:
|
|
257
|
+
raise ValueError("CBC decrypt length must be a block multiple")
|
|
258
|
+
return self._dec.update(data)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def pad_packet(payload_len_plus1: int, block_size: int) -> int:
|
|
262
|
+
"""
|
|
263
|
+
Padding length so that (4 + 1 + payload + pad) is a block multiple.
|
|
264
|
+
|
|
265
|
+
``payload_len_plus1`` is 1 (padding-length byte) + len(payload).
|
|
266
|
+
For ciphers where packet_length itself is encrypted (CBC/CTR/non-ETM,
|
|
267
|
+
and plaintext before NEWKEYS). Minimum padding is 4 bytes.
|
|
268
|
+
"""
|
|
269
|
+
pad = block_size - ((4 + payload_len_plus1) % block_size)
|
|
270
|
+
if pad < 4:
|
|
271
|
+
pad += block_size
|
|
272
|
+
if pad > 255:
|
|
273
|
+
raise ValueError("padding exceeds 255 bytes")
|
|
274
|
+
return pad
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def pad_len_aad(payload_len: int, block_size: int) -> int:
|
|
278
|
+
"""
|
|
279
|
+
Padding length so that (1 + payload + pad) is a block multiple.
|
|
280
|
+
|
|
281
|
+
For modes where packet_length travels unencrypted (ETM, AES-GCM with
|
|
282
|
+
block 16, chacha20-poly1305 with block 8). OpenSSH drops packets with
|
|
283
|
+
wrong alignment ("padding error").
|
|
284
|
+
"""
|
|
285
|
+
pad = block_size - ((1 + payload_len) % block_size)
|
|
286
|
+
if pad < 4:
|
|
287
|
+
pad += block_size
|
|
288
|
+
if pad > 255:
|
|
289
|
+
raise ValueError("padding exceeds 255 bytes")
|
|
290
|
+
return pad
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def build_unencrypted_block(payload: bytes, block_size: int) -> bytes:
|
|
294
|
+
"""Assemble packet_length || padding_length || payload || padding."""
|
|
295
|
+
# SSH packet_length (payload+padding+1) must fit MAX_PACKET=35000;
|
|
296
|
+
# SFTP data responses legitimately carry ~32KB + framing overhead,
|
|
297
|
+
# so cap the final packet length, not the raw payload.
|
|
298
|
+
pad_len = pad_packet(1 + len(payload), block_size)
|
|
299
|
+
pkt_len = 1 + len(payload) + pad_len
|
|
300
|
+
if pkt_len > 35000:
|
|
301
|
+
raise ValueError(f"packet too large (packet_length={pkt_len})")
|
|
302
|
+
return struct.pack(">I", pkt_len) + bytes([pad_len]) + payload + os.urandom(pad_len)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def build_aad_block(payload: bytes, block_size: int) -> tuple[bytes, bytes]:
|
|
306
|
+
"""
|
|
307
|
+
Assemble (length_field, body) for length-in-clear modes.
|
|
308
|
+
|
|
309
|
+
Returns the 4-byte big-endian packet_length and the
|
|
310
|
+
padding_length || payload || padding body.
|
|
311
|
+
"""
|
|
312
|
+
pad_len = pad_len_aad(len(payload), block_size)
|
|
313
|
+
body = bytes([pad_len]) + payload + os.urandom(pad_len)
|
|
314
|
+
if len(body) > 35000:
|
|
315
|
+
raise ValueError(f"packet too large (packet_length={len(body)})")
|
|
316
|
+
return struct.pack(">I", len(body)), body
|
ccssh/dh_groups.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RFC 3526 MODP primes, extracted mechanically from rfc3526.txt (no hand copying).
|
|
3
|
+
|
|
4
|
+
Plus the Oakley Group 2 1024-bit prime (RFC 2409 section 6.2) for the
|
|
5
|
+
legacy diffie-hellman-group1-sha1 method: weak by modern standards,
|
|
6
|
+
disabled by default (see algs.LEGACY_KEX), force explicitly to use.
|
|
7
|
+
Its bit length is asserted like the rest; live interop against a real
|
|
8
|
+
sshd proves the digits.
|
|
9
|
+
"""
|
|
10
|
+
P14_2048_HEX = (
|
|
11
|
+
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74"
|
|
12
|
+
"020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437"
|
|
13
|
+
"4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
|
14
|
+
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05"
|
|
15
|
+
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB"
|
|
16
|
+
"9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
|
17
|
+
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
|
18
|
+
"3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"
|
|
19
|
+
)
|
|
20
|
+
P14_2048 = int(P14_2048_HEX, 16)
|
|
21
|
+
if P14_2048.bit_length() != 2048:
|
|
22
|
+
raise ValueError("group14 prime corrupted")
|
|
23
|
+
P1_1024_HEX = (
|
|
24
|
+
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
|
|
25
|
+
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
|
|
26
|
+
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
|
|
27
|
+
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
|
28
|
+
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
|
|
29
|
+
"FFFFFFFFFFFFFFFF"
|
|
30
|
+
)
|
|
31
|
+
P1_1024 = int(P1_1024_HEX, 16)
|
|
32
|
+
if P1_1024.bit_length() != 1024:
|
|
33
|
+
raise ValueError("group1 prime corrupted")
|
|
34
|
+
P16_4096_HEX = (
|
|
35
|
+
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74"
|
|
36
|
+
"020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437"
|
|
37
|
+
"4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
|
38
|
+
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05"
|
|
39
|
+
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB"
|
|
40
|
+
"9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
|
41
|
+
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
|
42
|
+
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33"
|
|
43
|
+
"A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
|
44
|
+
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864"
|
|
45
|
+
"D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2"
|
|
46
|
+
"08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
|
|
47
|
+
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8"
|
|
48
|
+
"DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
|
|
49
|
+
"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
|
|
50
|
+
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF"
|
|
51
|
+
)
|
|
52
|
+
P16_4096 = int(P16_4096_HEX, 16)
|
|
53
|
+
if P16_4096.bit_length() != 4096:
|
|
54
|
+
raise ValueError("group16 prime corrupted")
|
|
55
|
+
P18_8192_HEX = (
|
|
56
|
+
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74"
|
|
57
|
+
"020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437"
|
|
58
|
+
"4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
|
|
59
|
+
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05"
|
|
60
|
+
"98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB"
|
|
61
|
+
"9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
|
|
62
|
+
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
|
|
63
|
+
"3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33"
|
|
64
|
+
"A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
|
|
65
|
+
"ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864"
|
|
66
|
+
"D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2"
|
|
67
|
+
"08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
|
|
68
|
+
"88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8"
|
|
69
|
+
"DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
|
|
70
|
+
"233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
|
|
71
|
+
"93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026"
|
|
72
|
+
"C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE"
|
|
73
|
+
"B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
|
|
74
|
+
"DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC"
|
|
75
|
+
"F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E"
|
|
76
|
+
"59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
|
|
77
|
+
"CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76"
|
|
78
|
+
"F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468"
|
|
79
|
+
"043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
|
|
80
|
+
"38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED"
|
|
81
|
+
"2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652D"
|
|
82
|
+
"E3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
|
|
83
|
+
"4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6"
|
|
84
|
+
"6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851D"
|
|
85
|
+
"F9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
|
|
86
|
+
"4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA"
|
|
87
|
+
"9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF"
|
|
88
|
+
)
|
|
89
|
+
P18_8192 = int(P18_8192_HEX, 16)
|
|
90
|
+
if P18_8192.bit_length() != 8192:
|
|
91
|
+
raise ValueError("group18 prime corrupted")
|
|
92
|
+
G = 2
|