purepycrypto 3.2.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.
Files changed (71) hide show
  1. purepycrypto/__init__.py +389 -0
  2. purepycrypto/__main__.py +20 -0
  3. purepycrypto/_ppyc_error.py +330 -0
  4. purepycrypto/_version.py +1 -0
  5. purepycrypto/aes.py +869 -0
  6. purepycrypto/aes_gcm_siv.py +644 -0
  7. purepycrypto/chacha.py +349 -0
  8. purepycrypto/cli.py +1177 -0
  9. purepycrypto/cli_args.py +794 -0
  10. purepycrypto/common.py +210 -0
  11. purepycrypto/der.py +150 -0
  12. purepycrypto/ed25519.py +634 -0
  13. purepycrypto/encoding.py +922 -0
  14. purepycrypto/examples/encrypt_file.py +84 -0
  15. purepycrypto/examples/key_exchange.py +62 -0
  16. purepycrypto/examples/parallel_usage.py +61 -0
  17. purepycrypto/examples/sign_verify.py +57 -0
  18. purepycrypto/hash.py +253 -0
  19. purepycrypto/kdf.py +553 -0
  20. purepycrypto/kdf2.py +1109 -0
  21. purepycrypto/parallel.py +169 -0
  22. purepycrypto/py.typed +0 -0
  23. purepycrypto/rand.py +606 -0
  24. purepycrypto/rsa.py +775 -0
  25. purepycrypto/scripts/build_single.py +487 -0
  26. purepycrypto/sha3.py +477 -0
  27. purepycrypto/single/purepycrypto.py +9539 -0
  28. purepycrypto/tests/__init__.py +0 -0
  29. purepycrypto/tests/_vectors.py +13 -0
  30. purepycrypto/tests/conftest.py +12 -0
  31. purepycrypto/tests/test_aes.py +219 -0
  32. purepycrypto/tests/test_chacha.py +76 -0
  33. purepycrypto/tests/test_cli.py +213 -0
  34. purepycrypto/tests/test_ed25519.py +121 -0
  35. purepycrypto/tests/test_encoding.py +334 -0
  36. purepycrypto/tests/test_encoding_verify.py +320 -0
  37. purepycrypto/tests/test_errors.py +175 -0
  38. purepycrypto/tests/test_errors_edge.py +371 -0
  39. purepycrypto/tests/test_gcm_siv.py +113 -0
  40. purepycrypto/tests/test_hash.py +74 -0
  41. purepycrypto/tests/test_kdf.py +124 -0
  42. purepycrypto/tests/test_kdf2.py +393 -0
  43. purepycrypto/tests/test_kdf2_verify.py +299 -0
  44. purepycrypto/tests/test_multiprocess.py +160 -0
  45. purepycrypto/tests/test_rand.py +339 -0
  46. purepycrypto/tests/test_rand_verify.py +293 -0
  47. purepycrypto/tests/test_rsa.py +125 -0
  48. purepycrypto/tests/test_sha3.py +78 -0
  49. purepycrypto/tests/test_vectors_strict.py +468 -0
  50. purepycrypto/tests/test_x25519.py +68 -0
  51. purepycrypto/tests/vectors/aes_fips197.json +11 -0
  52. purepycrypto/tests/vectors/aes_gcm_nist.json +13 -0
  53. purepycrypto/tests/vectors/argon2id_rfc9106.json +25 -0
  54. purepycrypto/tests/vectors/blake2b.json +11 -0
  55. purepycrypto/tests/vectors/ed25519_rfc8032.json +28 -0
  56. purepycrypto/tests/vectors/hkdf_rfc5869.json +35 -0
  57. purepycrypto/tests/vectors/pbkdf2.json +12 -0
  58. purepycrypto/tests/vectors/poly1305.json +14 -0
  59. purepycrypto/tests/vectors/rfc8452_gcm_siv.json +439 -0
  60. purepycrypto/tests/vectors/scrypt.json +10 -0
  61. purepycrypto/tests/vectors/sha2.json +20 -0
  62. purepycrypto/tests/vectors/sha3_fips202.json +47 -0
  63. purepycrypto/tests/vectors/shake_fips202.json +47 -0
  64. purepycrypto/tests/vectors/x25519_rfc7748.json +35 -0
  65. purepycrypto/x25519.py +155 -0
  66. purepycrypto-3.2.0.dist-info/METADATA +848 -0
  67. purepycrypto-3.2.0.dist-info/RECORD +71 -0
  68. purepycrypto-3.2.0.dist-info/WHEEL +5 -0
  69. purepycrypto-3.2.0.dist-info/entry_points.txt +2 -0
  70. purepycrypto-3.2.0.dist-info/licenses/LICENSE +21 -0
  71. purepycrypto-3.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,389 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ purepycrypto
