transcrypto 1.1.2__py3-none-any.whl → 1.3.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.
- transcrypto/aes.py +4 -3
- transcrypto/base.py +84 -30
- transcrypto/dsa.py +225 -48
- transcrypto/elgamal.py +237 -40
- transcrypto/modmath.py +487 -40
- transcrypto/rsa.py +220 -36
- transcrypto/sss.py +160 -23
- transcrypto/transcrypto.py +429 -191
- {transcrypto-1.1.2.dist-info → transcrypto-1.3.0.dist-info}/METADATA +732 -427
- transcrypto-1.3.0.dist-info/RECORD +15 -0
- transcrypto-1.1.2.dist-info/RECORD +0 -15
- {transcrypto-1.1.2.dist-info → transcrypto-1.3.0.dist-info}/WHEEL +0 -0
- {transcrypto-1.1.2.dist-info → transcrypto-1.3.0.dist-info}/licenses/LICENSE +0 -0
- {transcrypto-1.1.2.dist-info → transcrypto-1.3.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: transcrypto
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: Basic crypto primitives, not intended for actual use, but as a companion to --Criptografia, Métodos e Algoritmos--
|
|
5
5
|
Author-email: Daniel Balparda <balparda@github.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -61,69 +61,78 @@ Started in July/2025, by Daniel Balparda. Since version 1.0.2 it is PyPI package
|
|
|
61
61
|
- [`aes ecb decrypt`](#aes-ecb-decrypt)
|
|
62
62
|
- [`rsa`](#rsa)
|
|
63
63
|
- [`rsa new`](#rsa-new)
|
|
64
|
+
- [`rsa rawencrypt`](#rsa-rawencrypt)
|
|
64
65
|
- [`rsa encrypt`](#rsa-encrypt)
|
|
66
|
+
- [`rsa rawdecrypt`](#rsa-rawdecrypt)
|
|
65
67
|
- [`rsa decrypt`](#rsa-decrypt)
|
|
68
|
+
- [`rsa rawsign`](#rsa-rawsign)
|
|
66
69
|
- [`rsa sign`](#rsa-sign)
|
|
70
|
+
- [`rsa rawverify`](#rsa-rawverify)
|
|
67
71
|
- [`rsa verify`](#rsa-verify)
|
|
68
72
|
- [`elgamal`](#elgamal)
|
|
69
73
|
- [`elgamal shared`](#elgamal-shared)
|
|
70
74
|
- [`elgamal new`](#elgamal-new)
|
|
75
|
+
- [`elgamal rawencrypt`](#elgamal-rawencrypt)
|
|
71
76
|
- [`elgamal encrypt`](#elgamal-encrypt)
|
|
77
|
+
- [`elgamal rawdecrypt`](#elgamal-rawdecrypt)
|
|
72
78
|
- [`elgamal decrypt`](#elgamal-decrypt)
|
|
79
|
+
- [`elgamal rawsign`](#elgamal-rawsign)
|
|
73
80
|
- [`elgamal sign`](#elgamal-sign)
|
|
81
|
+
- [`elgamal rawverify`](#elgamal-rawverify)
|
|
74
82
|
- [`elgamal verify`](#elgamal-verify)
|
|
75
83
|
- [`dsa`](#dsa)
|
|
76
84
|
- [`dsa shared`](#dsa-shared)
|
|
77
85
|
- [`dsa new`](#dsa-new)
|
|
86
|
+
- [`dsa rawsign`](#dsa-rawsign)
|
|
78
87
|
- [`dsa sign`](#dsa-sign)
|
|
88
|
+
- [`dsa rawverify`](#dsa-rawverify)
|
|
79
89
|
- [`dsa verify`](#dsa-verify)
|
|
80
90
|
- [`bid`](#bid)
|
|
81
91
|
- [`bid new`](#bid-new)
|
|
82
92
|
- [`bid verify`](#bid-verify)
|
|
83
93
|
- [`sss`](#sss)
|
|
84
94
|
- [`sss new`](#sss-new)
|
|
95
|
+
- [`sss rawshares`](#sss-rawshares)
|
|
85
96
|
- [`sss shares`](#sss-shares)
|
|
97
|
+
- [`sss rawrecover`](#sss-rawrecover)
|
|
86
98
|
- [`sss recover`](#sss-recover)
|
|
87
|
-
- [`sss
|
|
99
|
+
- [`sss rawverify`](#sss-rawverify)
|
|
88
100
|
- [`doc`](#doc)
|
|
89
101
|
- [`doc md`](#doc-md)
|
|
90
102
|
- [Base Library](#base-library)
|
|
91
103
|
- [Humanized Sizes (IEC binary)](#humanized-sizes-iec-binary)
|
|
92
104
|
- [Humanized Decimal Quantities (SI)](#humanized-decimal-quantities-si)
|
|
93
105
|
- [Humanized Durations](#humanized-durations)
|
|
106
|
+
- [Execution Timing](#execution-timing)
|
|
107
|
+
- [Context manager](#context-manager)
|
|
108
|
+
- [Decorator](#decorator)
|
|
109
|
+
- [Manual use](#manual-use)
|
|
110
|
+
- [Key points](#key-points)
|
|
111
|
+
- [Serialization Pipeline](#serialization-pipeline)
|
|
112
|
+
- [Serialize](#serialize)
|
|
113
|
+
- [DeSerialize](#deserialize)
|
|
94
114
|
- [Cryptographically Secure Randomness](#cryptographically-secure-randomness)
|
|
95
115
|
- [Fixed-size random integers](#fixed-size-random-integers)
|
|
96
116
|
- [Uniform random integers in a range](#uniform-random-integers-in-a-range)
|
|
97
117
|
- [In-place secure shuffle](#in-place-secure-shuffle)
|
|
98
118
|
- [Random byte strings](#random-byte-strings)
|
|
99
119
|
- [Computing the Greatest Common Divisor](#computing-the-greatest-common-divisor)
|
|
120
|
+
- [Fast Modular Arithmetic](#fast-modular-arithmetic)
|
|
121
|
+
- [Chinese Remainder Theorem (CRT) – Pair](#chinese-remainder-theorem-crt--pair)
|
|
122
|
+
- [Modular Polynomials \& Lagrange Interpolation](#modular-polynomials--lagrange-interpolation)
|
|
123
|
+
- [Primality testing \& Prime generators, Mersenne primes](#primality-testing--prime-generators-mersenne-primes)
|
|
100
124
|
- [Cryptographic Hashing](#cryptographic-hashing)
|
|
101
125
|
- [SHA-256 hashing](#sha-256-hashing)
|
|
102
126
|
- [SHA-512 hashing](#sha-512-hashing)
|
|
103
127
|
- [File hashing](#file-hashing)
|
|
104
|
-
- [Execution Timing](#execution-timing)
|
|
105
|
-
- [Context manager](#context-manager)
|
|
106
|
-
- [Decorator](#decorator)
|
|
107
|
-
- [Manual use](#manual-use)
|
|
108
|
-
- [Key points](#key-points)
|
|
109
128
|
- [Symmetric Encryption Interface](#symmetric-encryption-interface)
|
|
110
|
-
- [Serialization Pipeline](#serialization-pipeline)
|
|
111
|
-
- [Serialize](#serialize)
|
|
112
|
-
- [DeSerialize](#deserialize)
|
|
113
129
|
- [Crypto Objects General Properties (`CryptoKey`)](#crypto-objects-general-properties-cryptokey)
|
|
114
130
|
- [AES-256 Symmetric Encryption](#aes-256-symmetric-encryption)
|
|
115
131
|
- [Key creation](#key-creation)
|
|
116
132
|
- [AES-256 + GCM (default)](#aes-256--gcm-default)
|
|
117
133
|
- [AES-256 + ECB (unsafe, fixed block only)](#aes-256--ecb-unsafe-fixed-block-only)
|
|
118
|
-
- [Fast Modular Arithmetic](#fast-modular-arithmetic)
|
|
119
|
-
- [Chinese Remainder Theorem (CRT) – Pair](#chinese-remainder-theorem-crt--pair)
|
|
120
|
-
- [Modular Polynomials \& Lagrange Interpolation](#modular-polynomials--lagrange-interpolation)
|
|
121
|
-
- [Primality testing \& Prime generators, Mersenne primes](#primality-testing--prime-generators-mersenne-primes)
|
|
122
134
|
- [RSA (Rivest-Shamir-Adleman) Public Cryptography](#rsa-rivest-shamir-adleman-public-cryptography)
|
|
123
135
|
- [El-Gamal Public-Key Cryptography](#el-gamal-public-key-cryptography)
|
|
124
|
-
- [Shared Public Key](#shared-public-key)
|
|
125
|
-
- [Public Key](#public-key)
|
|
126
|
-
- [Private Key](#private-key)
|
|
127
136
|
- [DSA (Digital Signature Algorithm)](#dsa-digital-signature-algorithm)
|
|
128
137
|
- [Security notes](#security-notes)
|
|
129
138
|
- [Advanced: custom primes generator](#advanced-custom-primes-generator)
|
|
@@ -144,13 +153,13 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|
|
144
153
|
|
|
145
154
|
## Design assumptions / Disclaimers
|
|
146
155
|
|
|
147
|
-
- The library is built to have reference, reliable, simple implementations of math and crypto primitives.
|
|
156
|
+
- The library is built to have reference, reliable, simple implementations of math and crypto primitives (e.g. `RawEncrypt()`/`RawSign()` and friends plus all the low-level primality and modular arithmetic). The issue is not that the library is unsafe, it is that the library is full of places that allow you to shoot yourself in the foot if you don't know what you are doing.
|
|
157
|
+
- The library also has advanced top-level methods that are cryptographically safe and might be used in real-world scenarios (e.g. `Encrypt()`/`Sign()` and friends).
|
|
148
158
|
- All library methods' `int` are tailored to be efficient with arbitrarily large integers.
|
|
149
|
-
- Everything **should work**, as the library is **extensively tested**, *but not necessarily the most efficient or safe for real-world cryptographic use.* For real-world crypto
|
|
150
|
-
- *All operations in this library may be vulnerable to timing attacks.*
|
|
151
|
-
- There is some logging and error messages that were written to be clear but in real-life security applications could leak private secrets. Again, this library is not build to be crypto safe. It was built as a simple tested reference implementation.
|
|
159
|
+
- Everything **should work**, as the library is **extensively tested**, *but not necessarily the most efficient or safe for real-world cryptographic use.* For real-world crypto you might consider *other optimized/safe libraries* that were built to be resistant to malicious attacks.
|
|
160
|
+
- *All operations in this library may be vulnerable to timing attacks.* This may be a problem to your use-case or not depending on the situation.
|
|
152
161
|
|
|
153
|
-
|
|
162
|
+
All that being said, extreme care was taken that this is a good library with a solid safe implementation. *Have fun!*
|
|
154
163
|
|
|
155
164
|
## Install
|
|
156
165
|
|
|
@@ -188,7 +197,7 @@ poetry run transcrypto <command> [sub-command] [options...]
|
|
|
188
197
|
|---|---|
|
|
189
198
|
| `-v, --verbose` | Increase verbosity (use -v/-vv/-vvv/-vvvv for ERROR/WARN/INFO/DEBUG) |
|
|
190
199
|
| `--hex` | Treat inputs as hex string (default) |
|
|
191
|
-
| `--b64` | Treat inputs as base64url |
|
|
200
|
+
| `--b64` | Treat inputs as base64url; sometimes base64 will start with "-" and that can conflict with flags, so use "--" before positional args if needed |
|
|
192
201
|
| `--bin` | Treat inputs as binary (bytes) |
|
|
193
202
|
| `--out-hex` | Outputs as hex (default) |
|
|
194
203
|
| `--out-b64` | Outputs as base64url |
|
|
@@ -207,11 +216,11 @@ poetry run transcrypto <command> [sub-command] [options...]
|
|
|
207
216
|
- **`mod`** — `poetry run transcrypto mod [-h] {inv,div,exp,poly,lagrange,crt} ...`
|
|
208
217
|
- **`hash`** — `poetry run transcrypto hash [-h] {sha256,sha512,file} ...`
|
|
209
218
|
- **`aes`** — `poetry run transcrypto aes [-h] {key,encrypt,decrypt,ecb} ...`
|
|
210
|
-
- **`rsa`** — `poetry run transcrypto rsa [-h] {new,encrypt,decrypt,sign,verify} ...`
|
|
211
|
-
- **`elgamal`** — `poetry run transcrypto elgamal [-h]
|
|
212
|
-
- **`dsa`** — `poetry run transcrypto dsa [-h] {shared,new,sign,verify} ...`
|
|
219
|
+
- **`rsa`** — `poetry run transcrypto rsa [-h] {new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...`
|
|
220
|
+
- **`elgamal`** — `poetry run transcrypto elgamal [-h] {shared,new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...`
|
|
221
|
+
- **`dsa`** — `poetry run transcrypto dsa [-h] {shared,new,rawsign,sign,rawverify,verify} ...`
|
|
213
222
|
- **`bid`** — `poetry run transcrypto bid [-h] {new,verify} ...`
|
|
214
|
-
- **`sss`** — `poetry run transcrypto sss [-h] {new,shares,recover,
|
|
223
|
+
- **`sss`** — `poetry run transcrypto sss [-h] {new,rawshares,shares,rawrecover,recover,rawverify} ...`
|
|
215
224
|
- **`doc`** — `poetry run transcrypto doc [-h] {md} ...`
|
|
216
225
|
|
|
217
226
|
```bash
|
|
@@ -240,36 +249,49 @@ Examples:
|
|
|
240
249
|
|
|
241
250
|
# --- Hashing ---
|
|
242
251
|
poetry run transcrypto hash sha256 xyz
|
|
243
|
-
poetry run transcrypto --b64 hash sha512 eHl6
|
|
252
|
+
poetry run transcrypto --b64 hash sha512 -- eHl6
|
|
244
253
|
poetry run transcrypto hash file /etc/passwd --digest sha512
|
|
245
254
|
|
|
246
255
|
# --- AES ---
|
|
247
256
|
poetry run transcrypto --out-b64 aes key "correct horse battery staple"
|
|
248
|
-
poetry run transcrypto --b64 --out-b64 aes encrypt -k "<b64key>" "secret"
|
|
249
|
-
poetry run transcrypto --b64 --out-b64 aes decrypt -k "<b64key>" "<ciphertext>"
|
|
257
|
+
poetry run transcrypto --b64 --out-b64 aes encrypt -k "<b64key>" -- "secret"
|
|
258
|
+
poetry run transcrypto --b64 --out-b64 aes decrypt -k "<b64key>" -- "<ciphertext>"
|
|
250
259
|
poetry run transcrypto aes ecb -k "<b64key>" encrypt "<128bithexblock>"
|
|
251
260
|
poetry run transcrypto aes ecb -k "<b64key>" decrypt "<128bithexblock>"
|
|
252
261
|
|
|
253
262
|
# --- RSA ---
|
|
254
263
|
poetry run transcrypto -p rsa-key rsa new --bits 2048
|
|
255
|
-
poetry run transcrypto -p rsa-key.pub rsa
|
|
256
|
-
poetry run transcrypto -p rsa-key.priv rsa
|
|
257
|
-
poetry run transcrypto -p rsa-key.priv rsa
|
|
258
|
-
poetry run transcrypto -p rsa-key.pub rsa
|
|
264
|
+
poetry run transcrypto -p rsa-key.pub rsa rawencrypt <plaintext>
|
|
265
|
+
poetry run transcrypto -p rsa-key.priv rsa rawdecrypt <ciphertext>
|
|
266
|
+
poetry run transcrypto -p rsa-key.priv rsa rawsign <message>
|
|
267
|
+
poetry run transcrypto -p rsa-key.pub rsa rawverify <message> <signature>
|
|
268
|
+
|
|
269
|
+
poetry run transcrypto --bin --out-b64 -p rsa-key.pub rsa encrypt -a <aad> <plaintext>
|
|
270
|
+
poetry run transcrypto --b64 --out-bin -p rsa-key.priv rsa decrypt -a <aad> -- <ciphertext>
|
|
271
|
+
poetry run transcrypto --bin --out-b64 -p rsa-key.priv rsa sign <message>
|
|
272
|
+
poetry run transcrypto --b64 -p rsa-key.pub rsa verify -- <message> <signature>
|
|
259
273
|
|
|
260
274
|
# --- ElGamal ---
|
|
261
275
|
poetry run transcrypto -p eg-key elgamal shared --bits 2048
|
|
262
276
|
poetry run transcrypto -p eg-key elgamal new
|
|
263
|
-
poetry run transcrypto -p eg-key.pub elgamal
|
|
264
|
-
poetry run transcrypto -p eg-key.priv elgamal
|
|
265
|
-
poetry run transcrypto -p eg-key.priv elgamal
|
|
266
|
-
poetry run transcrypto-p eg-key.pub elgamal
|
|
277
|
+
poetry run transcrypto -p eg-key.pub elgamal rawencrypt <plaintext>
|
|
278
|
+
poetry run transcrypto -p eg-key.priv elgamal rawdecrypt <c1:c2>
|
|
279
|
+
poetry run transcrypto -p eg-key.priv elgamal rawsign <message>
|
|
280
|
+
poetry run transcrypto-p eg-key.pub elgamal rawverify <message> <s1:s2>
|
|
281
|
+
|
|
282
|
+
poetry run transcrypto --bin --out-b64 -p eg-key.pub elgamal encrypt <plaintext>
|
|
283
|
+
poetry run transcrypto --b64 --out-bin -p eg-key.priv elgamal decrypt -- <ciphertext>
|
|
284
|
+
poetry run transcrypto --bin --out-b64 -p eg-key.priv elgamal sign <message>
|
|
285
|
+
poetry run transcrypto --b64 -p eg-key.pub elgamal verify -- <message> <signature>
|
|
267
286
|
|
|
268
287
|
# --- DSA ---
|
|
269
288
|
poetry run transcrypto -p dsa-key dsa shared --p-bits 2048 --q-bits 256
|
|
270
289
|
poetry run transcrypto -p dsa-key dsa new
|
|
271
|
-
poetry run transcrypto -p dsa-key.priv dsa
|
|
272
|
-
poetry run transcrypto -p dsa-key.pub dsa
|
|
290
|
+
poetry run transcrypto -p dsa-key.priv dsa rawsign <message>
|
|
291
|
+
poetry run transcrypto -p dsa-key.pub dsa rawverify <message> <s1:s2>
|
|
292
|
+
|
|
293
|
+
poetry run transcrypto --bin --out-b64 -p dsa-key.priv dsa sign <message>
|
|
294
|
+
poetry run transcrypto --b64 -p dsa-key.pub dsa verify -- <message> <signature>
|
|
273
295
|
|
|
274
296
|
# --- Public Bid ---
|
|
275
297
|
poetry run transcrypto --bin bid new "tomorrow it will rain"
|
|
@@ -277,9 +299,11 @@ Examples:
|
|
|
277
299
|
|
|
278
300
|
# --- Shamir Secret Sharing (SSS) ---
|
|
279
301
|
poetry run transcrypto -p sss-key sss new 3 --bits 1024
|
|
280
|
-
poetry run transcrypto -p sss-key sss
|
|
281
|
-
poetry run transcrypto -p sss-key sss
|
|
282
|
-
poetry run transcrypto -p sss-key sss
|
|
302
|
+
poetry run transcrypto -p sss-key sss rawshares <secret> <n>
|
|
303
|
+
poetry run transcrypto -p sss-key sss rawrecover
|
|
304
|
+
poetry run transcrypto -p sss-key sss rawverify <secret> poetry run transcrypto --bin -p sss-key sss shares <secret> <n>
|
|
305
|
+
poetry run transcrypto --out-bin -p sss-key sss recover
|
|
306
|
+
|
|
283
307
|
```
|
|
284
308
|
|
|
285
309
|
---
|
|
@@ -674,7 +698,7 @@ poetry run transcrypto hash sha256 [-h] data
|
|
|
674
698
|
```bash
|
|
675
699
|
$ poetry run transcrypto --bin hash sha256 xyz
|
|
676
700
|
3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
|
|
677
|
-
$ poetry run transcrypto --b64 hash sha256 eHl6 # "xyz" in base-64
|
|
701
|
+
$ poetry run transcrypto --b64 hash sha256 -- eHl6 # "xyz" in base-64
|
|
678
702
|
3608bca1e44ea6c4d268eb6db02260269892c0b42b86bbf1e77a6fa16c3c9282
|
|
679
703
|
```
|
|
680
704
|
|
|
@@ -695,7 +719,7 @@ poetry run transcrypto hash sha512 [-h] data
|
|
|
695
719
|
```bash
|
|
696
720
|
$ poetry run transcrypto --bin hash sha512 xyz
|
|
697
721
|
4a3ed8147e37876adc8f76328e5abcc1b470e6acfc18efea0135f983604953a58e183c1a6086e91ba3e821d926f5fdeb37761c7ca0328a963f5e92870675b728
|
|
698
|
-
$ poetry run transcrypto --b64 hash sha512 eHl6 # "xyz" in base-64
|
|
722
|
+
$ poetry run transcrypto --b64 hash sha512 -- eHl6 # "xyz" in base-64
|
|
699
723
|
4a3ed8147e37876adc8f76328e5abcc1b470e6acfc18efea0135f983604953a58e183c1a6086e91ba3e821d926f5fdeb37761c7ca0328a963f5e92870675b728
|
|
700
724
|
```
|
|
701
725
|
|
|
@@ -767,9 +791,9 @@ poetry run transcrypto aes encrypt [-h] [-k KEY] [-a AAD] plaintext
|
|
|
767
791
|
**Example:**
|
|
768
792
|
|
|
769
793
|
```bash
|
|
770
|
-
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= AAAAAAB4eXo=
|
|
794
|
+
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -- AAAAAAB4eXo=
|
|
771
795
|
F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
|
|
772
|
-
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 AAAAAAB4eXo=
|
|
796
|
+
$ poetry run transcrypto --b64 --out-b64 aes encrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 -- AAAAAAB4eXo=
|
|
773
797
|
xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
|
|
774
798
|
```
|
|
775
799
|
|
|
@@ -790,9 +814,9 @@ poetry run transcrypto aes decrypt [-h] [-k KEY] [-a AAD] ciphertext
|
|
|
790
814
|
**Example:**
|
|
791
815
|
|
|
792
816
|
```bash
|
|
793
|
-
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
|
|
817
|
+
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -- F2_ZLrUw5Y8oDnbTP5t5xCUWX8WtVILLD0teyUi_37_4KHeV-YowVA==
|
|
794
818
|
AAAAAAB4eXo=
|
|
795
|
-
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
|
|
819
|
+
$ poetry run transcrypto --b64 --out-b64 aes decrypt -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_eY0es= -a eHl6 -- xOlAHPUPpeyZHId-f3VQ_QKKMxjIW0_FBo9WOfIBrzjn0VkVV6xTRA==
|
|
796
820
|
AAAAAAB4eXo=
|
|
797
821
|
```
|
|
798
822
|
|
|
@@ -850,10 +874,11 @@ $ poetry run transcrypto --b64 aes ecb -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_
|
|
|
850
874
|
|
|
851
875
|
### `rsa`
|
|
852
876
|
|
|
853
|
-
|
|
877
|
+
RSA (Rivest-Shamir-Adleman) asymmetric cryptography. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
854
878
|
|
|
855
879
|
```bash
|
|
856
|
-
poetry run transcrypto rsa [-h]
|
|
880
|
+
poetry run transcrypto rsa [-h]
|
|
881
|
+
{new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...
|
|
857
882
|
```
|
|
858
883
|
|
|
859
884
|
#### `rsa new`
|
|
@@ -875,12 +900,12 @@ $ poetry run transcrypto -p rsa-key rsa new --bits 64 # NEVER use such a small
|
|
|
875
900
|
RSA private/public keys saved to 'rsa-key.priv/.pub'
|
|
876
901
|
```
|
|
877
902
|
|
|
878
|
-
#### `rsa
|
|
903
|
+
#### `rsa rawencrypt`
|
|
879
904
|
|
|
880
|
-
|
|
905
|
+
Raw encrypt *integer* `message` with public key (BEWARE: no OAEP/PSS padding or validation).
|
|
881
906
|
|
|
882
907
|
```bash
|
|
883
|
-
poetry run transcrypto rsa
|
|
908
|
+
poetry run transcrypto rsa rawencrypt [-h] message
|
|
884
909
|
```
|
|
885
910
|
|
|
886
911
|
| Option/Arg | Description |
|
|
@@ -890,16 +915,36 @@ poetry run transcrypto rsa encrypt [-h] message
|
|
|
890
915
|
**Example:**
|
|
891
916
|
|
|
892
917
|
```bash
|
|
893
|
-
$ poetry run transcrypto -p rsa-key.pub rsa
|
|
918
|
+
$ poetry run transcrypto -p rsa-key.pub rsa rawencrypt 999
|
|
894
919
|
6354905961171348600
|
|
895
920
|
```
|
|
896
921
|
|
|
897
|
-
#### `rsa
|
|
922
|
+
#### `rsa encrypt`
|
|
923
|
+
|
|
924
|
+
Encrypt `message` with public key.
|
|
925
|
+
|
|
926
|
+
```bash
|
|
927
|
+
poetry run transcrypto rsa encrypt [-h] [-a AAD] plaintext
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
| Option/Arg | Description |
|
|
931
|
+
|---|---|
|
|
932
|
+
| `plaintext` | Message to encrypt [type: str] |
|
|
933
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
934
|
+
|
|
935
|
+
**Example:**
|
|
936
|
+
|
|
937
|
+
```bash
|
|
938
|
+
$ poetry run transcrypto --bin --out-b64 -p rsa-key.pub rsa encrypt "abcde" -a "xyz"
|
|
939
|
+
AO6knI6xwq6TGR…Qy22jiFhXi1eQ==
|
|
940
|
+
```
|
|
898
941
|
|
|
899
|
-
|
|
942
|
+
#### `rsa rawdecrypt`
|
|
943
|
+
|
|
944
|
+
Raw decrypt *integer* `ciphertext` with private key (BEWARE: no OAEP/PSS padding or validation).
|
|
900
945
|
|
|
901
946
|
```bash
|
|
902
|
-
poetry run transcrypto rsa
|
|
947
|
+
poetry run transcrypto rsa rawdecrypt [-h] ciphertext
|
|
903
948
|
```
|
|
904
949
|
|
|
905
950
|
| Option/Arg | Description |
|
|
@@ -909,16 +954,36 @@ poetry run transcrypto rsa decrypt [-h] ciphertext
|
|
|
909
954
|
**Example:**
|
|
910
955
|
|
|
911
956
|
```bash
|
|
912
|
-
$ poetry run transcrypto -p rsa-key.priv rsa
|
|
957
|
+
$ poetry run transcrypto -p rsa-key.priv rsa rawdecrypt 6354905961171348600
|
|
913
958
|
999
|
|
914
959
|
```
|
|
915
960
|
|
|
916
|
-
#### `rsa
|
|
961
|
+
#### `rsa decrypt`
|
|
962
|
+
|
|
963
|
+
Decrypt `ciphertext` with private key.
|
|
964
|
+
|
|
965
|
+
```bash
|
|
966
|
+
poetry run transcrypto rsa decrypt [-h] [-a AAD] ciphertext
|
|
967
|
+
```
|
|
968
|
+
|
|
969
|
+
| Option/Arg | Description |
|
|
970
|
+
|---|---|
|
|
971
|
+
| `ciphertext` | Ciphertext to decrypt [type: str] |
|
|
972
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
|
|
973
|
+
|
|
974
|
+
**Example:**
|
|
975
|
+
|
|
976
|
+
```bash
|
|
977
|
+
$ poetry run transcrypto --b64 --out-bin -p rsa-key.priv rsa decrypt -a eHl6 -- AO6knI6xwq6TGR…Qy22jiFhXi1eQ==
|
|
978
|
+
abcde
|
|
979
|
+
```
|
|
917
980
|
|
|
918
|
-
|
|
981
|
+
#### `rsa rawsign`
|
|
982
|
+
|
|
983
|
+
Raw sign *integer* `message` with private key (BEWARE: no OAEP/PSS padding or validation).
|
|
919
984
|
|
|
920
985
|
```bash
|
|
921
|
-
poetry run transcrypto rsa
|
|
986
|
+
poetry run transcrypto rsa rawsign [-h] message
|
|
922
987
|
```
|
|
923
988
|
|
|
924
989
|
| Option/Arg | Description |
|
|
@@ -928,16 +993,36 @@ poetry run transcrypto rsa sign [-h] message
|
|
|
928
993
|
**Example:**
|
|
929
994
|
|
|
930
995
|
```bash
|
|
931
|
-
$ poetry run transcrypto -p rsa-key.priv rsa
|
|
996
|
+
$ poetry run transcrypto -p rsa-key.priv rsa rawsign 999
|
|
932
997
|
7632909108672871784
|
|
933
998
|
```
|
|
934
999
|
|
|
935
|
-
#### `rsa
|
|
1000
|
+
#### `rsa sign`
|
|
1001
|
+
|
|
1002
|
+
Sign `message` with private key.
|
|
1003
|
+
|
|
1004
|
+
```bash
|
|
1005
|
+
poetry run transcrypto rsa sign [-h] [-a AAD] message
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
| Option/Arg | Description |
|
|
1009
|
+
|---|---|
|
|
1010
|
+
| `message` | Message to sign [type: str] |
|
|
1011
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1012
|
+
|
|
1013
|
+
**Example:**
|
|
1014
|
+
|
|
1015
|
+
```bash
|
|
1016
|
+
$ poetry run transcrypto --bin --out-b64 -p rsa-key.priv rsa sign "xyz"
|
|
1017
|
+
91TS7gC6LORiL…6RD23Aejsfxlw==
|
|
1018
|
+
```
|
|
936
1019
|
|
|
937
|
-
|
|
1020
|
+
#### `rsa rawverify`
|
|
1021
|
+
|
|
1022
|
+
Raw verify *integer* `signature` for *integer* `message` with public key (BEWARE: no OAEP/PSS padding or validation).
|
|
938
1023
|
|
|
939
1024
|
```bash
|
|
940
|
-
poetry run transcrypto rsa
|
|
1025
|
+
poetry run transcrypto rsa rawverify [-h] message signature
|
|
941
1026
|
```
|
|
942
1027
|
|
|
943
1028
|
| Option/Arg | Description |
|
|
@@ -948,9 +1033,32 @@ poetry run transcrypto rsa verify [-h] message signature
|
|
|
948
1033
|
**Example:**
|
|
949
1034
|
|
|
950
1035
|
```bash
|
|
951
|
-
$ poetry run transcrypto -p rsa-key.pub rsa
|
|
1036
|
+
$ poetry run transcrypto -p rsa-key.pub rsa rawverify 999 7632909108672871784
|
|
1037
|
+
RSA signature: OK
|
|
1038
|
+
$ poetry run transcrypto -p rsa-key.pub rsa rawverify 999 7632909108672871785
|
|
1039
|
+
RSA signature: INVALID
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
#### `rsa verify`
|
|
1043
|
+
|
|
1044
|
+
Verify `signature` for `message` with public key.
|
|
1045
|
+
|
|
1046
|
+
```bash
|
|
1047
|
+
poetry run transcrypto rsa verify [-h] [-a AAD] message signature
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
| Option/Arg | Description |
|
|
1051
|
+
|---|---|
|
|
1052
|
+
| `message` | Message that was signed earlier [type: str] |
|
|
1053
|
+
| `signature` | Putative signature for `message` [type: str] |
|
|
1054
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during signing) [type: str] |
|
|
1055
|
+
|
|
1056
|
+
**Example:**
|
|
1057
|
+
|
|
1058
|
+
```bash
|
|
1059
|
+
$ poetry run transcrypto --b64 -p rsa-key.pub rsa verify -- eHl6 91TS7gC6LORiL…6RD23Aejsfxlw==
|
|
952
1060
|
RSA signature: OK
|
|
953
|
-
$ poetry run transcrypto -p rsa-key.pub rsa verify
|
|
1061
|
+
$ poetry run transcrypto --b64 -p rsa-key.pub rsa verify -- eLl6 91TS7gC6LORiL…6RD23Aejsfxlw==
|
|
954
1062
|
RSA signature: INVALID
|
|
955
1063
|
```
|
|
956
1064
|
|
|
@@ -958,11 +1066,11 @@ RSA signature: INVALID
|
|
|
958
1066
|
|
|
959
1067
|
### `elgamal`
|
|
960
1068
|
|
|
961
|
-
|
|
1069
|
+
El-Gamal asymmetric cryptography. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
962
1070
|
|
|
963
1071
|
```bash
|
|
964
1072
|
poetry run transcrypto elgamal [-h]
|
|
965
|
-
{shared,new,encrypt,decrypt,sign,verify} ...
|
|
1073
|
+
{shared,new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...
|
|
966
1074
|
```
|
|
967
1075
|
|
|
968
1076
|
#### `elgamal shared`
|
|
@@ -999,12 +1107,12 @@ $ poetry run transcrypto -p eg-key elgamal new
|
|
|
999
1107
|
El-Gamal private/public keys saved to 'eg-key.priv/.pub'
|
|
1000
1108
|
```
|
|
1001
1109
|
|
|
1002
|
-
#### `elgamal
|
|
1110
|
+
#### `elgamal rawencrypt`
|
|
1003
1111
|
|
|
1004
|
-
|
|
1112
|
+
Raw encrypt *integer* `message` with public key (BEWARE: no ECIES-style KEM/DEM padding or validation).
|
|
1005
1113
|
|
|
1006
1114
|
```bash
|
|
1007
|
-
poetry run transcrypto elgamal
|
|
1115
|
+
poetry run transcrypto elgamal rawencrypt [-h] message
|
|
1008
1116
|
```
|
|
1009
1117
|
|
|
1010
1118
|
| Option/Arg | Description |
|
|
@@ -1014,16 +1122,36 @@ poetry run transcrypto elgamal encrypt [-h] message
|
|
|
1014
1122
|
**Example:**
|
|
1015
1123
|
|
|
1016
1124
|
```bash
|
|
1017
|
-
$ poetry run transcrypto -p eg-key.pub elgamal
|
|
1125
|
+
$ poetry run transcrypto -p eg-key.pub elgamal rawencrypt 999
|
|
1018
1126
|
2948854810728206041:15945988196340032688
|
|
1019
1127
|
```
|
|
1020
1128
|
|
|
1021
|
-
#### `elgamal
|
|
1129
|
+
#### `elgamal encrypt`
|
|
1130
|
+
|
|
1131
|
+
Encrypt `message` with public key.
|
|
1132
|
+
|
|
1133
|
+
```bash
|
|
1134
|
+
poetry run transcrypto elgamal encrypt [-h] [-a AAD] plaintext
|
|
1135
|
+
```
|
|
1022
1136
|
|
|
1023
|
-
|
|
1137
|
+
| Option/Arg | Description |
|
|
1138
|
+
|---|---|
|
|
1139
|
+
| `plaintext` | Message to encrypt [type: str] |
|
|
1140
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1141
|
+
|
|
1142
|
+
**Example:**
|
|
1143
|
+
|
|
1144
|
+
```bash
|
|
1145
|
+
$ poetry run transcrypto --bin --out-b64 -p eg-key.pub elgamal encrypt "abcde" -a "xyz"
|
|
1146
|
+
CdFvoQ_IIPFPZLua…kqjhcUTspISxURg==
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
#### `elgamal rawdecrypt`
|
|
1150
|
+
|
|
1151
|
+
Raw decrypt *integer* `ciphertext` with private key (BEWARE: no ECIES-style KEM/DEM padding or validation).
|
|
1024
1152
|
|
|
1025
1153
|
```bash
|
|
1026
|
-
poetry run transcrypto elgamal
|
|
1154
|
+
poetry run transcrypto elgamal rawdecrypt [-h] ciphertext
|
|
1027
1155
|
```
|
|
1028
1156
|
|
|
1029
1157
|
| Option/Arg | Description |
|
|
@@ -1033,16 +1161,36 @@ poetry run transcrypto elgamal decrypt [-h] ciphertext
|
|
|
1033
1161
|
**Example:**
|
|
1034
1162
|
|
|
1035
1163
|
```bash
|
|
1036
|
-
$ poetry run transcrypto -p eg-key.priv elgamal
|
|
1164
|
+
$ poetry run transcrypto -p eg-key.priv elgamal rawdecrypt 2948854810728206041:15945988196340032688
|
|
1037
1165
|
999
|
|
1038
1166
|
```
|
|
1039
1167
|
|
|
1040
|
-
#### `elgamal
|
|
1168
|
+
#### `elgamal decrypt`
|
|
1169
|
+
|
|
1170
|
+
Decrypt `ciphertext` with private key.
|
|
1171
|
+
|
|
1172
|
+
```bash
|
|
1173
|
+
poetry run transcrypto elgamal decrypt [-h] [-a AAD] ciphertext
|
|
1174
|
+
```
|
|
1041
1175
|
|
|
1042
|
-
|
|
1176
|
+
| Option/Arg | Description |
|
|
1177
|
+
|---|---|
|
|
1178
|
+
| `ciphertext` | Ciphertext to decrypt [type: str] |
|
|
1179
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
|
|
1180
|
+
|
|
1181
|
+
**Example:**
|
|
1182
|
+
|
|
1183
|
+
```bash
|
|
1184
|
+
$ poetry run transcrypto --b64 --out-bin -p eg-key.priv elgamal decrypt -a eHl6 -- CdFvoQ_IIPFPZLua…kqjhcUTspISxURg==
|
|
1185
|
+
abcde
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
#### `elgamal rawsign`
|
|
1189
|
+
|
|
1190
|
+
Raw sign *integer* message with private key (BEWARE: no ECIES-style KEM/DEM padding or validation). Output will 2 *integers* in a `s1:s2` format.
|
|
1043
1191
|
|
|
1044
1192
|
```bash
|
|
1045
|
-
poetry run transcrypto elgamal
|
|
1193
|
+
poetry run transcrypto elgamal rawsign [-h] message
|
|
1046
1194
|
```
|
|
1047
1195
|
|
|
1048
1196
|
| Option/Arg | Description |
|
|
@@ -1052,16 +1200,36 @@ poetry run transcrypto elgamal sign [-h] message
|
|
|
1052
1200
|
**Example:**
|
|
1053
1201
|
|
|
1054
1202
|
```bash
|
|
1055
|
-
$ poetry run transcrypto -p eg-key.priv elgamal
|
|
1203
|
+
$ poetry run transcrypto -p eg-key.priv elgamal rawsign 999
|
|
1056
1204
|
4674885853217269088:14532144906178302633
|
|
1057
1205
|
```
|
|
1058
1206
|
|
|
1059
|
-
#### `elgamal
|
|
1207
|
+
#### `elgamal sign`
|
|
1208
|
+
|
|
1209
|
+
Sign message with private key.
|
|
1210
|
+
|
|
1211
|
+
```bash
|
|
1212
|
+
poetry run transcrypto elgamal sign [-h] [-a AAD] message
|
|
1213
|
+
```
|
|
1060
1214
|
|
|
1061
|
-
|
|
1215
|
+
| Option/Arg | Description |
|
|
1216
|
+
|---|---|
|
|
1217
|
+
| `message` | Message to sign [type: str] |
|
|
1218
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1219
|
+
|
|
1220
|
+
**Example:**
|
|
1221
|
+
|
|
1222
|
+
```bash
|
|
1223
|
+
$ poetry run transcrypto --bin --out-b64 -p eg-key.priv elgamal sign "xyz"
|
|
1224
|
+
Xl4hlYK8SHVGw…0fCKJE1XVzA==
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
#### `elgamal rawverify`
|
|
1228
|
+
|
|
1229
|
+
Raw verify *integer* `signature` for *integer* `message` with public key (BEWARE: no ECIES-style KEM/DEM padding or validation).
|
|
1062
1230
|
|
|
1063
1231
|
```bash
|
|
1064
|
-
poetry run transcrypto elgamal
|
|
1232
|
+
poetry run transcrypto elgamal rawverify [-h] message signature
|
|
1065
1233
|
```
|
|
1066
1234
|
|
|
1067
1235
|
| Option/Arg | Description |
|
|
@@ -1072,9 +1240,32 @@ poetry run transcrypto elgamal verify [-h] message signature
|
|
|
1072
1240
|
**Example:**
|
|
1073
1241
|
|
|
1074
1242
|
```bash
|
|
1075
|
-
$ poetry run transcrypto -p eg-key.pub elgamal
|
|
1243
|
+
$ poetry run transcrypto -p eg-key.pub elgamal rawverify 999 4674885853217269088:14532144906178302633
|
|
1244
|
+
El-Gamal signature: OK
|
|
1245
|
+
$ poetry run transcrypto -p eg-key.pub elgamal rawverify 999 4674885853217269088:14532144906178302632
|
|
1246
|
+
El-Gamal signature: INVALID
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
#### `elgamal verify`
|
|
1250
|
+
|
|
1251
|
+
Verify `signature` for `message` with public key.
|
|
1252
|
+
|
|
1253
|
+
```bash
|
|
1254
|
+
poetry run transcrypto elgamal verify [-h] [-a AAD] message signature
|
|
1255
|
+
```
|
|
1256
|
+
|
|
1257
|
+
| Option/Arg | Description |
|
|
1258
|
+
|---|---|
|
|
1259
|
+
| `message` | Message that was signed earlier [type: str] |
|
|
1260
|
+
| `signature` | Putative signature for `message` [type: str] |
|
|
1261
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during signing) [type: str] |
|
|
1262
|
+
|
|
1263
|
+
**Example:**
|
|
1264
|
+
|
|
1265
|
+
```bash
|
|
1266
|
+
$ poetry run transcrypto --b64 -p eg-key.pub elgamal verify -- eHl6 Xl4hlYK8SHVGw…0fCKJE1XVzA==
|
|
1076
1267
|
El-Gamal signature: OK
|
|
1077
|
-
$ poetry run transcrypto -p eg-key.pub elgamal verify
|
|
1268
|
+
$ poetry run transcrypto --b64 -p eg-key.pub elgamal verify -- eLl6 Xl4hlYK8SHVGw…0fCKJE1XVzA==
|
|
1078
1269
|
El-Gamal signature: INVALID
|
|
1079
1270
|
```
|
|
1080
1271
|
|
|
@@ -1082,15 +1273,16 @@ El-Gamal signature: INVALID
|
|
|
1082
1273
|
|
|
1083
1274
|
### `dsa`
|
|
1084
1275
|
|
|
1085
|
-
|
|
1276
|
+
DSA (Digital Signature Algorithm) asymmetric signing/verifying. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
1086
1277
|
|
|
1087
1278
|
```bash
|
|
1088
|
-
poetry run transcrypto dsa [-h]
|
|
1279
|
+
poetry run transcrypto dsa [-h]
|
|
1280
|
+
{shared,new,rawsign,sign,rawverify,verify} ...
|
|
1089
1281
|
```
|
|
1090
1282
|
|
|
1091
1283
|
#### `dsa shared`
|
|
1092
1284
|
|
|
1093
|
-
Generate a shared DSA key with `p-bits`/`q-bits` prime modulus sizes, which is the first step in key generation. `q-bits` should be larger than the secrets that will be protected and `p-bits` should be much larger than `q-bits` (e.g.
|
|
1285
|
+
Generate a shared DSA key with `p-bits`/`q-bits` prime modulus sizes, which is the first step in key generation. `q-bits` should be larger than the secrets that will be protected and `p-bits` should be much larger than `q-bits` (e.g. 4096/544). The shared key can safely be used by any number of users to generate their private/public key pairs (with the `new` command). The shared keys are "public". Requires `-p`/`--key-path` to set the basename for output files.
|
|
1094
1286
|
|
|
1095
1287
|
```bash
|
|
1096
1288
|
poetry run transcrypto dsa shared [-h] [--p-bits P_BITS]
|
|
@@ -1099,8 +1291,8 @@ poetry run transcrypto dsa shared [-h] [--p-bits P_BITS]
|
|
|
1099
1291
|
|
|
1100
1292
|
| Option/Arg | Description |
|
|
1101
1293
|
|---|---|
|
|
1102
|
-
| `--p-bits` | Prime modulus (`p`) size in bits; the default is a safe size [type: int (default:
|
|
1103
|
-
| `--q-bits` | Prime modulus (`q`) size in bits; the default is a safe size ***IFF*** you are protecting symmetric keys or regular hashes [type: int (default:
|
|
1294
|
+
| `--p-bits` | Prime modulus (`p`) size in bits; the default is a safe size [type: int (default: 4096)] |
|
|
1295
|
+
| `--q-bits` | Prime modulus (`q`) size in bits; the default is a safe size ***IFF*** you are protecting symmetric keys or regular hashes [type: int (default: 544)] |
|
|
1104
1296
|
|
|
1105
1297
|
**Example:**
|
|
1106
1298
|
|
|
@@ -1124,12 +1316,12 @@ $ poetry run transcrypto -p dsa-key dsa new
|
|
|
1124
1316
|
DSA private/public keys saved to 'dsa-key.priv/.pub'
|
|
1125
1317
|
```
|
|
1126
1318
|
|
|
1127
|
-
#### `dsa
|
|
1319
|
+
#### `dsa rawsign`
|
|
1128
1320
|
|
|
1129
|
-
|
|
1321
|
+
Raw sign *integer* message with private key (BEWARE: no ECDSA/EdDSA padding or validation). Output will 2 *integers* in a `s1:s2` format.
|
|
1130
1322
|
|
|
1131
1323
|
```bash
|
|
1132
|
-
poetry run transcrypto dsa
|
|
1324
|
+
poetry run transcrypto dsa rawsign [-h] message
|
|
1133
1325
|
```
|
|
1134
1326
|
|
|
1135
1327
|
| Option/Arg | Description |
|
|
@@ -1139,16 +1331,36 @@ poetry run transcrypto dsa sign [-h] message
|
|
|
1139
1331
|
**Example:**
|
|
1140
1332
|
|
|
1141
1333
|
```bash
|
|
1142
|
-
$ poetry run transcrypto -p dsa-key.priv dsa
|
|
1334
|
+
$ poetry run transcrypto -p dsa-key.priv dsa rawsign 999
|
|
1143
1335
|
2395961484:3435572290
|
|
1144
1336
|
```
|
|
1145
1337
|
|
|
1146
|
-
#### `dsa
|
|
1338
|
+
#### `dsa sign`
|
|
1339
|
+
|
|
1340
|
+
Sign message with private key.
|
|
1341
|
+
|
|
1342
|
+
```bash
|
|
1343
|
+
poetry run transcrypto dsa sign [-h] [-a AAD] message
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
| Option/Arg | Description |
|
|
1347
|
+
|---|---|
|
|
1348
|
+
| `message` | Message to sign [type: str] |
|
|
1349
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1350
|
+
|
|
1351
|
+
**Example:**
|
|
1352
|
+
|
|
1353
|
+
```bash
|
|
1354
|
+
$ poetry run transcrypto --bin --out-b64 -p dsa-key.priv dsa sign "xyz"
|
|
1355
|
+
yq8InJVpViXh9…BD4par2XuA=
|
|
1356
|
+
```
|
|
1147
1357
|
|
|
1148
|
-
|
|
1358
|
+
#### `dsa rawverify`
|
|
1359
|
+
|
|
1360
|
+
Raw verify *integer* `signature` for *integer* `message` with public key (BEWARE: no ECDSA/EdDSA padding or validation).
|
|
1149
1361
|
|
|
1150
1362
|
```bash
|
|
1151
|
-
poetry run transcrypto dsa
|
|
1363
|
+
poetry run transcrypto dsa rawverify [-h] message signature
|
|
1152
1364
|
```
|
|
1153
1365
|
|
|
1154
1366
|
| Option/Arg | Description |
|
|
@@ -1159,9 +1371,32 @@ poetry run transcrypto dsa verify [-h] message signature
|
|
|
1159
1371
|
**Example:**
|
|
1160
1372
|
|
|
1161
1373
|
```bash
|
|
1162
|
-
$ poetry run transcrypto -p dsa-key.pub dsa
|
|
1374
|
+
$ poetry run transcrypto -p dsa-key.pub dsa rawverify 999 2395961484:3435572290
|
|
1375
|
+
DSA signature: OK
|
|
1376
|
+
$ poetry run transcrypto -p dsa-key.pub dsa rawverify 999 2395961484:3435572291
|
|
1377
|
+
DSA signature: INVALID
|
|
1378
|
+
```
|
|
1379
|
+
|
|
1380
|
+
#### `dsa verify`
|
|
1381
|
+
|
|
1382
|
+
Verify `signature` for `message` with public key.
|
|
1383
|
+
|
|
1384
|
+
```bash
|
|
1385
|
+
poetry run transcrypto dsa verify [-h] [-a AAD] message signature
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
| Option/Arg | Description |
|
|
1389
|
+
|---|---|
|
|
1390
|
+
| `message` | Message that was signed earlier [type: str] |
|
|
1391
|
+
| `signature` | Putative signature for `message` [type: str] |
|
|
1392
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during signing) [type: str] |
|
|
1393
|
+
|
|
1394
|
+
**Example:**
|
|
1395
|
+
|
|
1396
|
+
```bash
|
|
1397
|
+
$ poetry run transcrypto --b64 -p dsa-key.pub dsa verify -- eHl6 yq8InJVpViXh9…BD4par2XuA=
|
|
1163
1398
|
DSA signature: OK
|
|
1164
|
-
$ poetry run transcrypto -p dsa-key.pub dsa verify
|
|
1399
|
+
$ poetry run transcrypto --b64 -p dsa-key.pub dsa verify -- eLl6 yq8InJVpViXh9…BD4par2XuA=
|
|
1165
1400
|
DSA signature: INVALID
|
|
1166
1401
|
```
|
|
1167
1402
|
|
|
@@ -1215,10 +1450,11 @@ tomorrow it will rain
|
|
|
1215
1450
|
|
|
1216
1451
|
### `sss`
|
|
1217
1452
|
|
|
1218
|
-
|
|
1453
|
+
SSS (Shamir Shared Secret) secret sharing crypto scheme. No measures are taken here to prevent timing attacks. All methods require file key(s) as `-p`/`--key-path` (see provided examples).
|
|
1219
1454
|
|
|
1220
1455
|
```bash
|
|
1221
|
-
poetry run transcrypto sss [-h]
|
|
1456
|
+
poetry run transcrypto sss [-h]
|
|
1457
|
+
{new,rawshares,shares,rawrecover,recover,rawverify} ...
|
|
1222
1458
|
```
|
|
1223
1459
|
|
|
1224
1460
|
#### `sss new`
|
|
@@ -1241,9 +1477,30 @@ $ poetry run transcrypto -p sss-key sss new 3 --bits 64 # NEVER use such a smal
|
|
|
1241
1477
|
SSS private/public keys saved to 'sss-key.priv/.pub'
|
|
1242
1478
|
```
|
|
1243
1479
|
|
|
1480
|
+
#### `sss rawshares`
|
|
1481
|
+
|
|
1482
|
+
Raw shares: Issue `count` private shares for an *integer* `secret` (BEWARE: no modern message wrapping, padding or validation).
|
|
1483
|
+
|
|
1484
|
+
```bash
|
|
1485
|
+
poetry run transcrypto sss rawshares [-h] secret count
|
|
1486
|
+
```
|
|
1487
|
+
|
|
1488
|
+
| Option/Arg | Description |
|
|
1489
|
+
|---|---|
|
|
1490
|
+
| `secret` | Integer secret to be protected, 1≤`secret`<*modulus* [type: str] |
|
|
1491
|
+
| `count` | How many shares to produce; must be ≥ `minimum` used in `new` command or else the `secret` would become unrecoverable [type: int] |
|
|
1492
|
+
|
|
1493
|
+
**Example:**
|
|
1494
|
+
|
|
1495
|
+
```bash
|
|
1496
|
+
$ poetry run transcrypto -p sss-key sss rawshares 999 5
|
|
1497
|
+
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
|
|
1498
|
+
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
|
|
1499
|
+
```
|
|
1500
|
+
|
|
1244
1501
|
#### `sss shares`
|
|
1245
1502
|
|
|
1246
|
-
Issue `count` private shares for
|
|
1503
|
+
Shares: Issue `count` private shares for a `secret`.
|
|
1247
1504
|
|
|
1248
1505
|
```bash
|
|
1249
1506
|
poetry run transcrypto sss shares [-h] secret count
|
|
@@ -1251,17 +1508,36 @@ poetry run transcrypto sss shares [-h] secret count
|
|
|
1251
1508
|
|
|
1252
1509
|
| Option/Arg | Description |
|
|
1253
1510
|
|---|---|
|
|
1254
|
-
| `secret` |
|
|
1511
|
+
| `secret` | Secret to be protected [type: str] |
|
|
1255
1512
|
| `count` | How many shares to produce; must be ≥ `minimum` used in `new` command or else the `secret` would become unrecoverable [type: int] |
|
|
1256
1513
|
|
|
1257
1514
|
**Example:**
|
|
1258
1515
|
|
|
1259
1516
|
```bash
|
|
1260
|
-
$ poetry run transcrypto -p sss-key sss shares
|
|
1517
|
+
$ poetry run transcrypto --bin -p sss-key sss shares "abcde" 5
|
|
1261
1518
|
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
|
|
1262
1519
|
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
|
|
1263
1520
|
```
|
|
1264
1521
|
|
|
1522
|
+
#### `sss rawrecover`
|
|
1523
|
+
|
|
1524
|
+
Raw recover *integer* secret from shares; will use any available shares that were found (BEWARE: no modern message wrapping, padding or validation).
|
|
1525
|
+
|
|
1526
|
+
```bash
|
|
1527
|
+
poetry run transcrypto sss rawrecover [-h]
|
|
1528
|
+
```
|
|
1529
|
+
|
|
1530
|
+
**Example:**
|
|
1531
|
+
|
|
1532
|
+
```bash
|
|
1533
|
+
$ poetry run transcrypto -p sss-key sss rawrecover
|
|
1534
|
+
Loaded SSS share: 'sss-key.share.3'
|
|
1535
|
+
Loaded SSS share: 'sss-key.share.5'
|
|
1536
|
+
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
|
|
1537
|
+
Secret:
|
|
1538
|
+
999
|
|
1539
|
+
```
|
|
1540
|
+
|
|
1265
1541
|
#### `sss recover`
|
|
1266
1542
|
|
|
1267
1543
|
Recover secret from shares; will use any available shares that were found.
|
|
@@ -1273,34 +1549,34 @@ poetry run transcrypto sss recover [-h]
|
|
|
1273
1549
|
**Example:**
|
|
1274
1550
|
|
|
1275
1551
|
```bash
|
|
1276
|
-
$ poetry run transcrypto -p sss-key sss recover
|
|
1552
|
+
$ poetry run transcrypto --out-bin -p sss-key sss recover
|
|
1277
1553
|
Loaded SSS share: 'sss-key.share.3'
|
|
1278
1554
|
Loaded SSS share: 'sss-key.share.5'
|
|
1279
1555
|
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
|
|
1280
1556
|
Secret:
|
|
1281
|
-
|
|
1557
|
+
abcde
|
|
1282
1558
|
```
|
|
1283
1559
|
|
|
1284
|
-
#### `sss
|
|
1560
|
+
#### `sss rawverify`
|
|
1285
1561
|
|
|
1286
|
-
|
|
1562
|
+
Raw verify shares against a secret (private params; BEWARE: no modern message wrapping, padding or validation).
|
|
1287
1563
|
|
|
1288
1564
|
```bash
|
|
1289
|
-
poetry run transcrypto sss
|
|
1565
|
+
poetry run transcrypto sss rawverify [-h] secret
|
|
1290
1566
|
```
|
|
1291
1567
|
|
|
1292
1568
|
| Option/Arg | Description |
|
|
1293
1569
|
|---|---|
|
|
1294
|
-
| `secret` | Integer secret used to generate the shares
|
|
1570
|
+
| `secret` | Integer secret used to generate the shares [type: str] |
|
|
1295
1571
|
|
|
1296
1572
|
**Example:**
|
|
1297
1573
|
|
|
1298
1574
|
```bash
|
|
1299
|
-
$ poetry run transcrypto -p sss-key sss
|
|
1575
|
+
$ poetry run transcrypto -p sss-key sss rawverify 999
|
|
1300
1576
|
SSS share 'sss-key.share.3' verification: OK
|
|
1301
1577
|
SSS share 'sss-key.share.5' verification: OK
|
|
1302
1578
|
SSS share 'sss-key.share.1' verification: OK
|
|
1303
|
-
$ poetry run transcrypto -p sss-key sss
|
|
1579
|
+
$ poetry run transcrypto -p sss-key sss rawverify 998
|
|
1304
1580
|
SSS share 'sss-key.share.3' verification: INVALID
|
|
1305
1581
|
SSS share 'sss-key.share.5' verification: INVALID
|
|
1306
1582
|
SSS share 'sss-key.share.1' verification: INVALID
|
|
@@ -1396,169 +1672,39 @@ Chooses an appropriate time unit based on magnitude and formats with fixed preci
|
|
|
1396
1672
|
- special case: `0 → '0.00 s'`
|
|
1397
1673
|
- errors: negative or non-finite inputs raise `InputError`
|
|
1398
1674
|
|
|
1399
|
-
####
|
|
1675
|
+
#### Execution Timing
|
|
1400
1676
|
|
|
1401
|
-
|
|
1677
|
+
A flexible timing utility that works as a **context manager**, **decorator**, or **manual timer object**.
|
|
1402
1678
|
|
|
1403
1679
|
```py
|
|
1404
1680
|
from transcrypto import base
|
|
1681
|
+
import time
|
|
1405
1682
|
```
|
|
1406
1683
|
|
|
1407
|
-
#####
|
|
1684
|
+
##### Context manager
|
|
1408
1685
|
|
|
1409
1686
|
```py
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1687
|
+
with base.Timer('Block timing'):
|
|
1688
|
+
time.sleep(1.2)
|
|
1689
|
+
# → logs: "Block timing: 1.20 s" (default via logging.info)
|
|
1413
1690
|
```
|
|
1414
1691
|
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
- errors: `n_bits < 8` → `InputError`
|
|
1692
|
+
Starts timing on entry, stops on exit, and reports elapsed time automatically.
|
|
1418
1693
|
|
|
1419
|
-
#####
|
|
1694
|
+
##### Decorator
|
|
1420
1695
|
|
|
1421
1696
|
```py
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
```
|
|
1697
|
+
@base.Timer('Function timing')
|
|
1698
|
+
def slow_function():
|
|
1699
|
+
time.sleep(0.8)
|
|
1426
1700
|
|
|
1427
|
-
|
|
1701
|
+
slow_function()
|
|
1702
|
+
# → logs: "Function timing: 0.80 s"
|
|
1703
|
+
```
|
|
1428
1704
|
|
|
1429
|
-
|
|
1430
|
-
- errors: invalid bounds → `InputError`
|
|
1705
|
+
Wraps a function so that each call is automatically timed.
|
|
1431
1706
|
|
|
1432
|
-
#####
|
|
1433
|
-
|
|
1434
|
-
```py
|
|
1435
|
-
deck = list(range(10))
|
|
1436
|
-
base.RandShuffle(deck)
|
|
1437
|
-
print(deck) # securely shuffled order
|
|
1438
|
-
```
|
|
1439
|
-
|
|
1440
|
-
Performs an in-place Fisher–Yates shuffle using `secrets.randbelow`. Suitable for sensitive data ordering.
|
|
1441
|
-
|
|
1442
|
-
- constraints: sequence length ≥ 2
|
|
1443
|
-
- errors: shorter sequences → `InputError`
|
|
1444
|
-
|
|
1445
|
-
##### Random byte strings
|
|
1446
|
-
|
|
1447
|
-
```py
|
|
1448
|
-
# 32 random bytes
|
|
1449
|
-
b = base.RandBytes(32)
|
|
1450
|
-
assert len(b) == 32
|
|
1451
|
-
```
|
|
1452
|
-
|
|
1453
|
-
Generates `n_bytes` of high-quality crypto-secure random data.
|
|
1454
|
-
|
|
1455
|
-
- constraints: `n_bytes ≥ 1`
|
|
1456
|
-
- errors: smaller values → `InputError`
|
|
1457
|
-
|
|
1458
|
-
#### Computing the Greatest Common Divisor
|
|
1459
|
-
|
|
1460
|
-
```py
|
|
1461
|
-
>>> from transcrypto import base
|
|
1462
|
-
>>> base.GCD(462, 1071)
|
|
1463
|
-
21
|
|
1464
|
-
>>> base.GCD(0, 17)
|
|
1465
|
-
17
|
|
1466
|
-
```
|
|
1467
|
-
|
|
1468
|
-
The function is `O(log(min(a, b)))` and handles arbitrarily large integers. To find Bézout coefficients `(x, y)` such that `ax + by = gcd(a, b)` do:
|
|
1469
|
-
|
|
1470
|
-
```py
|
|
1471
|
-
>>> base.ExtendedGCD(462, 1071)
|
|
1472
|
-
(21, -2, 1)
|
|
1473
|
-
>>> 462 * -2 + 1071 * 1
|
|
1474
|
-
21
|
|
1475
|
-
```
|
|
1476
|
-
|
|
1477
|
-
Use-cases:
|
|
1478
|
-
|
|
1479
|
-
- modular inverses: `inv = x % m` when `gcd(a, m) == 1`
|
|
1480
|
-
- solving linear Diophantine equations
|
|
1481
|
-
- RSA / ECC key generation internals
|
|
1482
|
-
|
|
1483
|
-
#### Cryptographic Hashing
|
|
1484
|
-
|
|
1485
|
-
Simple, fixed-output-size wrappers over Python’s `hashlib` for common digest operations, plus file hashing.
|
|
1486
|
-
|
|
1487
|
-
```py
|
|
1488
|
-
from transcrypto import base
|
|
1489
|
-
```
|
|
1490
|
-
|
|
1491
|
-
##### SHA-256 hashing
|
|
1492
|
-
|
|
1493
|
-
```py
|
|
1494
|
-
h = base.Hash256(b'hello world')
|
|
1495
|
-
assert len(h) == 32 # bytes
|
|
1496
|
-
print(h.hex()) # 64 hex chars
|
|
1497
|
-
```
|
|
1498
|
-
|
|
1499
|
-
Computes the SHA-256 digest of a byte string, returning exactly 32 bytes (256 bits). Suitable for fingerprints, commitments, or internal crypto primitives.
|
|
1500
|
-
|
|
1501
|
-
##### SHA-512 hashing
|
|
1502
|
-
|
|
1503
|
-
```py
|
|
1504
|
-
h = base.Hash512(b'hello world')
|
|
1505
|
-
assert len(h) == 64 # bytes
|
|
1506
|
-
print(h.hex()) # 128 hex chars
|
|
1507
|
-
```
|
|
1508
|
-
|
|
1509
|
-
Computes the SHA-512 digest of a byte string, returning exactly 64 bytes (512 bits). Higher collision resistance and larger output space than SHA-256.
|
|
1510
|
-
|
|
1511
|
-
##### File hashing
|
|
1512
|
-
|
|
1513
|
-
```py
|
|
1514
|
-
# Default SHA-256
|
|
1515
|
-
fh = base.FileHash('/path/to/file')
|
|
1516
|
-
print(fh.hex())
|
|
1517
|
-
|
|
1518
|
-
# SHA-512
|
|
1519
|
-
fh2 = base.FileHash('/path/to/file', digest='sha512')
|
|
1520
|
-
```
|
|
1521
|
-
|
|
1522
|
-
Hashes a file from disk in streaming mode. By default uses SHA-256; `digest='sha512'` switches to SHA-512.
|
|
1523
|
-
|
|
1524
|
-
- constraints:
|
|
1525
|
-
- `digest` must be `'sha256'` or `'sha512'`
|
|
1526
|
-
- `full_path` must exist
|
|
1527
|
-
- errors: invalid digest or missing file → `InputError`
|
|
1528
|
-
|
|
1529
|
-
#### Execution Timing
|
|
1530
|
-
|
|
1531
|
-
A flexible timing utility that works as a **context manager**, **decorator**, or **manual timer object**.
|
|
1532
|
-
|
|
1533
|
-
```py
|
|
1534
|
-
from transcrypto import base
|
|
1535
|
-
import time
|
|
1536
|
-
```
|
|
1537
|
-
|
|
1538
|
-
##### Context manager
|
|
1539
|
-
|
|
1540
|
-
```py
|
|
1541
|
-
with base.Timer('Block timing'):
|
|
1542
|
-
time.sleep(1.2)
|
|
1543
|
-
# → logs: "Block timing: 1.20 s" (default via logging.info)
|
|
1544
|
-
```
|
|
1545
|
-
|
|
1546
|
-
Starts timing on entry, stops on exit, and reports elapsed time automatically.
|
|
1547
|
-
|
|
1548
|
-
##### Decorator
|
|
1549
|
-
|
|
1550
|
-
```py
|
|
1551
|
-
@base.Timer('Function timing')
|
|
1552
|
-
def slow_function():
|
|
1553
|
-
time.sleep(0.8)
|
|
1554
|
-
|
|
1555
|
-
slow_function()
|
|
1556
|
-
# → logs: "Function timing: 0.80 s"
|
|
1557
|
-
```
|
|
1558
|
-
|
|
1559
|
-
Wraps a function so that each call is automatically timed.
|
|
1560
|
-
|
|
1561
|
-
##### Manual use
|
|
1707
|
+
##### Manual use
|
|
1562
1708
|
|
|
1563
1709
|
```py
|
|
1564
1710
|
tm = base.Timer('Inline timing', emit_print=True)
|
|
@@ -1582,21 +1728,6 @@ Manual control over `Start()` and `Stop()` for precise measurement of custom int
|
|
|
1582
1728
|
- Cannot stop an unstarted or already stopped timer
|
|
1583
1729
|
(raises `Error`)
|
|
1584
1730
|
|
|
1585
|
-
#### Symmetric Encryption Interface
|
|
1586
|
-
|
|
1587
|
-
`SymmetricCrypto` is an abstract base class that defines the **byte-in / byte-out** contract for symmetric ciphers.
|
|
1588
|
-
|
|
1589
|
-
- **Metadata handling** — if the algorithm uses a `nonce` or `tag`, the implementation must handle it internally (e.g., append it to ciphertext).
|
|
1590
|
-
- **AEAD modes** — if supported, `associated_data` must be authenticated; otherwise, a non-`None` value should raise `InputError`.
|
|
1591
|
-
|
|
1592
|
-
```py
|
|
1593
|
-
class MyAES(base.SymmetricCrypto):
|
|
1594
|
-
def Encrypt(self, plaintext: bytes, *, associated_data=None) -> bytes:
|
|
1595
|
-
...
|
|
1596
|
-
def Decrypt(self, ciphertext: bytes, *, associated_data=None) -> bytes:
|
|
1597
|
-
...
|
|
1598
|
-
```
|
|
1599
|
-
|
|
1600
1731
|
#### Serialization Pipeline
|
|
1601
1732
|
|
|
1602
1733
|
These helpers turn arbitrary Python objects into compressed and/or encrypted binary blobs, and back again — with detailed timing and size logging.
|
|
@@ -1679,114 +1810,89 @@ data/file → (decrypt) → (decompress if Zstd) → unpickle
|
|
|
1679
1810
|
- `file_path` must exist; `data` must be at least 4 bytes.
|
|
1680
1811
|
- Wrong key or corrupted data can raise `CryptoError`.
|
|
1681
1812
|
|
|
1682
|
-
####
|
|
1683
|
-
|
|
1684
|
-
Cryptographic objects all derive from the `CryptoKey` class and will all have some important characteristics:
|
|
1685
|
-
|
|
1686
|
-
- Will be safe to log and print, i.e., implement safe `__str__()` and `__repr__()` methods (in actuality `repr` will be exactly the same as `str`). The `__str__()` should always fully print the public parts of the object and obfuscate the private ones. This obfuscation allows for some debugging, if needed, but if the secrets are "too short" then it can be defeated by brute force. For usual crypto defaults the obfuscation is fine. The obfuscation is the fist 4 bytes of the SHA-512 for the value followed by an ellipsis (e.g. `c9626f16…`).
|
|
1687
|
-
- It will have a `_DebugDump()` method that **does print secrets** and can be used for **debugging only**.
|
|
1688
|
-
- Can be easily serialized to `bytes` by the `blob` property and to base-64 encoded `str` by the `encoded` property.
|
|
1689
|
-
- Can be serialized encrypted to `bytes` by the `Blob(key=[SymmetricCrypto])` method and to encrypted base-64 encoded `str` by the `Encoded(key=[SymmetricCrypto])` method.
|
|
1690
|
-
- Can be instantiated back as an object from `str` or `bytes` using the `Load(data, key=[SymmetricCrypto] | None)` method. The `Load()` will decide how to build the object and will work universally with all the serialization options discussed above.
|
|
1813
|
+
#### Cryptographically Secure Randomness
|
|
1691
1814
|
|
|
1692
|
-
|
|
1815
|
+
These helpers live in `base` and wrap Python’s `secrets` with additional checks and guarantees for crypto use-cases.
|
|
1693
1816
|
|
|
1694
|
-
<!-- cspell:disable -->
|
|
1695
1817
|
```py
|
|
1696
|
-
from transcrypto import base
|
|
1818
|
+
from transcrypto import base
|
|
1819
|
+
```
|
|
1697
1820
|
|
|
1698
|
-
|
|
1699
|
-
print(str(priv)) # safe, no secrets
|
|
1700
|
-
# ▶ RSAPrivateKey(RSAPublicKey(public_modulus=pQaoxy-QeXSds1k9WsGjJw==, encrypt_exp=AQAB), modulus_p=f18141aa…, modulus_q=67494eb9…, decrypt_exp=c96db24a…)
|
|
1821
|
+
##### Fixed-size random integers
|
|
1701
1822
|
|
|
1702
|
-
|
|
1703
|
-
#
|
|
1823
|
+
```py
|
|
1824
|
+
# Generate a 256-bit integer (first bit always set)
|
|
1825
|
+
r = base.RandBits(256)
|
|
1826
|
+
assert r.bit_length() == 256
|
|
1827
|
+
```
|
|
1704
1828
|
|
|
1705
|
-
|
|
1706
|
-
# ▶ b"(\xb5/\xfd \x98\xc1\x04\x00\x80\x04\x95\x8d\x00\x00\x00\x00\x00\x00\x00\x8c\x0ftranscrypto.rsa\x94\x8c\rRSAPrivateKey\x94\x93\x94)\x81\x94]\x94(\x8a\x11'\xa3\xc1Z=Y\xb3\x9dty\x90/\xc7\xa8\x06\xa5\x00J\x01\x00\x01\x00\x8a\t\xa1\xc4\x83\x81\xc8\xc1{\xb7\x00\x8a\t\xc7\x8a5\xf0Qq?\xe6\x00\x8a\x10A$&\x82!\x1cy\x89r\xef\xeb\xa7_\x04q\x1c\x8a\t\x01\xbc\xbb\x8a\x8b=%\x84\x00\x8a\x08;\x94#s\xff\xef\x8f|\x8a\t,\x9c\xe2z\x9a7\x0e\xa6\x00eb."
|
|
1829
|
+
Produces a crypto-secure random integer with exactly `n_bits` bits (`≥ 8`). The most significant bit is guaranteed to be `1`, so entropy is \~`n_bits−1` — negligible for large crypto sizes.
|
|
1707
1830
|
|
|
1708
|
-
|
|
1709
|
-
# ▶ KLUv_WBwAIELAIAElWUBAAAAAAAAjA90cmFuc2NyeXB0by5yc2GUjA1SU0FQcml2YXRlS2V5lJOUKYGUXZQoikHf1EvsmZedAZve7TrLmobLAwuRIr_77TLG6G_0fsLGThERVJu075be8PLjUQYnLXcacZFQ5Fb1Iy1WtiE985euAEoBAAEAiiFR9ngiXMzkf41o5CRBY3h0D4DJVisDDhLmAWsiaHggzQCKIS_cmQ6MKXCtROtC7c_Mrsi9A-9NM8DksaHaRwvy6uTZAIpB4TVbsLxc41TEc19wIzpxbi9y5dW5gdfTkRQSSiz0ijmb8Xk3pyBfKAv8JbHp8Yv48gNZUfX67qq0J7yhJqeUoACKIbFb2kTNRzSqm3JRtjc2BPS-FnLFdadlFcV4-6IW7eqLAIogFZfzDN39gZLR9uTz4KHSTaqxWrJgP8-YYssjss6FlFKKIIItgCDv7ompNpY8gBs5bibN8XTsr-JOYSntDVT5Fe5vZWIu
|
|
1831
|
+
- errors: `n_bits < 8` → `InputError`
|
|
1710
1832
|
|
|
1711
|
-
|
|
1712
|
-
print(key)
|
|
1713
|
-
# ▶ AESKey(key256=86a86df7…)
|
|
1833
|
+
##### Uniform random integers in a range
|
|
1714
1834
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1835
|
+
```py
|
|
1836
|
+
# Uniform between [10, 20] inclusive
|
|
1837
|
+
n = base.RandInt(10, 20)
|
|
1838
|
+
assert 10 <= n <= 20
|
|
1718
1839
|
```
|
|
1719
|
-
<!-- cspell:enable -->
|
|
1720
1840
|
|
|
1721
|
-
|
|
1841
|
+
Returns a crypto-secure integer uniformly distributed over the closed interval `[min_int, max_int]`.
|
|
1722
1842
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1843
|
+
- constraints: `min_int ≥ 0` and `< max_int`
|
|
1844
|
+
- errors: invalid bounds → `InputError`
|
|
1725
1845
|
|
|
1726
|
-
#####
|
|
1846
|
+
##### In-place secure shuffle
|
|
1727
1847
|
|
|
1728
1848
|
```py
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
#
|
|
1732
|
-
key = aes.AESKey(key256=b'\x00' * 32)
|
|
1733
|
-
|
|
1734
|
-
# From a static password (slow, high-iteration PBKDF2-SHA256)
|
|
1735
|
-
key = aes.AESKey.FromStaticPassword('correct horse battery staple')
|
|
1736
|
-
print(key.encoded) # URL-safe Base64
|
|
1849
|
+
deck = list(range(10))
|
|
1850
|
+
base.RandShuffle(deck)
|
|
1851
|
+
print(deck) # securely shuffled order
|
|
1737
1852
|
```
|
|
1738
1853
|
|
|
1739
|
-
-
|
|
1740
|
-
- `FromStaticPassword()`:
|
|
1741
|
-
- Uses PBKDF2-HMAC-SHA256 with **fixed** salt and \~2 million iterations
|
|
1742
|
-
- Designed for **interactive** password entry, **not** for password databases
|
|
1743
|
-
|
|
1744
|
-
##### AES-256 + GCM (default)
|
|
1854
|
+
Performs an in-place Fisher–Yates shuffle using `secrets.randbelow`. Suitable for sensitive data ordering.
|
|
1745
1855
|
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
aad = b'metadata'
|
|
1856
|
+
- constraints: sequence length ≥ 2
|
|
1857
|
+
- errors: shorter sequences → `InputError`
|
|
1749
1858
|
|
|
1750
|
-
|
|
1751
|
-
ct = key.Encrypt(data, associated_data=aad)
|
|
1859
|
+
##### Random byte strings
|
|
1752
1860
|
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1861
|
+
```py
|
|
1862
|
+
# 32 random bytes
|
|
1863
|
+
b = base.RandBytes(32)
|
|
1864
|
+
assert len(b) == 32
|
|
1756
1865
|
```
|
|
1757
1866
|
|
|
1758
|
-
-
|
|
1759
|
-
- Random 128-bit IV (`iv`) per encryption
|
|
1760
|
-
- Authenticated tag (128-bit) ensures integrity
|
|
1761
|
-
- Optional `associated_data` is authenticated but not encrypted
|
|
1762
|
-
- **Errors**:
|
|
1763
|
-
- Tag mismatch or wrong key → `CryptoError`
|
|
1867
|
+
Generates `n_bytes` of high-quality crypto-secure random data.
|
|
1764
1868
|
|
|
1765
|
-
|
|
1869
|
+
- constraints: `n_bytes ≥ 1`
|
|
1870
|
+
- errors: smaller values → `InputError`
|
|
1871
|
+
|
|
1872
|
+
#### Computing the Greatest Common Divisor
|
|
1766
1873
|
|
|
1767
1874
|
```py
|
|
1768
|
-
|
|
1769
|
-
|
|
1875
|
+
>>> from transcrypto import base
|
|
1876
|
+
>>> base.GCD(462, 1071)
|
|
1877
|
+
21
|
|
1878
|
+
>>> base.GCD(0, 17)
|
|
1879
|
+
17
|
|
1880
|
+
```
|
|
1770
1881
|
|
|
1771
|
-
|
|
1772
|
-
ct_block = ecb.Encrypt(block)
|
|
1773
|
-
pt_block = ecb.Decrypt(ct_block)
|
|
1774
|
-
assert pt_block == block
|
|
1882
|
+
The function is `O(log(min(a, b)))` and handles arbitrarily large integers. To find Bézout coefficients `(x, y)` such that `ax + by = gcd(a, b)` do:
|
|
1775
1883
|
|
|
1776
|
-
|
|
1777
|
-
|
|
1884
|
+
```py
|
|
1885
|
+
>>> base.ExtendedGCD(462, 1071)
|
|
1886
|
+
(21, -2, 1)
|
|
1887
|
+
>>> 462 * -2 + 1071 * 1
|
|
1888
|
+
21
|
|
1778
1889
|
```
|
|
1779
1890
|
|
|
1780
|
-
-
|
|
1781
|
-
- 16-byte plaintext ↔ 16-byte ciphertext
|
|
1782
|
-
- No padding, no IV, no integrity — **do not use for general encryption**
|
|
1783
|
-
- `associated_data` not supported
|
|
1784
|
-
|
|
1785
|
-
Key points:
|
|
1891
|
+
Use-cases:
|
|
1786
1892
|
|
|
1787
|
-
-
|
|
1788
|
-
-
|
|
1789
|
-
-
|
|
1893
|
+
- modular inverses: `inv = x % m` when `gcd(a, m) == 1`
|
|
1894
|
+
- solving linear Diophantine equations
|
|
1895
|
+
- RSA / ECC key generation internals
|
|
1790
1896
|
|
|
1791
1897
|
#### Fast Modular Arithmetic
|
|
1792
1898
|
|
|
@@ -1809,7 +1915,7 @@ assert (z * y) % m == x % m
|
|
|
1809
1915
|
exp = modmath.ModExp(3, 10**20, m) # ≈ log₂(y) time, handles huge exponents
|
|
1810
1916
|
```
|
|
1811
1917
|
|
|
1812
|
-
|
|
1918
|
+
##### Chinese Remainder Theorem (CRT) – Pair
|
|
1813
1919
|
|
|
1814
1920
|
```py
|
|
1815
1921
|
from transcrypto import modmath
|
|
@@ -1840,7 +1946,7 @@ x ≡ a2 (mod m2)
|
|
|
1840
1946
|
|
|
1841
1947
|
This function is a 2-modulus variant; for multiple moduli, apply it iteratively or use a general CRT solver.
|
|
1842
1948
|
|
|
1843
|
-
|
|
1949
|
+
##### Modular Polynomials & Lagrange Interpolation
|
|
1844
1950
|
|
|
1845
1951
|
```py
|
|
1846
1952
|
# f(t) = 7t³ − 3t² + 2t + 5 (coefficients constant-term first)
|
|
@@ -1868,7 +1974,7 @@ for p in modmath.PrimeGenerator(1_000_000):
|
|
|
1868
1974
|
break
|
|
1869
1975
|
|
|
1870
1976
|
# Secure random 384-bit prime (for RSA/ECC experiments)
|
|
1871
|
-
p384 = modmath.
|
|
1977
|
+
p384 = modmath.NBitRandomPrimes(384).pop()
|
|
1872
1978
|
|
|
1873
1979
|
for k, m_p, perfect in modmath.MersennePrimesGenerator(0):
|
|
1874
1980
|
print(f'p = {k:>8} M = {m_p} perfect = {perfect}')
|
|
@@ -1876,6 +1982,176 @@ for k, m_p, perfect in modmath.MersennePrimesGenerator(0):
|
|
|
1876
1982
|
break
|
|
1877
1983
|
```
|
|
1878
1984
|
|
|
1985
|
+
#### Cryptographic Hashing
|
|
1986
|
+
|
|
1987
|
+
Simple, fixed-output-size wrappers over Python’s `hashlib` for common digest operations, plus file hashing.
|
|
1988
|
+
|
|
1989
|
+
```py
|
|
1990
|
+
from transcrypto import base
|
|
1991
|
+
```
|
|
1992
|
+
|
|
1993
|
+
##### SHA-256 hashing
|
|
1994
|
+
|
|
1995
|
+
```py
|
|
1996
|
+
h = base.Hash256(b'hello world')
|
|
1997
|
+
assert len(h) == 32 # bytes
|
|
1998
|
+
print(h.hex()) # 64 hex chars
|
|
1999
|
+
```
|
|
2000
|
+
|
|
2001
|
+
Computes the SHA-256 digest of a byte string, returning exactly 32 bytes (256 bits). Suitable for fingerprints, commitments, or internal crypto primitives.
|
|
2002
|
+
|
|
2003
|
+
##### SHA-512 hashing
|
|
2004
|
+
|
|
2005
|
+
```py
|
|
2006
|
+
h = base.Hash512(b'hello world')
|
|
2007
|
+
assert len(h) == 64 # bytes
|
|
2008
|
+
print(h.hex()) # 128 hex chars
|
|
2009
|
+
```
|
|
2010
|
+
|
|
2011
|
+
Computes the SHA-512 digest of a byte string, returning exactly 64 bytes (512 bits). Higher collision resistance and larger output space than SHA-256.
|
|
2012
|
+
|
|
2013
|
+
##### File hashing
|
|
2014
|
+
|
|
2015
|
+
```py
|
|
2016
|
+
# Default SHA-256
|
|
2017
|
+
fh = base.FileHash('/path/to/file')
|
|
2018
|
+
print(fh.hex())
|
|
2019
|
+
|
|
2020
|
+
# SHA-512
|
|
2021
|
+
fh2 = base.FileHash('/path/to/file', digest='sha512')
|
|
2022
|
+
```
|
|
2023
|
+
|
|
2024
|
+
Hashes a file from disk in streaming mode. By default uses SHA-256; `digest='sha512'` switches to SHA-512.
|
|
2025
|
+
|
|
2026
|
+
- constraints:
|
|
2027
|
+
- `digest` must be `'sha256'` or `'sha512'`
|
|
2028
|
+
- `full_path` must exist
|
|
2029
|
+
- errors: invalid digest or missing file → `InputError`
|
|
2030
|
+
|
|
2031
|
+
#### Symmetric Encryption Interface
|
|
2032
|
+
|
|
2033
|
+
`SymmetricCrypto` is an abstract base class that defines the **byte-in / byte-out** contract for symmetric ciphers.
|
|
2034
|
+
|
|
2035
|
+
- **Metadata handling** — if the algorithm uses a `nonce` or `tag`, the implementation must handle it internally (e.g., append it to ciphertext).
|
|
2036
|
+
- **AEAD modes** — if supported, `associated_data` must be authenticated; otherwise, a non-`None` value should raise `InputError`.
|
|
2037
|
+
|
|
2038
|
+
```py
|
|
2039
|
+
class MyAES(base.SymmetricCrypto):
|
|
2040
|
+
def Encrypt(self, plaintext: bytes, *, associated_data=None) -> bytes:
|
|
2041
|
+
...
|
|
2042
|
+
def Decrypt(self, ciphertext: bytes, *, associated_data=None) -> bytes:
|
|
2043
|
+
...
|
|
2044
|
+
```
|
|
2045
|
+
|
|
2046
|
+
#### Crypto Objects General Properties (`CryptoKey`)
|
|
2047
|
+
|
|
2048
|
+
Cryptographic objects all derive from the `CryptoKey` class and will all have some important characteristics:
|
|
2049
|
+
|
|
2050
|
+
- Will be safe to log and print, i.e., implement safe `__str__()` and `__repr__()` methods (in actuality `repr` will be exactly the same as `str`). The `__str__()` should always fully print the public parts of the object and obfuscate the private ones. This obfuscation allows for some debugging, if needed, but if the secrets are "too short" then it can be defeated by brute force. For usual crypto defaults the obfuscation is fine. The obfuscation is the fist 4 bytes of the SHA-512 for the value followed by an ellipsis (e.g. `c9626f16…`).
|
|
2051
|
+
- It will have a `_DebugDump()` method that **does print secrets** and can be used for **debugging only**.
|
|
2052
|
+
- Can be easily serialized to `bytes` by the `blob` property and to base-64 encoded `str` by the `encoded` property.
|
|
2053
|
+
- Can be serialized encrypted to `bytes` by the `Blob(key=[SymmetricCrypto])` method and to encrypted base-64 encoded `str` by the `Encoded(key=[SymmetricCrypto])` method.
|
|
2054
|
+
- Can be instantiated back as an object from `str` or `bytes` using the `Load(data, key=[SymmetricCrypto] | None)` method. The `Load()` will decide how to build the object and will work universally with all the serialization options discussed above.
|
|
2055
|
+
|
|
2056
|
+
Example:
|
|
2057
|
+
|
|
2058
|
+
<!-- cspell:disable -->
|
|
2059
|
+
```py
|
|
2060
|
+
from transcrypto import base, rsa, aes
|
|
2061
|
+
|
|
2062
|
+
priv = rsa.RSAPrivateKey.New(512) # small key, but good for this example
|
|
2063
|
+
print(str(priv)) # safe, no secrets
|
|
2064
|
+
# ▶ RSAPrivateKey(RSAPublicKey(public_modulus=pQaoxy-QeXSds1k9WsGjJw==, encrypt_exp=AQAB), modulus_p=f18141aa…, modulus_q=67494eb9…, decrypt_exp=c96db24a…)
|
|
2065
|
+
|
|
2066
|
+
print(priv._DebugDump()) # UNSAFE: prints secrets
|
|
2067
|
+
# ▶ RSAPrivateKey(public_modulus=219357196311600536151291741191131996967, encrypt_exp=65537, modulus_p=13221374197986739361, modulus_q=16591104148992527047, decrypt_exp=37805202135275158391322585315542443073, remainder_p=9522084656682089473, remainder_q=8975656462800098363, q_inverse_p=11965562396596149292)
|
|
2068
|
+
|
|
2069
|
+
print(priv.blob)
|
|
2070
|
+
# ▶ b"(\xb5/\xfd \x98\xc1\x04\x00\x80\x04\x95\x8d\x00\x00\x00\x00\x00\x00\x00\x8c\x0ftranscrypto.rsa\x94\x8c\rRSAPrivateKey\x94\x93\x94)\x81\x94]\x94(\x8a\x11'\xa3\xc1Z=Y\xb3\x9dty\x90/\xc7\xa8\x06\xa5\x00J\x01\x00\x01\x00\x8a\t\xa1\xc4\x83\x81\xc8\xc1{\xb7\x00\x8a\t\xc7\x8a5\xf0Qq?\xe6\x00\x8a\x10A$&\x82!\x1cy\x89r\xef\xeb\xa7_\x04q\x1c\x8a\t\x01\xbc\xbb\x8a\x8b=%\x84\x00\x8a\x08;\x94#s\xff\xef\x8f|\x8a\t,\x9c\xe2z\x9a7\x0e\xa6\x00eb."
|
|
2071
|
+
|
|
2072
|
+
print(priv.encoded)
|
|
2073
|
+
# ▶ KLUv_WBwAIELAIAElWUBAAAAAAAAjA90cmFuc2NyeXB0by5yc2GUjA1SU0FQcml2YXRlS2V5lJOUKYGUXZQoikHf1EvsmZedAZve7TrLmobLAwuRIr_77TLG6G_0fsLGThERVJu075be8PLjUQYnLXcacZFQ5Fb1Iy1WtiE985euAEoBAAEAiiFR9ngiXMzkf41o5CRBY3h0D4DJVisDDhLmAWsiaHggzQCKIS_cmQ6MKXCtROtC7c_Mrsi9A-9NM8DksaHaRwvy6uTZAIpB4TVbsLxc41TEc19wIzpxbi9y5dW5gdfTkRQSSiz0ijmb8Xk3pyBfKAv8JbHp8Yv48gNZUfX67qq0J7yhJqeUoACKIbFb2kTNRzSqm3JRtjc2BPS-FnLFdadlFcV4-6IW7eqLAIogFZfzDN39gZLR9uTz4KHSTaqxWrJgP8-YYssjss6FlFKKIIItgCDv7ompNpY8gBs5bibN8XTsr-JOYSntDVT5Fe5vZWIu
|
|
2074
|
+
|
|
2075
|
+
key = aes.AESKey(key256=b'x' * 32)
|
|
2076
|
+
print(key)
|
|
2077
|
+
# ▶ AESKey(key256=86a86df7…)
|
|
2078
|
+
|
|
2079
|
+
encrypted = priv.Blob(key=key)
|
|
2080
|
+
print(priv == rsa.RSAPrivateKey.Load(encrypted, key=key))
|
|
2081
|
+
# ▶ True
|
|
2082
|
+
```
|
|
2083
|
+
<!-- cspell:enable -->
|
|
2084
|
+
|
|
2085
|
+
#### AES-256 Symmetric Encryption
|
|
2086
|
+
|
|
2087
|
+
Implements AES-256 in **GCM mode** for authenticated encryption and decryption, plus an **ECB mode** helper for fixed-size block encoding.
|
|
2088
|
+
Also includes a high-iteration PBKDF2-based key derivation from static passwords.
|
|
2089
|
+
|
|
2090
|
+
##### Key creation
|
|
2091
|
+
|
|
2092
|
+
```py
|
|
2093
|
+
from transcrypto import aes
|
|
2094
|
+
|
|
2095
|
+
# From raw bytes (must be exactly 32 bytes)
|
|
2096
|
+
key = aes.AESKey(key256=b'\x00' * 32)
|
|
2097
|
+
|
|
2098
|
+
# From a static password (slow, high-iteration PBKDF2-SHA256)
|
|
2099
|
+
key = aes.AESKey.FromStaticPassword('correct horse battery staple')
|
|
2100
|
+
print(key.encoded) # URL-safe Base64
|
|
2101
|
+
```
|
|
2102
|
+
|
|
2103
|
+
- **Length**: `key256` must be exactly 32 bytes
|
|
2104
|
+
- `FromStaticPassword()`:
|
|
2105
|
+
- Uses PBKDF2-HMAC-SHA256 with **fixed** salt and \~2 million iterations
|
|
2106
|
+
- Designed for **interactive** password entry, **not** for password databases
|
|
2107
|
+
|
|
2108
|
+
##### AES-256 + GCM (default)
|
|
2109
|
+
|
|
2110
|
+
```py
|
|
2111
|
+
data = b'secret message'
|
|
2112
|
+
aad = b'metadata'
|
|
2113
|
+
|
|
2114
|
+
# Encrypt (returns IV + ciphertext + tag)
|
|
2115
|
+
ct = key.Encrypt(data, associated_data=aad)
|
|
2116
|
+
|
|
2117
|
+
# Decrypt
|
|
2118
|
+
pt = key.Decrypt(ct, associated_data=aad)
|
|
2119
|
+
assert pt == data
|
|
2120
|
+
```
|
|
2121
|
+
|
|
2122
|
+
- **Security**:
|
|
2123
|
+
- Random 128-bit IV (`iv`) per encryption
|
|
2124
|
+
- Authenticated tag (128-bit) ensures integrity
|
|
2125
|
+
- Optional `associated_data` is authenticated but not encrypted
|
|
2126
|
+
- **Errors**:
|
|
2127
|
+
- Tag mismatch or wrong key → `CryptoError`
|
|
2128
|
+
|
|
2129
|
+
##### AES-256 + ECB (unsafe, fixed block only)
|
|
2130
|
+
|
|
2131
|
+
```py
|
|
2132
|
+
# ECB mode is for 16-byte block encoding ONLY
|
|
2133
|
+
ecb = key.ECBEncoder()
|
|
2134
|
+
|
|
2135
|
+
block = b'16-byte string!!'
|
|
2136
|
+
ct_block = ecb.Encrypt(block)
|
|
2137
|
+
pt_block = ecb.Decrypt(ct_block)
|
|
2138
|
+
assert pt_block == block
|
|
2139
|
+
|
|
2140
|
+
# Hex helpers
|
|
2141
|
+
hex_ct = ecb.EncryptHex('00112233445566778899aabbccddeeff')
|
|
2142
|
+
```
|
|
2143
|
+
|
|
2144
|
+
- **ECB mode**:
|
|
2145
|
+
- 16-byte plaintext ↔ 16-byte ciphertext
|
|
2146
|
+
- No padding, no IV, no integrity — **do not use for general encryption**
|
|
2147
|
+
- `associated_data` not supported
|
|
2148
|
+
|
|
2149
|
+
Key points:
|
|
2150
|
+
|
|
2151
|
+
- **GCM mode** is secure for general use; ECB mode is for special low-level operations
|
|
2152
|
+
- **Static password derivation** is intentionally slow to resist brute force
|
|
2153
|
+
- All sizes and parameters are validated with `InputError` on misuse
|
|
2154
|
+
|
|
1879
2155
|
#### RSA (Rivest-Shamir-Adleman) Public Cryptography
|
|
1880
2156
|
|
|
1881
2157
|
<https://en.wikipedia.org/wiki/RSA_cryptosystem>
|
|
@@ -1888,28 +2164,38 @@ By default and deliberate choice the *encryption exponent* will be either 7 or 6
|
|
|
1888
2164
|
from transcrypto import rsa
|
|
1889
2165
|
|
|
1890
2166
|
# Generate a key pair
|
|
1891
|
-
priv = rsa.RSAPrivateKey.New(2048)
|
|
1892
|
-
pub = rsa.RSAPublicKey.Copy(priv)
|
|
2167
|
+
priv = rsa.RSAPrivateKey.New(2048) # 2048-bit modulus
|
|
2168
|
+
pub = rsa.RSAPublicKey.Copy(priv) # public half
|
|
1893
2169
|
print(priv.public_modulus.bit_length()) # 2048
|
|
1894
2170
|
|
|
1895
|
-
#
|
|
2171
|
+
# Safe Encrypt & decrypt
|
|
2172
|
+
msg = b'xyz'
|
|
2173
|
+
cipher = pub.Encrypt(msg, associated_data=b'aad')
|
|
2174
|
+
plain = priv.Decrypt(cipher, associated_data=b'aad')
|
|
2175
|
+
assert plain == msg
|
|
2176
|
+
|
|
2177
|
+
# Safe Sign & verify
|
|
2178
|
+
signature = priv.Sign(msg) # can also have associated_data, optionally
|
|
2179
|
+
assert pub.Verify(msg, signature)
|
|
2180
|
+
|
|
2181
|
+
# Raw Encrypt & decrypt
|
|
1896
2182
|
msg = 123456789 # (Zero is forbidden by design; smallest valid message is 1.)
|
|
1897
|
-
cipher = pub.
|
|
1898
|
-
plain = priv.
|
|
2183
|
+
cipher = pub.RawEncrypt(msg)
|
|
2184
|
+
plain = priv.RawDecrypt(cipher)
|
|
1899
2185
|
assert plain == msg
|
|
1900
2186
|
|
|
1901
|
-
# Sign & verify
|
|
1902
|
-
signature = priv.
|
|
1903
|
-
assert pub.
|
|
2187
|
+
# Raw Sign & verify
|
|
2188
|
+
signature = priv.RawSign(msg)
|
|
2189
|
+
assert pub.RawVerify(msg, signature)
|
|
1904
2190
|
|
|
1905
2191
|
# Blind signatures (obfuscation pair) - only works on raw RSA
|
|
1906
2192
|
pair = rsa.RSAObfuscationPair.New(pub)
|
|
1907
2193
|
|
|
1908
2194
|
blind_msg = pair.ObfuscateMessage(msg) # what you send to signer
|
|
1909
|
-
blind_sig = priv.
|
|
2195
|
+
blind_sig = priv.RawSign(blind_msg) # signer’s output
|
|
1910
2196
|
|
|
1911
2197
|
sig = pair.RevealOriginalSignature(msg, blind_sig)
|
|
1912
|
-
assert pub.
|
|
2198
|
+
assert pub.RawVerify(msg, sig)
|
|
1913
2199
|
```
|
|
1914
2200
|
|
|
1915
2201
|
#### El-Gamal Public-Key Cryptography
|
|
@@ -1919,61 +2205,39 @@ assert pub.VerifySignature(msg, sig)
|
|
|
1919
2205
|
This is **raw El-Gamal** over a prime field — no padding, no hashing — and is **not** DSA.
|
|
1920
2206
|
For real-world deployments, use a high-level library with authenticated encryption and proper encoding.
|
|
1921
2207
|
|
|
1922
|
-
##### Shared Public Key
|
|
1923
|
-
|
|
1924
2208
|
```py
|
|
1925
2209
|
from transcrypto import elgamal
|
|
1926
2210
|
|
|
1927
|
-
#
|
|
2211
|
+
# Shared parameters (prime modulus, group base) for a group
|
|
1928
2212
|
shared = elgamal.ElGamalSharedPublicKey.New(256)
|
|
1929
2213
|
print(shared.prime_modulus)
|
|
1930
2214
|
print(shared.group_base)
|
|
1931
|
-
```
|
|
1932
|
-
|
|
1933
|
-
- `prime_modulus`: large prime `p ≥ 7`
|
|
1934
|
-
- `group_base`: integer `3 ≤ g < p`
|
|
1935
|
-
- Used to derive individual public/private keys.
|
|
1936
2215
|
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
```py
|
|
1940
|
-
# ➋ Public key from private
|
|
2216
|
+
# Public key from private
|
|
1941
2217
|
priv = elgamal.ElGamalPrivateKey.New(shared)
|
|
1942
2218
|
pub = elgamal.ElGamalPublicKey.Copy(priv)
|
|
1943
2219
|
|
|
1944
|
-
#
|
|
1945
|
-
msg =
|
|
1946
|
-
cipher = pub.Encrypt(msg)
|
|
1947
|
-
plain
|
|
2220
|
+
# Safe Encrypt & decrypt
|
|
2221
|
+
msg = b'xyz'
|
|
2222
|
+
cipher = pub.Encrypt(msg, associated_data=b'aad')
|
|
2223
|
+
plain = priv.Decrypt(cipher, associated_data=b'aad')
|
|
1948
2224
|
assert plain == msg
|
|
1949
2225
|
|
|
1950
|
-
#
|
|
1951
|
-
|
|
1952
|
-
assert pub.
|
|
1953
|
-
```
|
|
2226
|
+
# Safe Sign & verify
|
|
2227
|
+
signature = priv.Sign(msg) # can also have associated_data, optionally
|
|
2228
|
+
assert pub.Verify(msg, signature)
|
|
1954
2229
|
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
```py
|
|
1962
|
-
# ➌ Private key generation
|
|
1963
|
-
priv = elgamal.ElGamalPrivateKey.New(shared)
|
|
1964
|
-
|
|
1965
|
-
# Decryption
|
|
1966
|
-
plain = priv.Decrypt(cipher)
|
|
2230
|
+
# Raw Encryption
|
|
2231
|
+
msg = 42
|
|
2232
|
+
cipher = pub.RawEncrypt(msg)
|
|
2233
|
+
plain = priv.RawDecrypt(cipher)
|
|
2234
|
+
assert plain == msg
|
|
1967
2235
|
|
|
1968
|
-
#
|
|
1969
|
-
sig = priv.
|
|
1970
|
-
assert pub.
|
|
2236
|
+
# Raw Signature verify
|
|
2237
|
+
sig = priv.RawSign(msg)
|
|
2238
|
+
assert pub.RawVerify(msg, sig)
|
|
1971
2239
|
```
|
|
1972
2240
|
|
|
1973
|
-
- `decrypt_exp`: secret exponent `3 ≤ e < p`
|
|
1974
|
-
- `Decrypt((c1, c2))` recovers `m`
|
|
1975
|
-
- `Sign(m)` returns `(s1, s2)`; both satisfy the modulus constraints
|
|
1976
|
-
|
|
1977
2241
|
Key points:
|
|
1978
2242
|
|
|
1979
2243
|
- **Security parameters**:
|
|
@@ -1997,20 +2261,25 @@ This is **raw DSA** over a prime field — **no hashing or padding**. You sign/v
|
|
|
1997
2261
|
```py
|
|
1998
2262
|
from transcrypto import dsa
|
|
1999
2263
|
|
|
2000
|
-
#
|
|
2264
|
+
# Shared parameters (p, q, g)
|
|
2001
2265
|
shared = dsa.DSASharedPublicKey.New(p_bits=1024, q_bits=160)
|
|
2002
2266
|
print(shared.prime_modulus) # p
|
|
2003
2267
|
print(shared.prime_seed) # q (q | p-1)
|
|
2004
2268
|
print(shared.group_base) # g
|
|
2005
2269
|
|
|
2006
|
-
#
|
|
2270
|
+
# Individual key pair
|
|
2007
2271
|
priv = dsa.DSAPrivateKey.New(shared)
|
|
2008
2272
|
pub = dsa.DSAPublicKey.Copy(priv)
|
|
2009
2273
|
|
|
2010
|
-
#
|
|
2274
|
+
# Safe Sign & verify
|
|
2275
|
+
msg = b'xyz'
|
|
2276
|
+
signature = priv.Sign(msg) # can also have associated_data, optionally
|
|
2277
|
+
assert pub.Verify(msg, signature)
|
|
2278
|
+
|
|
2279
|
+
# Raw Sign & verify (message must be 1 ≤ m < q)
|
|
2011
2280
|
msg = 123456789 % shared.prime_seed
|
|
2012
|
-
sig = priv.
|
|
2013
|
-
assert pub.
|
|
2281
|
+
sig = priv.RawSign(msg)
|
|
2282
|
+
assert pub.RawVerify(msg, sig)
|
|
2014
2283
|
```
|
|
2015
2284
|
|
|
2016
2285
|
- ranges:
|
|
@@ -2044,13 +2313,13 @@ This is a way of bidding on some commitment (the `secret`) that can be cryptogra
|
|
|
2044
2313
|
from transcrypto import base
|
|
2045
2314
|
|
|
2046
2315
|
# Generate the private and public bids
|
|
2047
|
-
bid_priv = base.
|
|
2048
|
-
bid_pub = base.
|
|
2316
|
+
bid_priv = base.PrivateBid512.New(secret) # this one you keep private
|
|
2317
|
+
bid_pub = base.PublicBid512.Copy(bid_priv) # this one you publish
|
|
2049
2318
|
|
|
2050
2319
|
# Checking that a bid is genuine requires the public bid and knowing the nonce and the secret:
|
|
2051
2320
|
print(bid_pub.VerifyBid(private_key, secret_bid)) # these come from a divulged private bid
|
|
2052
2321
|
# of course, you want to also make sure the provided private data matches your version of it, e.g.:
|
|
2053
|
-
bid_pub_expected = base.
|
|
2322
|
+
bid_pub_expected = base.PublicBid512.Copy(bid_priv)
|
|
2054
2323
|
print(bid_pub == bid_pub_expected)
|
|
2055
2324
|
```
|
|
2056
2325
|
|
|
@@ -2063,8 +2332,8 @@ This is the information-theoretic SSS but with no authentication or binding betw
|
|
|
2063
2332
|
```py
|
|
2064
2333
|
from transcrypto import sss
|
|
2065
2334
|
|
|
2066
|
-
#
|
|
2067
|
-
#
|
|
2335
|
+
# Generate parameters: at least 3 of 5 shares needed,
|
|
2336
|
+
# coefficients & modulus are 128-bit primes
|
|
2068
2337
|
priv = sss.ShamirSharedSecretPrivate.New(minimum_shares=3, bit_length=128)
|
|
2069
2338
|
pub = sss.ShamirSharedSecretPublic.Copy(priv) # what you publish
|
|
2070
2339
|
|
|
@@ -2072,11 +2341,19 @@ print(f'threshold : {pub.minimum}')
|
|
|
2072
2341
|
print(f'prime mod : {pub.modulus}')
|
|
2073
2342
|
print(f'poly coefficients: {priv.polynomial}') # keep these private!
|
|
2074
2343
|
|
|
2075
|
-
#
|
|
2344
|
+
# Safe Issuing shares
|
|
2345
|
+
|
|
2346
|
+
secret = b'xyz'
|
|
2347
|
+
# Generate 5 shares, each has a copy of the encrypted secret
|
|
2348
|
+
five_shares = priv.MakeDataShares(secret, 5)
|
|
2349
|
+
for sh in five_shares:
|
|
2350
|
+
print(sh)
|
|
2351
|
+
|
|
2352
|
+
# Raw Issuing shares
|
|
2076
2353
|
|
|
2077
2354
|
secret = 0xC0FFEE
|
|
2078
2355
|
# Generate an unlimited stream; here we take 5
|
|
2079
|
-
five_shares = list(priv.
|
|
2356
|
+
five_shares = list(priv.RawShares(secret, max_shares=5))
|
|
2080
2357
|
for sh in five_shares:
|
|
2081
2358
|
print(f'share {sh.share_key} → {sh.share_value}')
|
|
2082
2359
|
```
|
|
@@ -2084,10 +2361,18 @@ for sh in five_shares:
|
|
|
2084
2361
|
A single share object looks like `sss.ShamirSharePrivate(minimum=3, modulus=..., share_key=42, share_value=123456789)`.
|
|
2085
2362
|
|
|
2086
2363
|
```py
|
|
2087
|
-
#
|
|
2364
|
+
# Safe Re-constructing the secret
|
|
2365
|
+
secret = b'xyz'
|
|
2366
|
+
five_shares = priv.MakeDataShares(secret, 5)
|
|
2367
|
+
subset = five_shares[:3] # any 3 distinct shares
|
|
2368
|
+
recovered = subset[0].RecoverData(subset) # each share has the encrypted data, so you ask it to join with the others
|
|
2369
|
+
assert recovered == secret
|
|
2088
2370
|
|
|
2371
|
+
# Raw Re-constructing the secret
|
|
2372
|
+
secret = 0xC0FFEE
|
|
2373
|
+
five_shares = list(priv.RawShares(secret, max_shares=5))
|
|
2089
2374
|
subset = five_shares[:3] # any 3 distinct shares
|
|
2090
|
-
recovered = pub.
|
|
2375
|
+
recovered = pub.RawRecoverSecret(subset)
|
|
2091
2376
|
assert recovered == secret
|
|
2092
2377
|
```
|
|
2093
2378
|
|
|
@@ -2095,23 +2380,23 @@ If you supply fewer than minimum shares you get a `CryptoError`, unless you expl
|
|
|
2095
2380
|
|
|
2096
2381
|
```py
|
|
2097
2382
|
try:
|
|
2098
|
-
pub.
|
|
2383
|
+
pub.RawRecoverSecret(five_shares[:2]) # raises
|
|
2099
2384
|
except Exception as e:
|
|
2100
2385
|
print(e) # "unrecoverable secret …"
|
|
2101
2386
|
|
|
2102
2387
|
# Force the interpolation even with 2 points (gives a wrong secret, of course)
|
|
2103
|
-
print(pub.
|
|
2388
|
+
print(pub.RawRecoverSecret(five_shares[:2], force_recover=True))
|
|
2104
2389
|
|
|
2105
2390
|
# Checking that a share is genuine
|
|
2106
2391
|
|
|
2107
2392
|
share = five_shares[0]
|
|
2108
|
-
ok = priv.
|
|
2393
|
+
ok = priv.RawVerifyShare(secret, share) # ▶ True
|
|
2109
2394
|
tampered = sss.ShamirSharePrivate(
|
|
2110
2395
|
minimum=share.minimum,
|
|
2111
2396
|
modulus=share.modulus,
|
|
2112
2397
|
share_key=share.share_key,
|
|
2113
2398
|
share_value=(share.share_value + 1) % share.modulus)
|
|
2114
|
-
print(priv.
|
|
2399
|
+
print(priv.RawVerifyShare(secret, tampered)) # ▶ False
|
|
2115
2400
|
```
|
|
2116
2401
|
|
|
2117
2402
|
## Appendix: Development Instructions
|
|
@@ -2179,7 +2464,7 @@ To activate like a regular environment do:
|
|
|
2179
2464
|
```sh
|
|
2180
2465
|
poetry env activate
|
|
2181
2466
|
# will print activation command which you next execute, or you can do:
|
|
2182
|
-
source .
|
|
2467
|
+
source .venv/bin/activate # if .venv is local to the project
|
|
2183
2468
|
source "$(poetry env info --path)/bin/activate" # for other paths
|
|
2184
2469
|
|
|
2185
2470
|
pytest # or other commands
|
|
@@ -2247,11 +2532,31 @@ poetry run transcrypto doc md > CLI.md
|
|
|
2247
2532
|
You can find the 10 top slowest tests by running:
|
|
2248
2533
|
|
|
2249
2534
|
```sh
|
|
2250
|
-
poetry run pytest -vvv -q --durations=
|
|
2535
|
+
poetry run pytest -vvv -q --durations=30
|
|
2536
|
+
|
|
2537
|
+
poetry run pytest -vvv -q --durations=30 -m "not slow" # find slow > 0.1s
|
|
2538
|
+
poetry run pytest -vvv -q --durations=30 -m "not veryslow" # find veryslow > 1s
|
|
2539
|
+
|
|
2540
|
+
poetry run pytest -vvv -q --durations=30 -m slow # check
|
|
2541
|
+
poetry run pytest -vvv -q --durations=30 -m veryslow # check
|
|
2251
2542
|
```
|
|
2252
2543
|
|
|
2253
|
-
You can search for flaky tests by running all tests 100 times:
|
|
2544
|
+
You can search for flaky tests by running all tests 100 times, or more:
|
|
2254
2545
|
|
|
2255
2546
|
```sh
|
|
2256
2547
|
poetry run pytest --flake-finder --flake-runs=100
|
|
2548
|
+
poetry run pytest --flake-finder --flake-runs=500 -m "not veryslow"
|
|
2549
|
+
poetry run pytest --flake-finder --flake-runs=10000 -m "not slow"
|
|
2257
2550
|
```
|
|
2551
|
+
|
|
2552
|
+
You can instrument your code to find bottlenecks:
|
|
2553
|
+
|
|
2554
|
+
```sh
|
|
2555
|
+
$ source .venv/bin/activate
|
|
2556
|
+
$ which transcrypto
|
|
2557
|
+
/path/to/.venv/bin/transcrypto # place this in the command below:
|
|
2558
|
+
$ pyinstrument -r html -o dsa_shared.html -- /path/to/.venv/bin/transcrypto -p rsa-key rsa new
|
|
2559
|
+
$ deactivate
|
|
2560
|
+
```
|
|
2561
|
+
|
|
2562
|
+
Hint: 85%+ is inside `MillerRabinIsPrime()`/`ModExp()`...
|