transcrypto 1.1.1__py3-none-any.whl → 1.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.
- transcrypto/aes.py +4 -3
- transcrypto/base.py +84 -30
- transcrypto/dsa.py +153 -19
- transcrypto/elgamal.py +224 -28
- transcrypto/rsa.py +203 -19
- transcrypto/sss.py +159 -20
- transcrypto/transcrypto.py +401 -178
- {transcrypto-1.1.1.dist-info → transcrypto-1.2.0.dist-info}/METADATA +684 -426
- transcrypto-1.2.0.dist-info/RECORD +15 -0
- transcrypto-1.1.1.dist-info/RECORD +0 -15
- {transcrypto-1.1.1.dist-info → transcrypto-1.2.0.dist-info}/WHEEL +0 -0
- {transcrypto-1.1.1.dist-info → transcrypto-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {transcrypto-1.1.1.dist-info → transcrypto-1.2.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.2.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
|
|
@@ -18,7 +18,7 @@ Dynamic: license-file
|
|
|
18
18
|
|
|
19
19
|
# TransCrypto
|
|
20
20
|
|
|
21
|
-
Basic
|
|
21
|
+
Basic cryptography primitives implementation, a companion to *"Criptografia, Métodos e Algoritmos"*.
|
|
22
22
|
|
|
23
23
|
Started in July/2025, by Daniel Balparda. Since version 1.0.2 it is PyPI package:
|
|
24
24
|
|
|
@@ -61,69 +61,66 @@ 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
|
|
65
|
-
- [`rsa
|
|
66
|
-
- [`rsa
|
|
67
|
-
- [`rsa
|
|
64
|
+
- [`rsa rawencrypt`](#rsa-rawencrypt)
|
|
65
|
+
- [`rsa rawdecrypt`](#rsa-rawdecrypt)
|
|
66
|
+
- [`rsa rawsign`](#rsa-rawsign)
|
|
67
|
+
- [`rsa rawverify`](#rsa-rawverify)
|
|
68
68
|
- [`elgamal`](#elgamal)
|
|
69
69
|
- [`elgamal shared`](#elgamal-shared)
|
|
70
70
|
- [`elgamal new`](#elgamal-new)
|
|
71
|
-
- [`elgamal
|
|
72
|
-
- [`elgamal
|
|
73
|
-
- [`elgamal
|
|
74
|
-
- [`elgamal
|
|
71
|
+
- [`elgamal rawencrypt`](#elgamal-rawencrypt)
|
|
72
|
+
- [`elgamal rawdecrypt`](#elgamal-rawdecrypt)
|
|
73
|
+
- [`elgamal rawsign`](#elgamal-rawsign)
|
|
74
|
+
- [`elgamal rawverify`](#elgamal-rawverify)
|
|
75
75
|
- [`dsa`](#dsa)
|
|
76
76
|
- [`dsa shared`](#dsa-shared)
|
|
77
77
|
- [`dsa new`](#dsa-new)
|
|
78
|
-
- [`dsa
|
|
79
|
-
- [`dsa
|
|
78
|
+
- [`dsa rawsign`](#dsa-rawsign)
|
|
79
|
+
- [`dsa rawverify`](#dsa-rawverify)
|
|
80
80
|
- [`bid`](#bid)
|
|
81
81
|
- [`bid new`](#bid-new)
|
|
82
82
|
- [`bid verify`](#bid-verify)
|
|
83
83
|
- [`sss`](#sss)
|
|
84
84
|
- [`sss new`](#sss-new)
|
|
85
|
-
- [`sss
|
|
86
|
-
- [`sss
|
|
87
|
-
- [`sss
|
|
85
|
+
- [`sss rawshares`](#sss-rawshares)
|
|
86
|
+
- [`sss rawrecover`](#sss-rawrecover)
|
|
87
|
+
- [`sss rawverify`](#sss-rawverify)
|
|
88
88
|
- [`doc`](#doc)
|
|
89
89
|
- [`doc md`](#doc-md)
|
|
90
90
|
- [Base Library](#base-library)
|
|
91
91
|
- [Humanized Sizes (IEC binary)](#humanized-sizes-iec-binary)
|
|
92
92
|
- [Humanized Decimal Quantities (SI)](#humanized-decimal-quantities-si)
|
|
93
93
|
- [Humanized Durations](#humanized-durations)
|
|
94
|
+
- [Execution Timing](#execution-timing)
|
|
95
|
+
- [Context manager](#context-manager)
|
|
96
|
+
- [Decorator](#decorator)
|
|
97
|
+
- [Manual use](#manual-use)
|
|
98
|
+
- [Key points](#key-points)
|
|
99
|
+
- [Serialization Pipeline](#serialization-pipeline)
|
|
100
|
+
- [Serialize](#serialize)
|
|
101
|
+
- [DeSerialize](#deserialize)
|
|
94
102
|
- [Cryptographically Secure Randomness](#cryptographically-secure-randomness)
|
|
95
103
|
- [Fixed-size random integers](#fixed-size-random-integers)
|
|
96
104
|
- [Uniform random integers in a range](#uniform-random-integers-in-a-range)
|
|
97
105
|
- [In-place secure shuffle](#in-place-secure-shuffle)
|
|
98
106
|
- [Random byte strings](#random-byte-strings)
|
|
99
107
|
- [Computing the Greatest Common Divisor](#computing-the-greatest-common-divisor)
|
|
108
|
+
- [Fast Modular Arithmetic](#fast-modular-arithmetic)
|
|
109
|
+
- [Chinese Remainder Theorem (CRT) – Pair](#chinese-remainder-theorem-crt--pair)
|
|
110
|
+
- [Modular Polynomials \& Lagrange Interpolation](#modular-polynomials--lagrange-interpolation)
|
|
111
|
+
- [Primality testing \& Prime generators, Mersenne primes](#primality-testing--prime-generators-mersenne-primes)
|
|
100
112
|
- [Cryptographic Hashing](#cryptographic-hashing)
|
|
101
113
|
- [SHA-256 hashing](#sha-256-hashing)
|
|
102
114
|
- [SHA-512 hashing](#sha-512-hashing)
|
|
103
115
|
- [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
116
|
- [Symmetric Encryption Interface](#symmetric-encryption-interface)
|
|
110
|
-
- [Serialization Pipeline](#serialization-pipeline)
|
|
111
|
-
- [Serialize](#serialize)
|
|
112
|
-
- [DeSerialize](#deserialize)
|
|
113
117
|
- [Crypto Objects General Properties (`CryptoKey`)](#crypto-objects-general-properties-cryptokey)
|
|
114
118
|
- [AES-256 Symmetric Encryption](#aes-256-symmetric-encryption)
|
|
115
119
|
- [Key creation](#key-creation)
|
|
116
120
|
- [AES-256 + GCM (default)](#aes-256--gcm-default)
|
|
117
121
|
- [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
122
|
- [RSA (Rivest-Shamir-Adleman) Public Cryptography](#rsa-rivest-shamir-adleman-public-cryptography)
|
|
123
123
|
- [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
124
|
- [DSA (Digital Signature Algorithm)](#dsa-digital-signature-algorithm)
|
|
128
125
|
- [Security notes](#security-notes)
|
|
129
126
|
- [Advanced: custom primes generator](#advanced-custom-primes-generator)
|
|
@@ -144,13 +141,13 @@ Unless required by applicable law or agreed to in writing, software distributed
|
|
|
144
141
|
|
|
145
142
|
## Design assumptions / Disclaimers
|
|
146
143
|
|
|
147
|
-
- The library is built to have reference, reliable, simple implementations of math and crypto primitives.
|
|
144
|
+
- 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.
|
|
145
|
+
- 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
146
|
- 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.
|
|
147
|
+
- 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.
|
|
148
|
+
- *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
149
|
|
|
153
|
-
|
|
150
|
+
All that being said, extreme care was taken that this is a good library with a solid safe implementation. *Have fun!*
|
|
154
151
|
|
|
155
152
|
## Install
|
|
156
153
|
|
|
@@ -207,11 +204,11 @@ poetry run transcrypto <command> [sub-command] [options...]
|
|
|
207
204
|
- **`mod`** — `poetry run transcrypto mod [-h] {inv,div,exp,poly,lagrange,crt} ...`
|
|
208
205
|
- **`hash`** — `poetry run transcrypto hash [-h] {sha256,sha512,file} ...`
|
|
209
206
|
- **`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} ...`
|
|
207
|
+
- **`rsa`** — `poetry run transcrypto rsa [-h] {new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...`
|
|
208
|
+
- **`elgamal`** — `poetry run transcrypto elgamal [-h] {shared,new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...`
|
|
209
|
+
- **`dsa`** — `poetry run transcrypto dsa [-h] {shared,new,rawsign,sign,rawverify,verify} ...`
|
|
213
210
|
- **`bid`** — `poetry run transcrypto bid [-h] {new,verify} ...`
|
|
214
|
-
- **`sss`** — `poetry run transcrypto sss [-h] {new,shares,recover,
|
|
211
|
+
- **`sss`** — `poetry run transcrypto sss [-h] {new,rawshares,shares,rawrecover,recover,rawverify} ...`
|
|
215
212
|
- **`doc`** — `poetry run transcrypto doc [-h] {md} ...`
|
|
216
213
|
|
|
217
214
|
```bash
|
|
@@ -252,24 +249,24 @@ Examples:
|
|
|
252
249
|
|
|
253
250
|
# --- RSA ---
|
|
254
251
|
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
|
|
252
|
+
poetry run transcrypto -p rsa-key.pub rsa rawencrypt <plaintext>
|
|
253
|
+
poetry run transcrypto -p rsa-key.priv rsa rawdecrypt <ciphertext>
|
|
254
|
+
poetry run transcrypto -p rsa-key.priv rsa rawsign <message>
|
|
255
|
+
poetry run transcrypto -p rsa-key.pub rsa rawverify <message> <signature>
|
|
259
256
|
|
|
260
257
|
# --- ElGamal ---
|
|
261
258
|
poetry run transcrypto -p eg-key elgamal shared --bits 2048
|
|
262
259
|
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
|
|
260
|
+
poetry run transcrypto -p eg-key.pub elgamal rawencrypt <plaintext>
|
|
261
|
+
poetry run transcrypto -p eg-key.priv elgamal rawdecrypt <c1:c2>
|
|
262
|
+
poetry run transcrypto -p eg-key.priv elgamal rawsign <message>
|
|
263
|
+
poetry run transcrypto-p eg-key.pub elgamal rawverify <message> <s1:s2>
|
|
267
264
|
|
|
268
265
|
# --- DSA ---
|
|
269
266
|
poetry run transcrypto -p dsa-key dsa shared --p-bits 2048 --q-bits 256
|
|
270
267
|
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
|
|
268
|
+
poetry run transcrypto -p dsa-key.priv dsa rawsign <message>
|
|
269
|
+
poetry run transcrypto -p dsa-key.pub dsa rawverify <message> <s1:s2>
|
|
273
270
|
|
|
274
271
|
# --- Public Bid ---
|
|
275
272
|
poetry run transcrypto --bin bid new "tomorrow it will rain"
|
|
@@ -277,9 +274,9 @@ Examples:
|
|
|
277
274
|
|
|
278
275
|
# --- Shamir Secret Sharing (SSS) ---
|
|
279
276
|
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
|
|
277
|
+
poetry run transcrypto -p sss-key sss rawshares <secret> 5
|
|
278
|
+
poetry run transcrypto -p sss-key sss rawrecover
|
|
279
|
+
poetry run transcrypto -p sss-key sss rawverify <secret>
|
|
283
280
|
```
|
|
284
281
|
|
|
285
282
|
---
|
|
@@ -850,10 +847,11 @@ $ poetry run transcrypto --b64 aes ecb -k DbWJ_ZrknLEEIoq_NpoCQwHYfjskGokpueN2O_
|
|
|
850
847
|
|
|
851
848
|
### `rsa`
|
|
852
849
|
|
|
853
|
-
|
|
850
|
+
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
851
|
|
|
855
852
|
```bash
|
|
856
|
-
poetry run transcrypto rsa [-h]
|
|
853
|
+
poetry run transcrypto rsa [-h]
|
|
854
|
+
{new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...
|
|
857
855
|
```
|
|
858
856
|
|
|
859
857
|
#### `rsa new`
|
|
@@ -875,12 +873,12 @@ $ poetry run transcrypto -p rsa-key rsa new --bits 64 # NEVER use such a small
|
|
|
875
873
|
RSA private/public keys saved to 'rsa-key.priv/.pub'
|
|
876
874
|
```
|
|
877
875
|
|
|
878
|
-
#### `rsa
|
|
876
|
+
#### `rsa rawencrypt`
|
|
879
877
|
|
|
880
|
-
|
|
878
|
+
Raw encrypt *integer* `message` with public key (BEWARE: no OAEP/PSS padding or validation).
|
|
881
879
|
|
|
882
880
|
```bash
|
|
883
|
-
poetry run transcrypto rsa
|
|
881
|
+
poetry run transcrypto rsa rawencrypt [-h] message
|
|
884
882
|
```
|
|
885
883
|
|
|
886
884
|
| Option/Arg | Description |
|
|
@@ -890,16 +888,36 @@ poetry run transcrypto rsa encrypt [-h] message
|
|
|
890
888
|
**Example:**
|
|
891
889
|
|
|
892
890
|
```bash
|
|
893
|
-
$ poetry run transcrypto -p rsa-key.pub rsa
|
|
891
|
+
$ poetry run transcrypto -p rsa-key.pub rsa rawencrypt 999
|
|
894
892
|
6354905961171348600
|
|
895
893
|
```
|
|
896
894
|
|
|
897
|
-
#### `rsa
|
|
895
|
+
#### `rsa encrypt`
|
|
896
|
+
|
|
897
|
+
Encrypt `message` with public key.
|
|
898
|
+
|
|
899
|
+
```bash
|
|
900
|
+
poetry run transcrypto rsa encrypt [-h] [-a AAD] plaintext
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
| Option/Arg | Description |
|
|
904
|
+
|---|---|
|
|
905
|
+
| `plaintext` | Message to encrypt [type: str] |
|
|
906
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
907
|
+
|
|
908
|
+
**Example:**
|
|
909
|
+
|
|
910
|
+
```bash
|
|
911
|
+
$ poetry run transcrypto --bin --out-b64 -p rsa-key.pub rsa encrypt "abcde" -a "xyz"
|
|
912
|
+
AO6knI6xwq6TGR…Qy22jiFhXi1eQ==
|
|
913
|
+
```
|
|
898
914
|
|
|
899
|
-
|
|
915
|
+
#### `rsa rawdecrypt`
|
|
916
|
+
|
|
917
|
+
Raw decrypt *integer* `ciphertext` with private key (BEWARE: no OAEP/PSS padding or validation).
|
|
900
918
|
|
|
901
919
|
```bash
|
|
902
|
-
poetry run transcrypto rsa
|
|
920
|
+
poetry run transcrypto rsa rawdecrypt [-h] ciphertext
|
|
903
921
|
```
|
|
904
922
|
|
|
905
923
|
| Option/Arg | Description |
|
|
@@ -909,16 +927,36 @@ poetry run transcrypto rsa decrypt [-h] ciphertext
|
|
|
909
927
|
**Example:**
|
|
910
928
|
|
|
911
929
|
```bash
|
|
912
|
-
$ poetry run transcrypto -p rsa-key.priv rsa
|
|
930
|
+
$ poetry run transcrypto -p rsa-key.priv rsa rawdecrypt 6354905961171348600
|
|
913
931
|
999
|
|
914
932
|
```
|
|
915
933
|
|
|
916
|
-
#### `rsa
|
|
934
|
+
#### `rsa decrypt`
|
|
935
|
+
|
|
936
|
+
Decrypt `ciphertext` with private key.
|
|
937
|
+
|
|
938
|
+
```bash
|
|
939
|
+
poetry run transcrypto rsa decrypt [-h] [-a AAD] ciphertext
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
| Option/Arg | Description |
|
|
943
|
+
|---|---|
|
|
944
|
+
| `ciphertext` | Ciphertext to decrypt [type: str] |
|
|
945
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
|
|
946
|
+
|
|
947
|
+
**Example:**
|
|
948
|
+
|
|
949
|
+
```bash
|
|
950
|
+
$ poetry run transcrypto --b64 --out-bin -p rsa-key.priv rsa decrypt "AO6knI6xwq6TGR…Qy22jiFhXi1eQ==" -a "eHl6"
|
|
951
|
+
abcde
|
|
952
|
+
```
|
|
917
953
|
|
|
918
|
-
|
|
954
|
+
#### `rsa rawsign`
|
|
955
|
+
|
|
956
|
+
Raw sign *integer* `message` with private key (BEWARE: no OAEP/PSS padding or validation).
|
|
919
957
|
|
|
920
958
|
```bash
|
|
921
|
-
poetry run transcrypto rsa
|
|
959
|
+
poetry run transcrypto rsa rawsign [-h] message
|
|
922
960
|
```
|
|
923
961
|
|
|
924
962
|
| Option/Arg | Description |
|
|
@@ -928,16 +966,36 @@ poetry run transcrypto rsa sign [-h] message
|
|
|
928
966
|
**Example:**
|
|
929
967
|
|
|
930
968
|
```bash
|
|
931
|
-
$ poetry run transcrypto -p rsa-key.priv rsa
|
|
969
|
+
$ poetry run transcrypto -p rsa-key.priv rsa rawsign 999
|
|
932
970
|
7632909108672871784
|
|
933
971
|
```
|
|
934
972
|
|
|
935
|
-
#### `rsa
|
|
973
|
+
#### `rsa sign`
|
|
974
|
+
|
|
975
|
+
Sign `message` with private key.
|
|
976
|
+
|
|
977
|
+
```bash
|
|
978
|
+
poetry run transcrypto rsa sign [-h] [-a AAD] message
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
| Option/Arg | Description |
|
|
982
|
+
|---|---|
|
|
983
|
+
| `message` | Message to sign [type: str] |
|
|
984
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
985
|
+
|
|
986
|
+
**Example:**
|
|
987
|
+
|
|
988
|
+
```bash
|
|
989
|
+
$ poetry run transcrypto --bin --out-b64 -p rsa-key.priv rsa sign "xyz"
|
|
990
|
+
91TS7gC6LORiL…6RD23Aejsfxlw==
|
|
991
|
+
```
|
|
936
992
|
|
|
937
|
-
|
|
993
|
+
#### `rsa rawverify`
|
|
994
|
+
|
|
995
|
+
Raw verify *integer* `signature` for *integer* `message` with public key (BEWARE: no OAEP/PSS padding or validation).
|
|
938
996
|
|
|
939
997
|
```bash
|
|
940
|
-
poetry run transcrypto rsa
|
|
998
|
+
poetry run transcrypto rsa rawverify [-h] message signature
|
|
941
999
|
```
|
|
942
1000
|
|
|
943
1001
|
| Option/Arg | Description |
|
|
@@ -948,9 +1006,32 @@ poetry run transcrypto rsa verify [-h] message signature
|
|
|
948
1006
|
**Example:**
|
|
949
1007
|
|
|
950
1008
|
```bash
|
|
951
|
-
$ poetry run transcrypto -p rsa-key.pub rsa
|
|
1009
|
+
$ poetry run transcrypto -p rsa-key.pub rsa rawverify 999 7632909108672871784
|
|
1010
|
+
RSA signature: OK
|
|
1011
|
+
$ poetry run transcrypto -p rsa-key.pub rsa rawverify 999 7632909108672871785
|
|
1012
|
+
RSA signature: INVALID
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
#### `rsa verify`
|
|
1016
|
+
|
|
1017
|
+
Verify `signature` for `message` with public key.
|
|
1018
|
+
|
|
1019
|
+
```bash
|
|
1020
|
+
poetry run transcrypto rsa verify [-h] [-a AAD] message signature
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
| Option/Arg | Description |
|
|
1024
|
+
|---|---|
|
|
1025
|
+
| `message` | Message that was signed earlier [type: str] |
|
|
1026
|
+
| `signature` | Putative signature for `message` [type: str] |
|
|
1027
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during signing) [type: str] |
|
|
1028
|
+
|
|
1029
|
+
**Example:**
|
|
1030
|
+
|
|
1031
|
+
```bash
|
|
1032
|
+
$ poetry run transcrypto --b64 -p rsa-key.pub rsa verify "eHl6" "91TS7gC6LORiL…6RD23Aejsfxlw=="
|
|
952
1033
|
RSA signature: OK
|
|
953
|
-
$ poetry run transcrypto -p rsa-key.pub rsa verify
|
|
1034
|
+
$ poetry run transcrypto --b64 -p rsa-key.pub rsa verify "eLl6" "91TS7gC6LORiL…6RD23Aejsfxlw=="
|
|
954
1035
|
RSA signature: INVALID
|
|
955
1036
|
```
|
|
956
1037
|
|
|
@@ -958,11 +1039,11 @@ RSA signature: INVALID
|
|
|
958
1039
|
|
|
959
1040
|
### `elgamal`
|
|
960
1041
|
|
|
961
|
-
|
|
1042
|
+
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
1043
|
|
|
963
1044
|
```bash
|
|
964
1045
|
poetry run transcrypto elgamal [-h]
|
|
965
|
-
{shared,new,encrypt,decrypt,sign,verify} ...
|
|
1046
|
+
{shared,new,rawencrypt,encrypt,rawdecrypt,decrypt,rawsign,sign,rawverify,verify} ...
|
|
966
1047
|
```
|
|
967
1048
|
|
|
968
1049
|
#### `elgamal shared`
|
|
@@ -999,12 +1080,12 @@ $ poetry run transcrypto -p eg-key elgamal new
|
|
|
999
1080
|
El-Gamal private/public keys saved to 'eg-key.priv/.pub'
|
|
1000
1081
|
```
|
|
1001
1082
|
|
|
1002
|
-
#### `elgamal
|
|
1083
|
+
#### `elgamal rawencrypt`
|
|
1003
1084
|
|
|
1004
|
-
|
|
1085
|
+
Raw encrypt *integer* `message` with public key (BEWARE: no ECIES-style KEM/DEM padding or validation).
|
|
1005
1086
|
|
|
1006
1087
|
```bash
|
|
1007
|
-
poetry run transcrypto elgamal
|
|
1088
|
+
poetry run transcrypto elgamal rawencrypt [-h] message
|
|
1008
1089
|
```
|
|
1009
1090
|
|
|
1010
1091
|
| Option/Arg | Description |
|
|
@@ -1014,16 +1095,36 @@ poetry run transcrypto elgamal encrypt [-h] message
|
|
|
1014
1095
|
**Example:**
|
|
1015
1096
|
|
|
1016
1097
|
```bash
|
|
1017
|
-
$ poetry run transcrypto -p eg-key.pub elgamal
|
|
1098
|
+
$ poetry run transcrypto -p eg-key.pub elgamal rawencrypt 999
|
|
1018
1099
|
2948854810728206041:15945988196340032688
|
|
1019
1100
|
```
|
|
1020
1101
|
|
|
1021
|
-
#### `elgamal
|
|
1102
|
+
#### `elgamal encrypt`
|
|
1103
|
+
|
|
1104
|
+
Encrypt `message` with public key.
|
|
1105
|
+
|
|
1106
|
+
```bash
|
|
1107
|
+
poetry run transcrypto elgamal encrypt [-h] [-a AAD] plaintext
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
| Option/Arg | Description |
|
|
1111
|
+
|---|---|
|
|
1112
|
+
| `plaintext` | Message to encrypt [type: str] |
|
|
1113
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1022
1114
|
|
|
1023
|
-
|
|
1115
|
+
**Example:**
|
|
1116
|
+
|
|
1117
|
+
```bash
|
|
1118
|
+
$ poetry run transcrypto --bin --out-b64 -p eg-key.pub elgamal encrypt "abcde" -a "xyz"
|
|
1119
|
+
CdFvoQ_IIPFPZLua…kqjhcUTspISxURg==
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
#### `elgamal rawdecrypt`
|
|
1123
|
+
|
|
1124
|
+
Raw decrypt *integer* `ciphertext` with private key (BEWARE: no ECIES-style KEM/DEM padding or validation).
|
|
1024
1125
|
|
|
1025
1126
|
```bash
|
|
1026
|
-
poetry run transcrypto elgamal
|
|
1127
|
+
poetry run transcrypto elgamal rawdecrypt [-h] ciphertext
|
|
1027
1128
|
```
|
|
1028
1129
|
|
|
1029
1130
|
| Option/Arg | Description |
|
|
@@ -1033,16 +1134,36 @@ poetry run transcrypto elgamal decrypt [-h] ciphertext
|
|
|
1033
1134
|
**Example:**
|
|
1034
1135
|
|
|
1035
1136
|
```bash
|
|
1036
|
-
$ poetry run transcrypto -p eg-key.priv elgamal
|
|
1137
|
+
$ poetry run transcrypto -p eg-key.priv elgamal rawdecrypt 2948854810728206041:15945988196340032688
|
|
1037
1138
|
999
|
|
1038
1139
|
```
|
|
1039
1140
|
|
|
1040
|
-
#### `elgamal
|
|
1141
|
+
#### `elgamal decrypt`
|
|
1142
|
+
|
|
1143
|
+
Decrypt `ciphertext` with private key.
|
|
1144
|
+
|
|
1145
|
+
```bash
|
|
1146
|
+
poetry run transcrypto elgamal decrypt [-h] [-a AAD] ciphertext
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
| Option/Arg | Description |
|
|
1150
|
+
|---|---|
|
|
1151
|
+
| `ciphertext` | Ciphertext to decrypt [type: str] |
|
|
1152
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during encryption) [type: str] |
|
|
1041
1153
|
|
|
1042
|
-
|
|
1154
|
+
**Example:**
|
|
1155
|
+
|
|
1156
|
+
```bash
|
|
1157
|
+
$ poetry run transcrypto --b64 --out-bin -p eg-key.priv elgamal decrypt "CdFvoQ_IIPFPZLua…kqjhcUTspISxURg==" -a "eHl6"
|
|
1158
|
+
abcde
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
#### `elgamal rawsign`
|
|
1162
|
+
|
|
1163
|
+
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
1164
|
|
|
1044
1165
|
```bash
|
|
1045
|
-
poetry run transcrypto elgamal
|
|
1166
|
+
poetry run transcrypto elgamal rawsign [-h] message
|
|
1046
1167
|
```
|
|
1047
1168
|
|
|
1048
1169
|
| Option/Arg | Description |
|
|
@@ -1052,16 +1173,36 @@ poetry run transcrypto elgamal sign [-h] message
|
|
|
1052
1173
|
**Example:**
|
|
1053
1174
|
|
|
1054
1175
|
```bash
|
|
1055
|
-
$ poetry run transcrypto -p eg-key.priv elgamal
|
|
1176
|
+
$ poetry run transcrypto -p eg-key.priv elgamal rawsign 999
|
|
1056
1177
|
4674885853217269088:14532144906178302633
|
|
1057
1178
|
```
|
|
1058
1179
|
|
|
1059
|
-
#### `elgamal
|
|
1180
|
+
#### `elgamal sign`
|
|
1181
|
+
|
|
1182
|
+
Sign message with private key.
|
|
1183
|
+
|
|
1184
|
+
```bash
|
|
1185
|
+
poetry run transcrypto elgamal sign [-h] [-a AAD] message
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
| Option/Arg | Description |
|
|
1189
|
+
|---|---|
|
|
1190
|
+
| `message` | Message to sign [type: str] |
|
|
1191
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1060
1192
|
|
|
1061
|
-
|
|
1193
|
+
**Example:**
|
|
1194
|
+
|
|
1195
|
+
```bash
|
|
1196
|
+
$ poetry run transcrypto --bin --out-b64 -p eg-key.priv elgamal sign "xyz"
|
|
1197
|
+
Xl4hlYK8SHVGw…0fCKJE1XVzA==
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
#### `elgamal rawverify`
|
|
1201
|
+
|
|
1202
|
+
Raw verify *integer* `signature` for *integer* `message` with public key (BEWARE: no ECIES-style KEM/DEM padding or validation).
|
|
1062
1203
|
|
|
1063
1204
|
```bash
|
|
1064
|
-
poetry run transcrypto elgamal
|
|
1205
|
+
poetry run transcrypto elgamal rawverify [-h] message signature
|
|
1065
1206
|
```
|
|
1066
1207
|
|
|
1067
1208
|
| Option/Arg | Description |
|
|
@@ -1072,9 +1213,32 @@ poetry run transcrypto elgamal verify [-h] message signature
|
|
|
1072
1213
|
**Example:**
|
|
1073
1214
|
|
|
1074
1215
|
```bash
|
|
1075
|
-
$ poetry run transcrypto -p eg-key.pub elgamal
|
|
1216
|
+
$ poetry run transcrypto -p eg-key.pub elgamal rawverify 999 4674885853217269088:14532144906178302633
|
|
1217
|
+
El-Gamal signature: OK
|
|
1218
|
+
$ poetry run transcrypto -p eg-key.pub elgamal rawverify 999 4674885853217269088:14532144906178302632
|
|
1219
|
+
El-Gamal signature: INVALID
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
#### `elgamal verify`
|
|
1223
|
+
|
|
1224
|
+
Verify `signature` for `message` with public key.
|
|
1225
|
+
|
|
1226
|
+
```bash
|
|
1227
|
+
poetry run transcrypto elgamal verify [-h] [-a AAD] message signature
|
|
1228
|
+
```
|
|
1229
|
+
|
|
1230
|
+
| Option/Arg | Description |
|
|
1231
|
+
|---|---|
|
|
1232
|
+
| `message` | Message that was signed earlier [type: str] |
|
|
1233
|
+
| `signature` | Putative signature for `message` [type: str] |
|
|
1234
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during signing) [type: str] |
|
|
1235
|
+
|
|
1236
|
+
**Example:**
|
|
1237
|
+
|
|
1238
|
+
```bash
|
|
1239
|
+
$ poetry run transcrypto --b64 -p eg-key.pub elgamal verify "eHl6" "Xl4hlYK8SHVGw…0fCKJE1XVzA=="
|
|
1076
1240
|
El-Gamal signature: OK
|
|
1077
|
-
$ poetry run transcrypto -p eg-key.pub elgamal verify
|
|
1241
|
+
$ poetry run transcrypto --b64 -p eg-key.pub elgamal verify "eLl6" "Xl4hlYK8SHVGw…0fCKJE1XVzA=="
|
|
1078
1242
|
El-Gamal signature: INVALID
|
|
1079
1243
|
```
|
|
1080
1244
|
|
|
@@ -1082,15 +1246,16 @@ El-Gamal signature: INVALID
|
|
|
1082
1246
|
|
|
1083
1247
|
### `dsa`
|
|
1084
1248
|
|
|
1085
|
-
|
|
1249
|
+
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
1250
|
|
|
1087
1251
|
```bash
|
|
1088
|
-
poetry run transcrypto dsa [-h]
|
|
1252
|
+
poetry run transcrypto dsa [-h]
|
|
1253
|
+
{shared,new,rawsign,sign,rawverify,verify} ...
|
|
1089
1254
|
```
|
|
1090
1255
|
|
|
1091
1256
|
#### `dsa shared`
|
|
1092
1257
|
|
|
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.
|
|
1258
|
+
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
1259
|
|
|
1095
1260
|
```bash
|
|
1096
1261
|
poetry run transcrypto dsa shared [-h] [--p-bits P_BITS]
|
|
@@ -1099,8 +1264,8 @@ poetry run transcrypto dsa shared [-h] [--p-bits P_BITS]
|
|
|
1099
1264
|
|
|
1100
1265
|
| Option/Arg | Description |
|
|
1101
1266
|
|---|---|
|
|
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:
|
|
1267
|
+
| `--p-bits` | Prime modulus (`p`) size in bits; the default is a safe size [type: int (default: 4096)] |
|
|
1268
|
+
| `--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
1269
|
|
|
1105
1270
|
**Example:**
|
|
1106
1271
|
|
|
@@ -1124,12 +1289,12 @@ $ poetry run transcrypto -p dsa-key dsa new
|
|
|
1124
1289
|
DSA private/public keys saved to 'dsa-key.priv/.pub'
|
|
1125
1290
|
```
|
|
1126
1291
|
|
|
1127
|
-
#### `dsa
|
|
1292
|
+
#### `dsa rawsign`
|
|
1128
1293
|
|
|
1129
|
-
|
|
1294
|
+
Raw sign *integer* message with private key (BEWARE: no ECDSA/EdDSA padding or validation). Output will 2 *integers* in a `s1:s2` format.
|
|
1130
1295
|
|
|
1131
1296
|
```bash
|
|
1132
|
-
poetry run transcrypto dsa
|
|
1297
|
+
poetry run transcrypto dsa rawsign [-h] message
|
|
1133
1298
|
```
|
|
1134
1299
|
|
|
1135
1300
|
| Option/Arg | Description |
|
|
@@ -1139,16 +1304,36 @@ poetry run transcrypto dsa sign [-h] message
|
|
|
1139
1304
|
**Example:**
|
|
1140
1305
|
|
|
1141
1306
|
```bash
|
|
1142
|
-
$ poetry run transcrypto -p dsa-key.priv dsa
|
|
1307
|
+
$ poetry run transcrypto -p dsa-key.priv dsa rawsign 999
|
|
1143
1308
|
2395961484:3435572290
|
|
1144
1309
|
```
|
|
1145
1310
|
|
|
1146
|
-
#### `dsa
|
|
1311
|
+
#### `dsa sign`
|
|
1312
|
+
|
|
1313
|
+
Sign message with private key.
|
|
1314
|
+
|
|
1315
|
+
```bash
|
|
1316
|
+
poetry run transcrypto dsa sign [-h] [-a AAD] message
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
| Option/Arg | Description |
|
|
1320
|
+
|---|---|
|
|
1321
|
+
| `message` | Message to sign [type: str] |
|
|
1322
|
+
| `-a, --aad` | Associated data (optional; has to be separately sent to receiver/stored) [type: str] |
|
|
1323
|
+
|
|
1324
|
+
**Example:**
|
|
1325
|
+
|
|
1326
|
+
```bash
|
|
1327
|
+
$ poetry run transcrypto --bin --out-b64 -p dsa-key.priv dsa sign "xyz"
|
|
1328
|
+
yq8InJVpViXh9…BD4par2XuA=
|
|
1329
|
+
```
|
|
1147
1330
|
|
|
1148
|
-
|
|
1331
|
+
#### `dsa rawverify`
|
|
1332
|
+
|
|
1333
|
+
Raw verify *integer* `signature` for *integer* `message` with public key (BEWARE: no ECDSA/EdDSA padding or validation).
|
|
1149
1334
|
|
|
1150
1335
|
```bash
|
|
1151
|
-
poetry run transcrypto dsa
|
|
1336
|
+
poetry run transcrypto dsa rawverify [-h] message signature
|
|
1152
1337
|
```
|
|
1153
1338
|
|
|
1154
1339
|
| Option/Arg | Description |
|
|
@@ -1159,9 +1344,32 @@ poetry run transcrypto dsa verify [-h] message signature
|
|
|
1159
1344
|
**Example:**
|
|
1160
1345
|
|
|
1161
1346
|
```bash
|
|
1162
|
-
$ poetry run transcrypto -p dsa-key.pub dsa
|
|
1347
|
+
$ poetry run transcrypto -p dsa-key.pub dsa rawverify 999 2395961484:3435572290
|
|
1348
|
+
DSA signature: OK
|
|
1349
|
+
$ poetry run transcrypto -p dsa-key.pub dsa rawverify 999 2395961484:3435572291
|
|
1350
|
+
DSA signature: INVALID
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
#### `dsa verify`
|
|
1354
|
+
|
|
1355
|
+
Verify `signature` for `message` with public key.
|
|
1356
|
+
|
|
1357
|
+
```bash
|
|
1358
|
+
poetry run transcrypto dsa verify [-h] [-a AAD] message signature
|
|
1359
|
+
```
|
|
1360
|
+
|
|
1361
|
+
| Option/Arg | Description |
|
|
1362
|
+
|---|---|
|
|
1363
|
+
| `message` | Message that was signed earlier [type: str] |
|
|
1364
|
+
| `signature` | Putative signature for `message` [type: str] |
|
|
1365
|
+
| `-a, --aad` | Associated data (optional; has to be exactly the same as used during signing) [type: str] |
|
|
1366
|
+
|
|
1367
|
+
**Example:**
|
|
1368
|
+
|
|
1369
|
+
```bash
|
|
1370
|
+
$ poetry run transcrypto --b64 -p dsa-key.pub dsa verify "eHl6" "yq8InJVpViXh9…BD4par2XuA="
|
|
1163
1371
|
DSA signature: OK
|
|
1164
|
-
$ poetry run transcrypto -p dsa-key.pub dsa verify
|
|
1372
|
+
$ poetry run transcrypto --b64 -p dsa-key.pub dsa verify "eLl6" "yq8InJVpViXh9…BD4par2XuA="
|
|
1165
1373
|
DSA signature: INVALID
|
|
1166
1374
|
```
|
|
1167
1375
|
|
|
@@ -1215,10 +1423,11 @@ tomorrow it will rain
|
|
|
1215
1423
|
|
|
1216
1424
|
### `sss`
|
|
1217
1425
|
|
|
1218
|
-
|
|
1426
|
+
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
1427
|
|
|
1220
1428
|
```bash
|
|
1221
|
-
poetry run transcrypto sss [-h]
|
|
1429
|
+
poetry run transcrypto sss [-h]
|
|
1430
|
+
{new,rawshares,shares,rawrecover,recover,rawverify} ...
|
|
1222
1431
|
```
|
|
1223
1432
|
|
|
1224
1433
|
#### `sss new`
|
|
@@ -1241,9 +1450,30 @@ $ poetry run transcrypto -p sss-key sss new 3 --bits 64 # NEVER use such a smal
|
|
|
1241
1450
|
SSS private/public keys saved to 'sss-key.priv/.pub'
|
|
1242
1451
|
```
|
|
1243
1452
|
|
|
1453
|
+
#### `sss rawshares`
|
|
1454
|
+
|
|
1455
|
+
Raw shares: Issue `count` private shares for an *integer* `secret` (BEWARE: no modern message wrapping, padding or validation).
|
|
1456
|
+
|
|
1457
|
+
```bash
|
|
1458
|
+
poetry run transcrypto sss rawshares [-h] secret count
|
|
1459
|
+
```
|
|
1460
|
+
|
|
1461
|
+
| Option/Arg | Description |
|
|
1462
|
+
|---|---|
|
|
1463
|
+
| `secret` | Integer secret to be protected, 1≤`secret`<*modulus* [type: str] |
|
|
1464
|
+
| `count` | How many shares to produce; must be ≥ `minimum` used in `new` command or else the `secret` would become unrecoverable [type: int] |
|
|
1465
|
+
|
|
1466
|
+
**Example:**
|
|
1467
|
+
|
|
1468
|
+
```bash
|
|
1469
|
+
$ poetry run transcrypto -p sss-key sss rawshares 999 5
|
|
1470
|
+
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
|
|
1471
|
+
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1244
1474
|
#### `sss shares`
|
|
1245
1475
|
|
|
1246
|
-
Issue `count` private shares for
|
|
1476
|
+
Shares: Issue `count` private shares for a `secret`.
|
|
1247
1477
|
|
|
1248
1478
|
```bash
|
|
1249
1479
|
poetry run transcrypto sss shares [-h] secret count
|
|
@@ -1251,17 +1481,36 @@ poetry run transcrypto sss shares [-h] secret count
|
|
|
1251
1481
|
|
|
1252
1482
|
| Option/Arg | Description |
|
|
1253
1483
|
|---|---|
|
|
1254
|
-
| `secret` |
|
|
1484
|
+
| `secret` | Secret to be protected [type: str] |
|
|
1255
1485
|
| `count` | How many shares to produce; must be ≥ `minimum` used in `new` command or else the `secret` would become unrecoverable [type: int] |
|
|
1256
1486
|
|
|
1257
1487
|
**Example:**
|
|
1258
1488
|
|
|
1259
1489
|
```bash
|
|
1260
|
-
$ poetry run transcrypto -p sss-key sss shares
|
|
1490
|
+
$ poetry run transcrypto --bin -p sss-key sss shares "abcde" 5
|
|
1261
1491
|
SSS 5 individual (private) shares saved to 'sss-key.share.1…5'
|
|
1262
1492
|
$ rm sss-key.share.2 sss-key.share.4 # this is to simulate only having shares 1,3,5
|
|
1263
1493
|
```
|
|
1264
1494
|
|
|
1495
|
+
#### `sss rawrecover`
|
|
1496
|
+
|
|
1497
|
+
Raw recover *integer* secret from shares; will use any available shares that were found (BEWARE: no modern message wrapping, padding or validation).
|
|
1498
|
+
|
|
1499
|
+
```bash
|
|
1500
|
+
poetry run transcrypto sss rawrecover [-h]
|
|
1501
|
+
```
|
|
1502
|
+
|
|
1503
|
+
**Example:**
|
|
1504
|
+
|
|
1505
|
+
```bash
|
|
1506
|
+
$ poetry run transcrypto -p sss-key sss rawrecover
|
|
1507
|
+
Loaded SSS share: 'sss-key.share.3'
|
|
1508
|
+
Loaded SSS share: 'sss-key.share.5'
|
|
1509
|
+
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
|
|
1510
|
+
Secret:
|
|
1511
|
+
999
|
|
1512
|
+
```
|
|
1513
|
+
|
|
1265
1514
|
#### `sss recover`
|
|
1266
1515
|
|
|
1267
1516
|
Recover secret from shares; will use any available shares that were found.
|
|
@@ -1273,34 +1522,34 @@ poetry run transcrypto sss recover [-h]
|
|
|
1273
1522
|
**Example:**
|
|
1274
1523
|
|
|
1275
1524
|
```bash
|
|
1276
|
-
$ poetry run transcrypto -p sss-key sss recover
|
|
1525
|
+
$ poetry run transcrypto --out-bin -p sss-key sss recover
|
|
1277
1526
|
Loaded SSS share: 'sss-key.share.3'
|
|
1278
1527
|
Loaded SSS share: 'sss-key.share.5'
|
|
1279
1528
|
Loaded SSS share: 'sss-key.share.1' # using only 3 shares: number 2/4 are missing
|
|
1280
1529
|
Secret:
|
|
1281
|
-
|
|
1530
|
+
abcde
|
|
1282
1531
|
```
|
|
1283
1532
|
|
|
1284
|
-
#### `sss
|
|
1533
|
+
#### `sss rawverify`
|
|
1285
1534
|
|
|
1286
|
-
|
|
1535
|
+
Raw verify shares against a secret (private params; BEWARE: no modern message wrapping, padding or validation).
|
|
1287
1536
|
|
|
1288
1537
|
```bash
|
|
1289
|
-
poetry run transcrypto sss
|
|
1538
|
+
poetry run transcrypto sss rawverify [-h] secret
|
|
1290
1539
|
```
|
|
1291
1540
|
|
|
1292
1541
|
| Option/Arg | Description |
|
|
1293
1542
|
|---|---|
|
|
1294
|
-
| `secret` | Integer secret used to generate the shares
|
|
1543
|
+
| `secret` | Integer secret used to generate the shares [type: str] |
|
|
1295
1544
|
|
|
1296
1545
|
**Example:**
|
|
1297
1546
|
|
|
1298
1547
|
```bash
|
|
1299
|
-
$ poetry run transcrypto -p sss-key sss
|
|
1548
|
+
$ poetry run transcrypto -p sss-key sss rawverify 999
|
|
1300
1549
|
SSS share 'sss-key.share.3' verification: OK
|
|
1301
1550
|
SSS share 'sss-key.share.5' verification: OK
|
|
1302
1551
|
SSS share 'sss-key.share.1' verification: OK
|
|
1303
|
-
$ poetry run transcrypto -p sss-key sss
|
|
1552
|
+
$ poetry run transcrypto -p sss-key sss rawverify 998
|
|
1304
1553
|
SSS share 'sss-key.share.3' verification: INVALID
|
|
1305
1554
|
SSS share 'sss-key.share.5' verification: INVALID
|
|
1306
1555
|
SSS share 'sss-key.share.1' verification: INVALID
|
|
@@ -1396,169 +1645,39 @@ Chooses an appropriate time unit based on magnitude and formats with fixed preci
|
|
|
1396
1645
|
- special case: `0 → '0.00 s'`
|
|
1397
1646
|
- errors: negative or non-finite inputs raise `InputError`
|
|
1398
1647
|
|
|
1399
|
-
####
|
|
1648
|
+
#### Execution Timing
|
|
1400
1649
|
|
|
1401
|
-
|
|
1650
|
+
A flexible timing utility that works as a **context manager**, **decorator**, or **manual timer object**.
|
|
1402
1651
|
|
|
1403
1652
|
```py
|
|
1404
1653
|
from transcrypto import base
|
|
1654
|
+
import time
|
|
1405
1655
|
```
|
|
1406
1656
|
|
|
1407
|
-
#####
|
|
1657
|
+
##### Context manager
|
|
1408
1658
|
|
|
1409
1659
|
```py
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1660
|
+
with base.Timer('Block timing'):
|
|
1661
|
+
time.sleep(1.2)
|
|
1662
|
+
# → logs: "Block timing: 1.20 s" (default via logging.info)
|
|
1413
1663
|
```
|
|
1414
1664
|
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
- errors: `n_bits < 8` → `InputError`
|
|
1665
|
+
Starts timing on entry, stops on exit, and reports elapsed time automatically.
|
|
1418
1666
|
|
|
1419
|
-
#####
|
|
1667
|
+
##### Decorator
|
|
1420
1668
|
|
|
1421
1669
|
```py
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
```
|
|
1670
|
+
@base.Timer('Function timing')
|
|
1671
|
+
def slow_function():
|
|
1672
|
+
time.sleep(0.8)
|
|
1426
1673
|
|
|
1427
|
-
|
|
1674
|
+
slow_function()
|
|
1675
|
+
# → logs: "Function timing: 0.80 s"
|
|
1676
|
+
```
|
|
1428
1677
|
|
|
1429
|
-
|
|
1430
|
-
- errors: invalid bounds → `InputError`
|
|
1678
|
+
Wraps a function so that each call is automatically timed.
|
|
1431
1679
|
|
|
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
|
|
1680
|
+
##### Manual use
|
|
1562
1681
|
|
|
1563
1682
|
```py
|
|
1564
1683
|
tm = base.Timer('Inline timing', emit_print=True)
|
|
@@ -1582,21 +1701,6 @@ Manual control over `Start()` and `Stop()` for precise measurement of custom int
|
|
|
1582
1701
|
- Cannot stop an unstarted or already stopped timer
|
|
1583
1702
|
(raises `Error`)
|
|
1584
1703
|
|
|
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
1704
|
#### Serialization Pipeline
|
|
1601
1705
|
|
|
1602
1706
|
These helpers turn arbitrary Python objects into compressed and/or encrypted binary blobs, and back again — with detailed timing and size logging.
|
|
@@ -1679,114 +1783,89 @@ data/file → (decrypt) → (decompress if Zstd) → unpickle
|
|
|
1679
1783
|
- `file_path` must exist; `data` must be at least 4 bytes.
|
|
1680
1784
|
- Wrong key or corrupted data can raise `CryptoError`.
|
|
1681
1785
|
|
|
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.
|
|
1786
|
+
#### Cryptographically Secure Randomness
|
|
1691
1787
|
|
|
1692
|
-
|
|
1788
|
+
These helpers live in `base` and wrap Python’s `secrets` with additional checks and guarantees for crypto use-cases.
|
|
1693
1789
|
|
|
1694
|
-
<!-- cspell:disable -->
|
|
1695
1790
|
```py
|
|
1696
|
-
from transcrypto import base
|
|
1791
|
+
from transcrypto import base
|
|
1792
|
+
```
|
|
1697
1793
|
|
|
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…)
|
|
1794
|
+
##### Fixed-size random integers
|
|
1701
1795
|
|
|
1702
|
-
|
|
1703
|
-
#
|
|
1796
|
+
```py
|
|
1797
|
+
# Generate a 256-bit integer (first bit always set)
|
|
1798
|
+
r = base.RandBits(256)
|
|
1799
|
+
assert r.bit_length() == 256
|
|
1800
|
+
```
|
|
1704
1801
|
|
|
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."
|
|
1802
|
+
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
1803
|
|
|
1708
|
-
|
|
1709
|
-
# ▶ KLUv_WBwAIELAIAElWUBAAAAAAAAjA90cmFuc2NyeXB0by5yc2GUjA1SU0FQcml2YXRlS2V5lJOUKYGUXZQoikHf1EvsmZedAZve7TrLmobLAwuRIr_77TLG6G_0fsLGThERVJu075be8PLjUQYnLXcacZFQ5Fb1Iy1WtiE985euAEoBAAEAiiFR9ngiXMzkf41o5CRBY3h0D4DJVisDDhLmAWsiaHggzQCKIS_cmQ6MKXCtROtC7c_Mrsi9A-9NM8DksaHaRwvy6uTZAIpB4TVbsLxc41TEc19wIzpxbi9y5dW5gdfTkRQSSiz0ijmb8Xk3pyBfKAv8JbHp8Yv48gNZUfX67qq0J7yhJqeUoACKIbFb2kTNRzSqm3JRtjc2BPS-FnLFdadlFcV4-6IW7eqLAIogFZfzDN39gZLR9uTz4KHSTaqxWrJgP8-YYssjss6FlFKKIIItgCDv7ompNpY8gBs5bibN8XTsr-JOYSntDVT5Fe5vZWIu
|
|
1804
|
+
- errors: `n_bits < 8` → `InputError`
|
|
1710
1805
|
|
|
1711
|
-
|
|
1712
|
-
print(key)
|
|
1713
|
-
# ▶ AESKey(key256=86a86df7…)
|
|
1806
|
+
##### Uniform random integers in a range
|
|
1714
1807
|
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1808
|
+
```py
|
|
1809
|
+
# Uniform between [10, 20] inclusive
|
|
1810
|
+
n = base.RandInt(10, 20)
|
|
1811
|
+
assert 10 <= n <= 20
|
|
1718
1812
|
```
|
|
1719
|
-
<!-- cspell:enable -->
|
|
1720
1813
|
|
|
1721
|
-
|
|
1814
|
+
Returns a crypto-secure integer uniformly distributed over the closed interval `[min_int, max_int]`.
|
|
1722
1815
|
|
|
1723
|
-
|
|
1724
|
-
|
|
1816
|
+
- constraints: `min_int ≥ 0` and `< max_int`
|
|
1817
|
+
- errors: invalid bounds → `InputError`
|
|
1725
1818
|
|
|
1726
|
-
#####
|
|
1819
|
+
##### In-place secure shuffle
|
|
1727
1820
|
|
|
1728
1821
|
```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
|
|
1822
|
+
deck = list(range(10))
|
|
1823
|
+
base.RandShuffle(deck)
|
|
1824
|
+
print(deck) # securely shuffled order
|
|
1737
1825
|
```
|
|
1738
1826
|
|
|
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)
|
|
1827
|
+
Performs an in-place Fisher–Yates shuffle using `secrets.randbelow`. Suitable for sensitive data ordering.
|
|
1745
1828
|
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
aad = b'metadata'
|
|
1829
|
+
- constraints: sequence length ≥ 2
|
|
1830
|
+
- errors: shorter sequences → `InputError`
|
|
1749
1831
|
|
|
1750
|
-
|
|
1751
|
-
ct = key.Encrypt(data, associated_data=aad)
|
|
1832
|
+
##### Random byte strings
|
|
1752
1833
|
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1834
|
+
```py
|
|
1835
|
+
# 32 random bytes
|
|
1836
|
+
b = base.RandBytes(32)
|
|
1837
|
+
assert len(b) == 32
|
|
1756
1838
|
```
|
|
1757
1839
|
|
|
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`
|
|
1840
|
+
Generates `n_bytes` of high-quality crypto-secure random data.
|
|
1764
1841
|
|
|
1765
|
-
|
|
1842
|
+
- constraints: `n_bytes ≥ 1`
|
|
1843
|
+
- errors: smaller values → `InputError`
|
|
1844
|
+
|
|
1845
|
+
#### Computing the Greatest Common Divisor
|
|
1766
1846
|
|
|
1767
1847
|
```py
|
|
1768
|
-
|
|
1769
|
-
|
|
1848
|
+
>>> from transcrypto import base
|
|
1849
|
+
>>> base.GCD(462, 1071)
|
|
1850
|
+
21
|
|
1851
|
+
>>> base.GCD(0, 17)
|
|
1852
|
+
17
|
|
1853
|
+
```
|
|
1770
1854
|
|
|
1771
|
-
|
|
1772
|
-
ct_block = ecb.Encrypt(block)
|
|
1773
|
-
pt_block = ecb.Decrypt(ct_block)
|
|
1774
|
-
assert pt_block == block
|
|
1855
|
+
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
1856
|
|
|
1776
|
-
|
|
1777
|
-
|
|
1857
|
+
```py
|
|
1858
|
+
>>> base.ExtendedGCD(462, 1071)
|
|
1859
|
+
(21, -2, 1)
|
|
1860
|
+
>>> 462 * -2 + 1071 * 1
|
|
1861
|
+
21
|
|
1778
1862
|
```
|
|
1779
1863
|
|
|
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:
|
|
1864
|
+
Use-cases:
|
|
1786
1865
|
|
|
1787
|
-
-
|
|
1788
|
-
-
|
|
1789
|
-
-
|
|
1866
|
+
- modular inverses: `inv = x % m` when `gcd(a, m) == 1`
|
|
1867
|
+
- solving linear Diophantine equations
|
|
1868
|
+
- RSA / ECC key generation internals
|
|
1790
1869
|
|
|
1791
1870
|
#### Fast Modular Arithmetic
|
|
1792
1871
|
|
|
@@ -1809,7 +1888,7 @@ assert (z * y) % m == x % m
|
|
|
1809
1888
|
exp = modmath.ModExp(3, 10**20, m) # ≈ log₂(y) time, handles huge exponents
|
|
1810
1889
|
```
|
|
1811
1890
|
|
|
1812
|
-
|
|
1891
|
+
##### Chinese Remainder Theorem (CRT) – Pair
|
|
1813
1892
|
|
|
1814
1893
|
```py
|
|
1815
1894
|
from transcrypto import modmath
|
|
@@ -1840,7 +1919,7 @@ x ≡ a2 (mod m2)
|
|
|
1840
1919
|
|
|
1841
1920
|
This function is a 2-modulus variant; for multiple moduli, apply it iteratively or use a general CRT solver.
|
|
1842
1921
|
|
|
1843
|
-
|
|
1922
|
+
##### Modular Polynomials & Lagrange Interpolation
|
|
1844
1923
|
|
|
1845
1924
|
```py
|
|
1846
1925
|
# f(t) = 7t³ − 3t² + 2t + 5 (coefficients constant-term first)
|
|
@@ -1876,6 +1955,176 @@ for k, m_p, perfect in modmath.MersennePrimesGenerator(0):
|
|
|
1876
1955
|
break
|
|
1877
1956
|
```
|
|
1878
1957
|
|
|
1958
|
+
#### Cryptographic Hashing
|
|
1959
|
+
|
|
1960
|
+
Simple, fixed-output-size wrappers over Python’s `hashlib` for common digest operations, plus file hashing.
|
|
1961
|
+
|
|
1962
|
+
```py
|
|
1963
|
+
from transcrypto import base
|
|
1964
|
+
```
|
|
1965
|
+
|
|
1966
|
+
##### SHA-256 hashing
|
|
1967
|
+
|
|
1968
|
+
```py
|
|
1969
|
+
h = base.Hash256(b'hello world')
|
|
1970
|
+
assert len(h) == 32 # bytes
|
|
1971
|
+
print(h.hex()) # 64 hex chars
|
|
1972
|
+
```
|
|
1973
|
+
|
|
1974
|
+
Computes the SHA-256 digest of a byte string, returning exactly 32 bytes (256 bits). Suitable for fingerprints, commitments, or internal crypto primitives.
|
|
1975
|
+
|
|
1976
|
+
##### SHA-512 hashing
|
|
1977
|
+
|
|
1978
|
+
```py
|
|
1979
|
+
h = base.Hash512(b'hello world')
|
|
1980
|
+
assert len(h) == 64 # bytes
|
|
1981
|
+
print(h.hex()) # 128 hex chars
|
|
1982
|
+
```
|
|
1983
|
+
|
|
1984
|
+
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.
|
|
1985
|
+
|
|
1986
|
+
##### File hashing
|
|
1987
|
+
|
|
1988
|
+
```py
|
|
1989
|
+
# Default SHA-256
|
|
1990
|
+
fh = base.FileHash('/path/to/file')
|
|
1991
|
+
print(fh.hex())
|
|
1992
|
+
|
|
1993
|
+
# SHA-512
|
|
1994
|
+
fh2 = base.FileHash('/path/to/file', digest='sha512')
|
|
1995
|
+
```
|
|
1996
|
+
|
|
1997
|
+
Hashes a file from disk in streaming mode. By default uses SHA-256; `digest='sha512'` switches to SHA-512.
|
|
1998
|
+
|
|
1999
|
+
- constraints:
|
|
2000
|
+
- `digest` must be `'sha256'` or `'sha512'`
|
|
2001
|
+
- `full_path` must exist
|
|
2002
|
+
- errors: invalid digest or missing file → `InputError`
|
|
2003
|
+
|
|
2004
|
+
#### Symmetric Encryption Interface
|
|
2005
|
+
|
|
2006
|
+
`SymmetricCrypto` is an abstract base class that defines the **byte-in / byte-out** contract for symmetric ciphers.
|
|
2007
|
+
|
|
2008
|
+
- **Metadata handling** — if the algorithm uses a `nonce` or `tag`, the implementation must handle it internally (e.g., append it to ciphertext).
|
|
2009
|
+
- **AEAD modes** — if supported, `associated_data` must be authenticated; otherwise, a non-`None` value should raise `InputError`.
|
|
2010
|
+
|
|
2011
|
+
```py
|
|
2012
|
+
class MyAES(base.SymmetricCrypto):
|
|
2013
|
+
def Encrypt(self, plaintext: bytes, *, associated_data=None) -> bytes:
|
|
2014
|
+
...
|
|
2015
|
+
def Decrypt(self, ciphertext: bytes, *, associated_data=None) -> bytes:
|
|
2016
|
+
...
|
|
2017
|
+
```
|
|
2018
|
+
|
|
2019
|
+
#### Crypto Objects General Properties (`CryptoKey`)
|
|
2020
|
+
|
|
2021
|
+
Cryptographic objects all derive from the `CryptoKey` class and will all have some important characteristics:
|
|
2022
|
+
|
|
2023
|
+
- 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…`).
|
|
2024
|
+
- It will have a `_DebugDump()` method that **does print secrets** and can be used for **debugging only**.
|
|
2025
|
+
- Can be easily serialized to `bytes` by the `blob` property and to base-64 encoded `str` by the `encoded` property.
|
|
2026
|
+
- 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.
|
|
2027
|
+
- 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.
|
|
2028
|
+
|
|
2029
|
+
Example:
|
|
2030
|
+
|
|
2031
|
+
<!-- cspell:disable -->
|
|
2032
|
+
```py
|
|
2033
|
+
from transcrypto import base, rsa, aes
|
|
2034
|
+
|
|
2035
|
+
priv = rsa.RSAPrivateKey.New(512) # small key, but good for this example
|
|
2036
|
+
print(str(priv)) # safe, no secrets
|
|
2037
|
+
# ▶ RSAPrivateKey(RSAPublicKey(public_modulus=pQaoxy-QeXSds1k9WsGjJw==, encrypt_exp=AQAB), modulus_p=f18141aa…, modulus_q=67494eb9…, decrypt_exp=c96db24a…)
|
|
2038
|
+
|
|
2039
|
+
print(priv._DebugDump()) # UNSAFE: prints secrets
|
|
2040
|
+
# ▶ 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)
|
|
2041
|
+
|
|
2042
|
+
print(priv.blob)
|
|
2043
|
+
# ▶ 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."
|
|
2044
|
+
|
|
2045
|
+
print(priv.encoded)
|
|
2046
|
+
# ▶ KLUv_WBwAIELAIAElWUBAAAAAAAAjA90cmFuc2NyeXB0by5yc2GUjA1SU0FQcml2YXRlS2V5lJOUKYGUXZQoikHf1EvsmZedAZve7TrLmobLAwuRIr_77TLG6G_0fsLGThERVJu075be8PLjUQYnLXcacZFQ5Fb1Iy1WtiE985euAEoBAAEAiiFR9ngiXMzkf41o5CRBY3h0D4DJVisDDhLmAWsiaHggzQCKIS_cmQ6MKXCtROtC7c_Mrsi9A-9NM8DksaHaRwvy6uTZAIpB4TVbsLxc41TEc19wIzpxbi9y5dW5gdfTkRQSSiz0ijmb8Xk3pyBfKAv8JbHp8Yv48gNZUfX67qq0J7yhJqeUoACKIbFb2kTNRzSqm3JRtjc2BPS-FnLFdadlFcV4-6IW7eqLAIogFZfzDN39gZLR9uTz4KHSTaqxWrJgP8-YYssjss6FlFKKIIItgCDv7ompNpY8gBs5bibN8XTsr-JOYSntDVT5Fe5vZWIu
|
|
2047
|
+
|
|
2048
|
+
key = aes.AESKey(key256=b'x' * 32)
|
|
2049
|
+
print(key)
|
|
2050
|
+
# ▶ AESKey(key256=86a86df7…)
|
|
2051
|
+
|
|
2052
|
+
encrypted = priv.Blob(key=key)
|
|
2053
|
+
print(priv == rsa.RSAPrivateKey.Load(encrypted, key=key))
|
|
2054
|
+
# ▶ True
|
|
2055
|
+
```
|
|
2056
|
+
<!-- cspell:enable -->
|
|
2057
|
+
|
|
2058
|
+
#### AES-256 Symmetric Encryption
|
|
2059
|
+
|
|
2060
|
+
Implements AES-256 in **GCM mode** for authenticated encryption and decryption, plus an **ECB mode** helper for fixed-size block encoding.
|
|
2061
|
+
Also includes a high-iteration PBKDF2-based key derivation from static passwords.
|
|
2062
|
+
|
|
2063
|
+
##### Key creation
|
|
2064
|
+
|
|
2065
|
+
```py
|
|
2066
|
+
from transcrypto import aes
|
|
2067
|
+
|
|
2068
|
+
# From raw bytes (must be exactly 32 bytes)
|
|
2069
|
+
key = aes.AESKey(key256=b'\x00' * 32)
|
|
2070
|
+
|
|
2071
|
+
# From a static password (slow, high-iteration PBKDF2-SHA256)
|
|
2072
|
+
key = aes.AESKey.FromStaticPassword('correct horse battery staple')
|
|
2073
|
+
print(key.encoded) # URL-safe Base64
|
|
2074
|
+
```
|
|
2075
|
+
|
|
2076
|
+
- **Length**: `key256` must be exactly 32 bytes
|
|
2077
|
+
- `FromStaticPassword()`:
|
|
2078
|
+
- Uses PBKDF2-HMAC-SHA256 with **fixed** salt and \~2 million iterations
|
|
2079
|
+
- Designed for **interactive** password entry, **not** for password databases
|
|
2080
|
+
|
|
2081
|
+
##### AES-256 + GCM (default)
|
|
2082
|
+
|
|
2083
|
+
```py
|
|
2084
|
+
data = b'secret message'
|
|
2085
|
+
aad = b'metadata'
|
|
2086
|
+
|
|
2087
|
+
# Encrypt (returns IV + ciphertext + tag)
|
|
2088
|
+
ct = key.Encrypt(data, associated_data=aad)
|
|
2089
|
+
|
|
2090
|
+
# Decrypt
|
|
2091
|
+
pt = key.Decrypt(ct, associated_data=aad)
|
|
2092
|
+
assert pt == data
|
|
2093
|
+
```
|
|
2094
|
+
|
|
2095
|
+
- **Security**:
|
|
2096
|
+
- Random 128-bit IV (`iv`) per encryption
|
|
2097
|
+
- Authenticated tag (128-bit) ensures integrity
|
|
2098
|
+
- Optional `associated_data` is authenticated but not encrypted
|
|
2099
|
+
- **Errors**:
|
|
2100
|
+
- Tag mismatch or wrong key → `CryptoError`
|
|
2101
|
+
|
|
2102
|
+
##### AES-256 + ECB (unsafe, fixed block only)
|
|
2103
|
+
|
|
2104
|
+
```py
|
|
2105
|
+
# ECB mode is for 16-byte block encoding ONLY
|
|
2106
|
+
ecb = key.ECBEncoder()
|
|
2107
|
+
|
|
2108
|
+
block = b'16-byte string!!'
|
|
2109
|
+
ct_block = ecb.Encrypt(block)
|
|
2110
|
+
pt_block = ecb.Decrypt(ct_block)
|
|
2111
|
+
assert pt_block == block
|
|
2112
|
+
|
|
2113
|
+
# Hex helpers
|
|
2114
|
+
hex_ct = ecb.EncryptHex('00112233445566778899aabbccddeeff')
|
|
2115
|
+
```
|
|
2116
|
+
|
|
2117
|
+
- **ECB mode**:
|
|
2118
|
+
- 16-byte plaintext ↔ 16-byte ciphertext
|
|
2119
|
+
- No padding, no IV, no integrity — **do not use for general encryption**
|
|
2120
|
+
- `associated_data` not supported
|
|
2121
|
+
|
|
2122
|
+
Key points:
|
|
2123
|
+
|
|
2124
|
+
- **GCM mode** is secure for general use; ECB mode is for special low-level operations
|
|
2125
|
+
- **Static password derivation** is intentionally slow to resist brute force
|
|
2126
|
+
- All sizes and parameters are validated with `InputError` on misuse
|
|
2127
|
+
|
|
1879
2128
|
#### RSA (Rivest-Shamir-Adleman) Public Cryptography
|
|
1880
2129
|
|
|
1881
2130
|
<https://en.wikipedia.org/wiki/RSA_cryptosystem>
|
|
@@ -1888,28 +2137,38 @@ By default and deliberate choice the *encryption exponent* will be either 7 or 6
|
|
|
1888
2137
|
from transcrypto import rsa
|
|
1889
2138
|
|
|
1890
2139
|
# Generate a key pair
|
|
1891
|
-
priv = rsa.RSAPrivateKey.New(2048)
|
|
1892
|
-
pub = rsa.RSAPublicKey.Copy(priv)
|
|
2140
|
+
priv = rsa.RSAPrivateKey.New(2048) # 2048-bit modulus
|
|
2141
|
+
pub = rsa.RSAPublicKey.Copy(priv) # public half
|
|
1893
2142
|
print(priv.public_modulus.bit_length()) # 2048
|
|
1894
2143
|
|
|
1895
|
-
#
|
|
2144
|
+
# Safe Encrypt & decrypt
|
|
2145
|
+
msg = b'xyz'
|
|
2146
|
+
cipher = pub.Encrypt(msg, associated_data=b'aad')
|
|
2147
|
+
plain = priv.Decrypt(cipher, associated_data=b'aad')
|
|
2148
|
+
assert plain == msg
|
|
2149
|
+
|
|
2150
|
+
# Safe Sign & verify
|
|
2151
|
+
signature = priv.Sign(msg) # can also have associated_data, optionally
|
|
2152
|
+
assert pub.Verify(msg, signature)
|
|
2153
|
+
|
|
2154
|
+
# Raw Encrypt & decrypt
|
|
1896
2155
|
msg = 123456789 # (Zero is forbidden by design; smallest valid message is 1.)
|
|
1897
|
-
cipher = pub.
|
|
1898
|
-
plain = priv.
|
|
2156
|
+
cipher = pub.RawEncrypt(msg)
|
|
2157
|
+
plain = priv.RawDecrypt(cipher)
|
|
1899
2158
|
assert plain == msg
|
|
1900
2159
|
|
|
1901
|
-
# Sign & verify
|
|
1902
|
-
signature = priv.
|
|
1903
|
-
assert pub.
|
|
2160
|
+
# Raw Sign & verify
|
|
2161
|
+
signature = priv.RawSign(msg)
|
|
2162
|
+
assert pub.RawVerify(msg, signature)
|
|
1904
2163
|
|
|
1905
2164
|
# Blind signatures (obfuscation pair) - only works on raw RSA
|
|
1906
2165
|
pair = rsa.RSAObfuscationPair.New(pub)
|
|
1907
2166
|
|
|
1908
2167
|
blind_msg = pair.ObfuscateMessage(msg) # what you send to signer
|
|
1909
|
-
blind_sig = priv.
|
|
2168
|
+
blind_sig = priv.RawSign(blind_msg) # signer’s output
|
|
1910
2169
|
|
|
1911
2170
|
sig = pair.RevealOriginalSignature(msg, blind_sig)
|
|
1912
|
-
assert pub.
|
|
2171
|
+
assert pub.RawVerify(msg, sig)
|
|
1913
2172
|
```
|
|
1914
2173
|
|
|
1915
2174
|
#### El-Gamal Public-Key Cryptography
|
|
@@ -1919,61 +2178,39 @@ assert pub.VerifySignature(msg, sig)
|
|
|
1919
2178
|
This is **raw El-Gamal** over a prime field — no padding, no hashing — and is **not** DSA.
|
|
1920
2179
|
For real-world deployments, use a high-level library with authenticated encryption and proper encoding.
|
|
1921
2180
|
|
|
1922
|
-
##### Shared Public Key
|
|
1923
|
-
|
|
1924
2181
|
```py
|
|
1925
2182
|
from transcrypto import elgamal
|
|
1926
2183
|
|
|
1927
|
-
#
|
|
2184
|
+
# Shared parameters (prime modulus, group base) for a group
|
|
1928
2185
|
shared = elgamal.ElGamalSharedPublicKey.New(256)
|
|
1929
2186
|
print(shared.prime_modulus)
|
|
1930
2187
|
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
|
-
|
|
1937
|
-
##### Public Key
|
|
1938
2188
|
|
|
1939
|
-
|
|
1940
|
-
# ➋ Public key from private
|
|
2189
|
+
# Public key from private
|
|
1941
2190
|
priv = elgamal.ElGamalPrivateKey.New(shared)
|
|
1942
2191
|
pub = elgamal.ElGamalPublicKey.Copy(priv)
|
|
1943
2192
|
|
|
1944
|
-
#
|
|
1945
|
-
msg =
|
|
1946
|
-
cipher = pub.Encrypt(msg)
|
|
1947
|
-
plain
|
|
2193
|
+
# Safe Encrypt & decrypt
|
|
2194
|
+
msg = b'xyz'
|
|
2195
|
+
cipher = pub.Encrypt(msg, associated_data=b'aad')
|
|
2196
|
+
plain = priv.Decrypt(cipher, associated_data=b'aad')
|
|
1948
2197
|
assert plain == msg
|
|
1949
2198
|
|
|
1950
|
-
#
|
|
1951
|
-
|
|
1952
|
-
assert pub.
|
|
1953
|
-
```
|
|
2199
|
+
# Safe Sign & verify
|
|
2200
|
+
signature = priv.Sign(msg) # can also have associated_data, optionally
|
|
2201
|
+
assert pub.Verify(msg, signature)
|
|
1954
2202
|
|
|
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)
|
|
2203
|
+
# Raw Encryption
|
|
2204
|
+
msg = 42
|
|
2205
|
+
cipher = pub.RawEncrypt(msg)
|
|
2206
|
+
plain = priv.RawDecrypt(cipher)
|
|
2207
|
+
assert plain == msg
|
|
1967
2208
|
|
|
1968
|
-
#
|
|
1969
|
-
sig = priv.
|
|
1970
|
-
assert pub.
|
|
2209
|
+
# Raw Signature verify
|
|
2210
|
+
sig = priv.RawSign(msg)
|
|
2211
|
+
assert pub.RawVerify(msg, sig)
|
|
1971
2212
|
```
|
|
1972
2213
|
|
|
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
2214
|
Key points:
|
|
1978
2215
|
|
|
1979
2216
|
- **Security parameters**:
|
|
@@ -1997,20 +2234,25 @@ This is **raw DSA** over a prime field — **no hashing or padding**. You sign/v
|
|
|
1997
2234
|
```py
|
|
1998
2235
|
from transcrypto import dsa
|
|
1999
2236
|
|
|
2000
|
-
#
|
|
2237
|
+
# Shared parameters (p, q, g)
|
|
2001
2238
|
shared = dsa.DSASharedPublicKey.New(p_bits=1024, q_bits=160)
|
|
2002
2239
|
print(shared.prime_modulus) # p
|
|
2003
2240
|
print(shared.prime_seed) # q (q | p-1)
|
|
2004
2241
|
print(shared.group_base) # g
|
|
2005
2242
|
|
|
2006
|
-
#
|
|
2243
|
+
# Individual key pair
|
|
2007
2244
|
priv = dsa.DSAPrivateKey.New(shared)
|
|
2008
2245
|
pub = dsa.DSAPublicKey.Copy(priv)
|
|
2009
2246
|
|
|
2010
|
-
#
|
|
2247
|
+
# Safe Sign & verify
|
|
2248
|
+
msg = b'xyz'
|
|
2249
|
+
signature = priv.Sign(msg) # can also have associated_data, optionally
|
|
2250
|
+
assert pub.Verify(msg, signature)
|
|
2251
|
+
|
|
2252
|
+
# Raw Sign & verify (message must be 1 ≤ m < q)
|
|
2011
2253
|
msg = 123456789 % shared.prime_seed
|
|
2012
|
-
sig = priv.
|
|
2013
|
-
assert pub.
|
|
2254
|
+
sig = priv.RawSign(msg)
|
|
2255
|
+
assert pub.RawVerify(msg, sig)
|
|
2014
2256
|
```
|
|
2015
2257
|
|
|
2016
2258
|
- ranges:
|
|
@@ -2044,13 +2286,13 @@ This is a way of bidding on some commitment (the `secret`) that can be cryptogra
|
|
|
2044
2286
|
from transcrypto import base
|
|
2045
2287
|
|
|
2046
2288
|
# Generate the private and public bids
|
|
2047
|
-
bid_priv = base.
|
|
2048
|
-
bid_pub = base.
|
|
2289
|
+
bid_priv = base.PrivateBid512.New(secret) # this one you keep private
|
|
2290
|
+
bid_pub = base.PublicBid512.Copy(bid_priv) # this one you publish
|
|
2049
2291
|
|
|
2050
2292
|
# Checking that a bid is genuine requires the public bid and knowing the nonce and the secret:
|
|
2051
2293
|
print(bid_pub.VerifyBid(private_key, secret_bid)) # these come from a divulged private bid
|
|
2052
2294
|
# of course, you want to also make sure the provided private data matches your version of it, e.g.:
|
|
2053
|
-
bid_pub_expected = base.
|
|
2295
|
+
bid_pub_expected = base.PublicBid512.Copy(bid_priv)
|
|
2054
2296
|
print(bid_pub == bid_pub_expected)
|
|
2055
2297
|
```
|
|
2056
2298
|
|
|
@@ -2063,8 +2305,8 @@ This is the information-theoretic SSS but with no authentication or binding betw
|
|
|
2063
2305
|
```py
|
|
2064
2306
|
from transcrypto import sss
|
|
2065
2307
|
|
|
2066
|
-
#
|
|
2067
|
-
#
|
|
2308
|
+
# Generate parameters: at least 3 of 5 shares needed,
|
|
2309
|
+
# coefficients & modulus are 128-bit primes
|
|
2068
2310
|
priv = sss.ShamirSharedSecretPrivate.New(minimum_shares=3, bit_length=128)
|
|
2069
2311
|
pub = sss.ShamirSharedSecretPublic.Copy(priv) # what you publish
|
|
2070
2312
|
|
|
@@ -2072,11 +2314,19 @@ print(f'threshold : {pub.minimum}')
|
|
|
2072
2314
|
print(f'prime mod : {pub.modulus}')
|
|
2073
2315
|
print(f'poly coefficients: {priv.polynomial}') # keep these private!
|
|
2074
2316
|
|
|
2075
|
-
#
|
|
2317
|
+
# Safe Issuing shares
|
|
2318
|
+
|
|
2319
|
+
secret = b'xyz'
|
|
2320
|
+
# Generate 5 shares, each has a copy of the encrypted secret
|
|
2321
|
+
five_shares = priv.MakeDataShares(secret, 5)
|
|
2322
|
+
for sh in five_shares:
|
|
2323
|
+
print(sh)
|
|
2324
|
+
|
|
2325
|
+
# Raw Issuing shares
|
|
2076
2326
|
|
|
2077
2327
|
secret = 0xC0FFEE
|
|
2078
2328
|
# Generate an unlimited stream; here we take 5
|
|
2079
|
-
five_shares = list(priv.
|
|
2329
|
+
five_shares = list(priv.RawShares(secret, max_shares=5))
|
|
2080
2330
|
for sh in five_shares:
|
|
2081
2331
|
print(f'share {sh.share_key} → {sh.share_value}')
|
|
2082
2332
|
```
|
|
@@ -2084,10 +2334,18 @@ for sh in five_shares:
|
|
|
2084
2334
|
A single share object looks like `sss.ShamirSharePrivate(minimum=3, modulus=..., share_key=42, share_value=123456789)`.
|
|
2085
2335
|
|
|
2086
2336
|
```py
|
|
2087
|
-
#
|
|
2337
|
+
# Safe Re-constructing the secret
|
|
2338
|
+
secret = b'xyz'
|
|
2339
|
+
five_shares = priv.MakeDataShares(secret, 5)
|
|
2340
|
+
subset = five_shares[:3] # any 3 distinct shares
|
|
2341
|
+
recovered = subset[0].RecoverData(subset) # each share has the encrypted data, so you ask it to join with the others
|
|
2342
|
+
assert recovered == secret
|
|
2088
2343
|
|
|
2344
|
+
# Raw Re-constructing the secret
|
|
2345
|
+
secret = 0xC0FFEE
|
|
2346
|
+
five_shares = list(priv.RawShares(secret, max_shares=5))
|
|
2089
2347
|
subset = five_shares[:3] # any 3 distinct shares
|
|
2090
|
-
recovered = pub.
|
|
2348
|
+
recovered = pub.RawRecoverSecret(subset)
|
|
2091
2349
|
assert recovered == secret
|
|
2092
2350
|
```
|
|
2093
2351
|
|
|
@@ -2095,23 +2353,23 @@ If you supply fewer than minimum shares you get a `CryptoError`, unless you expl
|
|
|
2095
2353
|
|
|
2096
2354
|
```py
|
|
2097
2355
|
try:
|
|
2098
|
-
pub.
|
|
2356
|
+
pub.RawRecoverSecret(five_shares[:2]) # raises
|
|
2099
2357
|
except Exception as e:
|
|
2100
2358
|
print(e) # "unrecoverable secret …"
|
|
2101
2359
|
|
|
2102
2360
|
# Force the interpolation even with 2 points (gives a wrong secret, of course)
|
|
2103
|
-
print(pub.
|
|
2361
|
+
print(pub.RawRecoverSecret(five_shares[:2], force_recover=True))
|
|
2104
2362
|
|
|
2105
2363
|
# Checking that a share is genuine
|
|
2106
2364
|
|
|
2107
2365
|
share = five_shares[0]
|
|
2108
|
-
ok = priv.
|
|
2366
|
+
ok = priv.RawVerifyShare(secret, share) # ▶ True
|
|
2109
2367
|
tampered = sss.ShamirSharePrivate(
|
|
2110
2368
|
minimum=share.minimum,
|
|
2111
2369
|
modulus=share.modulus,
|
|
2112
2370
|
share_key=share.share_key,
|
|
2113
2371
|
share_value=(share.share_value + 1) % share.modulus)
|
|
2114
|
-
print(priv.
|
|
2372
|
+
print(priv.RawVerifyShare(secret, tampered)) # ▶ False
|
|
2115
2373
|
```
|
|
2116
2374
|
|
|
2117
2375
|
## Appendix: Development Instructions
|