4
+ ============
5
+ Pure-Python cryptography library (zero third-party dependencies) - developed by Dvs(DvsXT).
6
+
7
+ Hash
8
+ ----
9
+ - SHA-256 / SHA-512 / BLAKE2b (``hash``)
10
+ - SHA-3 / Keccak / SHAKE, HMAC-SHA3 (``sha3``)
11
+
12
+ Key derivation
13
+ --------
14
+ - HMAC-SHA256/512, PBKDF2, HKDF, scrypt, Argon2id (``kdf``)
15
+
16
+ Symmetric encryption
17
+ --------
18
+ - AES-128/192/256: ECB / CBC / CTR / CFB / OFB / GCM (``aes``)
19
+ - AES-GCM-SIV (RFC 8452, nonce-misuse resistant) (``aes_gcm_siv``)
20
+ - ChaCha20-Poly1305 / XChaCha20-Poly1305 (``chacha``)
21
+
22
+ Public key
23
+ ----
24
+ - X25519 (RFC 7748) (``x25519``)
25
+ - Ed25519 (RFC 8032) (``ed25519``)
26
+ - RSA: keygen / OAEP / PSS / PEM (``rsa``)
27
+ - ASN.1 DER / PEM (``der``)
28
+
29
+ Utilities
30
+ ----
31
+ - Constant-time comparison, secure random, multiprocessing (``common`` / ``parallel``)
32
+
33
+ Usage
34
+ ----
35
+ from purepycrypto import sha256, sha3_256, AES, ed25519_sign
36
+
37
+ digest = sha256(b"hello")
38
+ aes = AES(b"0" * 16)
39
+ ct, tag = aes.gcm_encrypt(b"\\x00" * 12, b"secret")
40
+
41
+ Command line
42
+ ------
43
+ One command, two modes (call it directly after install, no python -m needed):
44
+
45
+ purepycrypto # no args -> interactive TUI
46
+ purepycrypto hash --algo sha256 --text abc --hex # with args -> CLI
47
+ purepycrypto --help # CLI help
48
+ purepycrypto version # show version
49
+ purepycrypto selftest # run built-in self-test
50
+
51
+ Equivalent invocation (when not installed):
52
+
53
+ python -m purepycrypto # TUI
54
+ python -m purepycrypto hash --text abc --hex # CLI
55
+ """
56
+
57
+ # ------------------------------------------------------------------
58
+ # Public API exports
59
+ # ------------------------------------------------------------------
60
+ # ---- Unified error system (the single place where errors are defined) ----
61
+ from ._ppyc_error import (
62
+ PPYC_ERR,
63
+ PPYCError,
64
+ CryptoError,
65
+ DecryptionError,
66
+ Ed25519Error,
67
+ ok, err, is_ok, is_err, raise_ppyc, OK_TUPLE,
68
+ PPYCResult,
69
+ ALL_ERROR_CODES,
70
+ PPYC_ERR_PREFIX,
71
+ )
72
+
73
+ from .common import (
74
+ _consttime_eq,
75
+ _consttime_int_eq,
76
+ _consttime_select,
77
+ rand_int,
78
+ rand_bytes,
79
+ MASK32, MASK64, MASK128,
80
+ POLY1305_P,
81
+ GHASH_R,
82
+ R_CONST,
83
+ )
84
+
85
+ from .hash import sha256, sha512, blake2b
86
+
87
+ from .kdf import (
88
+ hmac_sha256,
89
+ hmac_sha512,
90
+ pbkdf2_hmac,
91
+ hkdf,
92
+ hkdf_extract,
93
+ hkdf_expand,
94
+ scrypt,
95
+ argon2id,
96
+ )
97
+
98
+ from .aes import AES
99
+
100
+ from .chacha import (
101
+ poly1305_mac,
102
+ chacha20poly1305_encrypt,
103
+ chacha20poly1305_decrypt,
104
+ xchacha20poly1305_encrypt,
105
+ xchacha20poly1305_decrypt,
106
+ )
107
+
108
+ from .x25519 import (
109
+ x25519,
110
+ x25519_base,
111
+ x25519_shared,
112
+ x25519_generate_keypair,
113
+ )
114
+
115
+ from .rsa import (
116
+ RSAPublicKey,
117
+ RSAPrivateKey,
118
+ rsa_keygen,
119
+ rsa_oaep_encrypt,
120
+ rsa_oaep_decrypt,
121
+ rsa_pss_sign,
122
+ rsa_pss_verify,
123
+ )
124
+
125
+ from .der import (
126
+ private_key_to_pkcs1_der,
127
+ public_key_to_pkcs1_der,
128
+ private_key_to_pkcs8_der,
129
+ public_key_to_spki_der,
130
+ private_key_to_pem,
131
+ public_key_to_pem,
132
+ parse_private_pem,
133
+ )
134
+
135
+ from .parallel import _HAS_MP
136
+
137
+ # ---- Algorithms added in v1.1 (optional: skipped if the module is missing, for gradual upgrades) ----
138
+ try:
139
+ from .sha3 import (
140
+ sha3_224, sha3_256, sha3_384, sha3_512,
141
+ shake128, shake256,
142
+ hmac_sha3_256, hmac_sha3_512,
143
+ sha3_batch,
144
+ )
145
+ _HAS_SHA3 = True
146
+ except ImportError:
147
+ _HAS_SHA3 = False
148
+
149
+ try:
150
+ from .ed25519 import (
151
+ ed25519_keygen,
152
+ ed25519_publickey,
153
+ ed25519_sign,
154
+ ed25519_verify,
155
+ )
156
+ _HAS_ED25519 = True
157
+ except ImportError:
158
+ _HAS_ED25519 = False
159
+
160
+ try:
161
+ from .aes_gcm_siv import (
162
+ aes128_gcm_siv_encrypt,
163
+ aes128_gcm_siv_decrypt,
164
+ aes256_gcm_siv_encrypt,
165
+ aes256_gcm_siv_decrypt,
166
+ aes_gcm_siv_encrypt,
167
+ aes_gcm_siv_decrypt,
168
+ set_cache_enabled,
169
+ cache_enabled,
170
+ clear_caches,
171
+ )
172
+ _HAS_GCM_SIV = True
173
+ except ImportError:
174
+ _HAS_GCM_SIV = False
175
+
176
+ # ---- Modules added in v3.2.0 (optional: skipped when the module is missing, for gradual upgrades) ----
177
+ try:
178
+ from .kdf2 import (
179
+ pbkdf2, argon2id_hash, argon2id_verify, argon2i_hash, argon2d_hash,
180
+ argon2id_hash_encoded, scrypt_simple,
181
+ )
182
+ _HAS_KDF2 = True
183
+ except ImportError:
184
+ _HAS_KDF2 = False
185
+
186
+ try:
187
+ from .encoding import (
188
+ b64encode, b64decode, b64encode_urlsafe, b64decode_urlsafe,
189
+ b64encode_nopad, b64decode_nopad,
190
+ b32encode, b32decode, b32encode_hex, b32decode_hex,
191
+ hex_encode, hex_decode, hex_encode_sep, hex_decode_sep,
192
+ b58encode, b58decode,
193
+ )
194
+ _HAS_ENCODING = True
195
+ except ImportError:
196
+ _HAS_ENCODING = False
197
+
198
+ try:
199
+ from .rand import (
200
+ random_bytes, random_int, random_below, random_bit, random_bits,
201
+ token_bytes, token_hex, token_urlsafe,
202
+ random_string, random_password, random_uuid4,
203
+ random_choice, random_sample,
204
+ )
205
+ _HAS_RAND = True
206
+ except ImportError:
207
+ _HAS_RAND = False
208
+
209
+ try:
210
+ from ._version import __version__
211
+ except ImportError: # fallback when _version.py has not been generated in a dev environment
212
+ __version__ = "3.2.0"
213
+
214
+ __author__ = "Dvs(DvsXT)"
215
+ __license__ = "MIT"
216
+
217
+
218
+ # ------------------------------------------------------------------
219
+ # Entry points: reuse the single-file build from build_single or the in-package entry modules
220
+ # ------------------------------------------------------------------
221
+
222
+ def run_tui(argv=None):
223
+ """Start the interactive TUI.
224
+
225
+ Prefers the in-package ``purepycrypto.cli``; if unavailable (e.g. a trimmed distribution),
226
+ it falls back to generating and running a single-file TUI build via ``scripts.build_single``.
227
+ """
228
+ try:
229
+ from . import cli
230
+ return cli._tui_main()
231
+ except ImportError:
232
+ return _run_from_build_single("tui", argv)
233
+
234
+
235
+ def run_cli(argv=None):
236
+ """Run the command-line argument version (subcommands: hash/kdf/aes/x25519/rsa/...).
237
+
238
+ Prefers the in-package ``purepycrypto.cli_args``; otherwise falls back to the single-file CLI build from build_single.
239
+ """
240
+ try:
241
+ from . import cli_args
242
+ return cli_args._cli_main(argv)
243
+ except ImportError:
244
+ return _run_from_build_single("cli", argv)
245
+
246
+
247
+ def _run_from_build_single(mode, argv=None):
248
+ """Fallback path: generate and execute a single-file build of the given mode via scripts/build_single.
249
+
250
+ This guarantees that even if the package layout is trimmed, as long as scripts/build_single.py is
251
+ reachable, the full TUI / CLI remains available. build_single itself can also be run standalone.
252
+ """
253
+ import os
254
+ import runpy
255
+ import subprocess
256
+ import sys
257
+ import tempfile
258
+
259
+ here = os.path.dirname(os.path.abspath(__file__))
260
+ build_script = os.path.join(here, "scripts", "build_single.py")
261
+ if not os.path.exists(build_script):
262
+ raise SystemExit(
263
+ "[✗] Neither the cli/cli_args module nor scripts/build_single.py is available; "
264
+ "cannot start " + mode + "."
265
+ )
266
+
267
+ out_dir = tempfile.mkdtemp(prefix="purepycrypto_")
268
+ out_file = os.path.join(out_dir, "purepycrypto_%s.py" % mode)
269
+
270
+ # Invoke build_single to generate the single file (subprocess, avoids polluting this namespace)
271
+ rc = subprocess.call([sys.executable, build_script, "--mode", mode, "-o", out_file])
272
+ if rc != 0 or not os.path.exists(out_file):
273
+ raise SystemExit("[✗] build_single failed to generate " + mode)
274
+
275
+ # Run the single file; in CLI mode pass argv through
276
+ if mode == "cli" and argv is not None:
277
+ return subprocess.call([sys.executable, out_file] + list(argv))
278
+ return runpy.run_path(out_file, run_name="__main__")
279
+
280
+
281
+ def main(argv=None):
282
+ """Unified entry point (serves both the console script ``purepycrypto`` and ``python -m purepycrypto``).
283
+
284
+ Behavior
285
+ ----
286
+ * ``purepycrypto`` (no args) -> start the interactive TUI
287
+ * ``purepycrypto --help`` (with args) -> CLI help
288
+ * ``purepycrypto hash --algo ...``(with args) -> CLI mode
289
+ * ``purepycrypto tui`` (explicit) -> start the TUI
290
+ * ``purepycrypto cli ...`` (legacy form) -> CLI mode
291
+
292
+ That is: **one command -- no args enters the TUI, args go to the CLI**.
293
+ """
294
+ import sys
295
+
296
+ argv = list(sys.argv[1:] if argv is None else argv)
297
+
298
+ # No args -> TUI
299
+ if not argv:
300
+ return run_tui([])
301
+
302
+ first = argv[0]
303
+
304
+ # Explicit legacy form compatibility
305
+ if first == "tui":
306
+ return run_tui(argv[1:])
307
+ if first == "cli":
308
+ return run_cli(argv[1:])
309
+
310
+ # Any other args (subcommand, or --help/-h/-V/--version, etc.) -> CLI mode
311
+ return run_cli(argv)
312
+
313
+
314
+ __all__ = [
315
+ # Unified error system
316
+ "PPYC_ERR", "PPYCError", "CryptoError", "DecryptionError", "Ed25519Error",
317
+ "ok", "err", "is_ok", "is_err", "raise_ppyc", "OK_TUPLE", "PPYCResult",
318
+ "ALL_ERROR_CODES", "PPYC_ERR_PREFIX",
319
+ # common
320
+ "rand_int", "rand_bytes",
321
+ "MASK32", "MASK64", "MASK128", "POLY1305_P", "GHASH_R", "R_CONST",
322
+ # hash
323
+ "sha256", "sha512", "blake2b",
324
+ # kdf
325
+ "hmac_sha256", "hmac_sha512", "pbkdf2_hmac",
326
+ "hkdf", "hkdf_extract", "hkdf_expand", "scrypt", "argon2id",
327
+ # aes
328
+ "AES",
329
+ # chacha
330
+ "poly1305_mac",
331
+ "chacha20poly1305_encrypt", "chacha20poly1305_decrypt",
332
+ "xchacha20poly1305_encrypt", "xchacha20poly1305_decrypt",
333
+ # x25519
334
+ "x25519", "x25519_base", "x25519_shared", "x25519_generate_keypair",
335
+ # rsa
336
+ "RSAPublicKey", "RSAPrivateKey", "rsa_keygen",
337
+ "rsa_oaep_encrypt", "rsa_oaep_decrypt", "rsa_pss_sign", "rsa_pss_verify",
338
+ # der
339
+ "private_key_to_pkcs1_der", "public_key_to_pkcs1_der",
340
+ "private_key_to_pkcs8_der", "public_key_to_spki_der",
341
+ "private_key_to_pem", "public_key_to_pem", "parse_private_pem",
342
+ # Entry points
343
+ "run_tui", "run_cli", "main",
344
+ # meta
345
+ "__version__", "__author__", "__license__",
346
+ ]
347
+
348
+ # v1.1 algorithms (added to __all__ when present)
349
+ if _HAS_SHA3:
350
+ __all__ += ["sha3_224", "sha3_256", "sha3_384", "sha3_512",
351
+ "shake128", "shake256", "hmac_sha3_256", "hmac_sha3_512",
352
+ "sha3_batch"]
353
+ if _HAS_ED25519:
354
+ __all__ += ["ed25519_keygen", "ed25519_publickey",
355
+ "ed25519_sign", "ed25519_verify"]
356
+ if _HAS_GCM_SIV:
357
+ __all__ += ["aes128_gcm_siv_encrypt", "aes128_gcm_siv_decrypt",
358
+ "aes256_gcm_siv_encrypt", "aes256_gcm_siv_decrypt",
359
+ "aes_gcm_siv_encrypt", "aes_gcm_siv_decrypt",
360
+ "set_cache_enabled", "cache_enabled", "clear_caches"]
361
+
362
+ # v3.2.0 module exports
363
+ if _HAS_KDF2:
364
+ __all__ += ["pbkdf2", "argon2id_hash", "argon2id_verify",
365
+ "argon2i_hash", "argon2d_hash", "argon2id_hash_encoded",
366
+ "scrypt_simple"]
367
+ if _HAS_ENCODING:
368
+ __all__ += ["b64encode", "b64decode", "b64encode_urlsafe", "b64decode_urlsafe",
369
+ "b64encode_nopad", "b64decode_nopad",
370
+ "b32encode", "b32decode", "b32encode_hex", "b32decode_hex",
371
+ "hex_encode", "hex_decode", "hex_encode_sep", "hex_decode_sep",
372
+ "b58encode", "b58decode"]
373
+ if _HAS_RAND:
374
+ __all__ += ["random_bytes", "random_int", "random_below", "random_bit",
375
+ "random_bits", "token_bytes", "token_hex", "token_urlsafe",
376
+ "random_string", "random_password", "random_uuid4",
377
+ "random_choice", "random_sample"]
378
+
379
+ # Export all error code constants (PPYC_ERR_xxx) so users can reference them directly
380
+ # Note: the constant names must actually be imported into this namespace for "from purepycrypto import PPYC_ERR_xxx" to work
381
+ from . import _ppyc_error as _ppyc_error_mod
382
+ for _name in dir(_ppyc_error_mod):
383
+ if _name.startswith("PPYC_ERR_") and _name != "PPYC_ERR_PREFIX":
384
+ globals()[_name] = getattr(_ppyc_error_mod, _name)
385
+ if _name not in __all__:
386
+ __all__.append(_name)
387
+ del _name
388
+
389
+ __version_tuple__ = tuple(int(x) for x in __version__.split(".")[:3])
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ """``python -m purepycrypto`` entry point (behaves the same as the console script ``purepycrypto``).
3
+
4
+ Usage
5
+ -----
6
+ python -m purepycrypto # no arguments -> interactive TUI
7
+ python -m purepycrypto hash --algo sha256 --text abc --hex # with arguments -> CLI
8
+ python -m purepycrypto --help # help for the argument-based CLI
9
+
10
+ After installation you can use the same-named command (located in the Python Scripts directory):
11
+
12
+ purepycrypto # TUI
13
+ purepycrypto hash --text abc --hex # CLI
14
+ """
15
+ import sys
16
+
17
+ from . import main
18
+
19
+ if __name__ == "__main__":
20
+ sys.exit(main() or 0)