yace-codec 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. yace_codec-0.3.0/CHANGELOG.md +211 -0
  2. {yace_codec-0.2.0 → yace_codec-0.3.0}/MANIFEST.in +2 -0
  3. yace_codec-0.3.0/PKG-INFO +852 -0
  4. yace_codec-0.3.0/README.md +809 -0
  5. yace_codec-0.3.0/SECURITY.md +213 -0
  6. yace_codec-0.3.0/examples/encryption.py +30 -0
  7. {yace_codec-0.2.0 → yace_codec-0.3.0}/pyproject.toml +27 -11
  8. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/__init__.py +27 -2
  9. yace_codec-0.3.0/src/yace_codec/_algorithms.py +263 -0
  10. yace_codec-0.3.0/src/yace_codec/_files.py +120 -0
  11. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/_text.py +14 -8
  12. yace_codec-0.3.0/src/yace_codec/_winsec.py +164 -0
  13. yace_codec-0.3.0/src/yace_codec/cli.py +711 -0
  14. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/codec.py +427 -60
  15. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/errors.py +15 -1
  16. yace_codec-0.3.0/src/yace_codec/keybackends.py +439 -0
  17. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/keystore.py +224 -58
  18. yace_codec-0.3.0/src/yace_codec/sealed.py +974 -0
  19. yace_codec-0.3.0/src/yace_codec.egg-info/PKG-INFO +852 -0
  20. yace_codec-0.3.0/src/yace_codec.egg-info/SOURCES.txt +56 -0
  21. yace_codec-0.3.0/src/yace_codec.egg-info/requires.txt +12 -0
  22. yace_codec-0.3.0/tests/conftest.py +122 -0
  23. yace_codec-0.3.0/tests/fixtures/legacy_keystore.json +1235 -0
  24. yace_codec-0.3.0/tests/fixtures/legacy_tokens.json +350 -0
  25. yace_codec-0.3.0/tests/legacy_reference.py +74 -0
  26. yace_codec-0.3.0/tests/test_aad.py +69 -0
  27. yace_codec-0.3.0/tests/test_cli.py +264 -0
  28. yace_codec-0.3.0/tests/test_cli_encryption.py +270 -0
  29. yace_codec-0.3.0/tests/test_cli_robustness.py +128 -0
  30. yace_codec-0.3.0/tests/test_codec.py +462 -0
  31. yace_codec-0.3.0/tests/test_examples.py +38 -0
  32. yace_codec-0.3.0/tests/test_format.py +284 -0
  33. yace_codec-0.3.0/tests/test_key_backends.py +219 -0
  34. yace_codec-0.3.0/tests/test_key_store_robustness.py +204 -0
  35. yace_codec-0.3.0/tests/test_keystore.py +411 -0
  36. yace_codec-0.3.0/tests/test_malformed.py +91 -0
  37. yace_codec-0.3.0/tests/test_output_format.py +195 -0
  38. yace_codec-0.3.0/tests/test_properties.py +61 -0
  39. yace_codec-0.3.0/tests/test_raw_keys.py +79 -0
  40. yace_codec-0.3.0/tests/test_robustness.py +264 -0
  41. yace_codec-0.3.0/tests/test_spec_independent.py +117 -0
  42. yace_codec-0.3.0/tests/test_stream.py +318 -0
  43. yace_codec-0.3.0/tests/test_tables.py +198 -0
  44. yace_codec-0.3.0/tests/test_vectors.py +70 -0
  45. yace_codec-0.3.0/tests/vectors/generate.py +114 -0
  46. yace_codec-0.3.0/tests/vectors/legacy.json +42 -0
  47. yace_codec-0.3.0/tests/vectors/v3.json +491 -0
  48. yace_codec-0.2.0/CHANGELOG.md +0 -96
  49. yace_codec-0.2.0/PKG-INFO +0 -847
  50. yace_codec-0.2.0/README.md +0 -814
  51. yace_codec-0.2.0/src/yace_codec/cli.py +0 -413
  52. yace_codec-0.2.0/src/yace_codec/sealed.py +0 -228
  53. yace_codec-0.2.0/src/yace_codec.egg-info/PKG-INFO +0 -847
  54. yace_codec-0.2.0/src/yace_codec.egg-info/SOURCES.txt +0 -23
  55. {yace_codec-0.2.0 → yace_codec-0.3.0}/LICENSE +0 -0
  56. {yace_codec-0.2.0 → yace_codec-0.3.0}/examples/bytes_and_unicode.py +0 -0
  57. {yace_codec-0.2.0 → yace_codec-0.3.0}/examples/quickstart.py +0 -0
  58. {yace_codec-0.2.0 → yace_codec-0.3.0}/examples/share_tables.py +0 -0
  59. {yace_codec-0.2.0 → yace_codec-0.3.0}/setup.cfg +0 -0
  60. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/__main__.py +0 -0
  61. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/py.typed +0 -0
  62. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/tables.py +0 -0
  63. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec.egg-info/dependency_links.txt +0 -0
  64. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec.egg-info/entry_points.txt +0 -0
  65. {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec.egg-info/top_level.txt +0 -0
@@ -0,0 +1,211 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.3.0] - 2026-10-16
8
+
9
+ Output of 0.3.0 cannot be decrypted by 0.2.x. Everything 0.2.x made still decrypts.
10
+
11
+ ### Added
12
+
13
+ - **Versioned format.** Messages (format 3) and streams (format 4) carry a version
14
+ byte, an algorithm id, and four check bytes, authenticated by the tag and hidden
15
+ under a key-derived mask: output still has no recognisable prefix, and a wrong key
16
+ or secret token is rejected from the header alone. SECURITY.md specifies both
17
+ formats byte by byte.
18
+ - **Algorithms:** `aes-256-gcm` (the default) and `chacha20-poly1305` from the
19
+ audited `cryptography` package, and the standard-library `yace-hmac-sha256`. Every
20
+ algorithm has a 16-byte tag, so output length does not reveal the algorithm.
21
+ Choose with `algorithm=` or `--algorithm`; list them with `algorithms()` or
22
+ `yace-codec algorithms`.
23
+ - **Associated data:** `aad=` (and `--aad`) binds output to a context; a wrong `aad`
24
+ raises `DecryptionError`.
25
+ - **Raw keys:** `encrypt(data, key=<32 bytes>)`, `decrypt(out, keys=[...])`, and
26
+ `generate_key()`, with no key store and no scrypt. Other key sizes raise the new
27
+ `InvalidKeyError`.
28
+ - **Output format:** `output="bytes"` (and `--format bytes`) gives raw output with no
29
+ expansion; `"text"` stays the default. `decrypt()` accepts both.
30
+ - **Streaming:** `encrypt_stream()` and `decrypt_stream()` encrypt files of any size in
31
+ constant memory, in chunks whose nonces hold the chunk index and a final flag, so
32
+ truncation, reordering, and duplication are detected. `decrypt()` also reads
33
+ streams, and `decrypt_stream()` reads every format.
34
+ - **Key backends:** the `KeyBackend` interface, `Codec(key_backend=...)` (an object
35
+ or a name), `open_key_backend()`, and `--key-backend`; `DpapiKeyStore` (Windows;
36
+ keys encrypted with DPAPI) and `KeyringKeyStore` (the system keyring;
37
+ `pip install "yace-codec[keyring]"`).
38
+ - **Key rotation and deletion:** `rotate_key()` / `yace-codec keys rotate` keep the
39
+ previous key for decryption; `delete_key()` / `yace-codec keys delete --yes`.
40
+ - **Command line:** `--token-file PATH` and `--token-stdin`; `encrypt` and `decrypt`
41
+ stream files in constant memory (`encrypt` always writes the stream format).
42
+ - New names: `DEFAULT_ALGORITHM`, `DEFAULT_CHUNK_SIZE`, `KEY_SIZE`,
43
+ `MAX_MESSAGE_SIZE`, `AlgorithmInfo`, `StreamInfo`, `KeyBackend`,
44
+ `KeyNotFoundError`, and the `Codec.key_backend` attribute.
45
+ - `SECURITY.md` with the threat model, the format specification, supported versions,
46
+ and how to report a vulnerability privately.
47
+ - The test suite ships in the sdist and runs in CI on Linux, Windows, and macOS for
48
+ Python 3.10–3.15, against the built wheel and the oldest supported dependencies:
49
+ test vectors for every algorithm and format (`tests/vectors/`), an independent
50
+ implementation that decrypts them, property tests, and tamper, stream, concurrency,
51
+ and legacy tests. `benchmarks/bench.py` reports throughput.
52
+
53
+ ### Changed
54
+
55
+ - **The default algorithm is now `aes-256-gcm`**, and `cryptography` is a dependency.
56
+ (0.2.x used an HMAC-SHA256 construction; it remains available as
57
+ `yace-hmac-sha256`.)
58
+ - Python 3.10 or newer is required (3.9 reached end of life in October 2025).
59
+ - Every bad argument raises a `YaceError` subclass (or `TypeError`), and every
60
+ argument is checked before a stored key is created.
61
+ - Command line:
62
+ - every `-o` writes a temporary file that replaces the target only on success;
63
+ - decrypted and decoded files, and exported keys and tables, are created readable
64
+ only by you;
65
+ - usage mistakes (bad `--max-age`, `-l`, `-i`, or `--key`, and conflicting inputs)
66
+ exit with status 2;
67
+ - abbreviated option names are no longer accepted;
68
+ - `--token-file` reads UTF-16 files with a byte order mark (PowerShell);
69
+ - `--token` fails at once without a terminal;
70
+ - `keys rotate` refuses a key that does not exist;
71
+ - with `--key-backend dpapi`, `-k` names the key store and the keys go in
72
+ `keys-dpapi.json` next to it.
73
+ - New key store files are readable only by their owner on Windows too (an
74
+ access control list for you and SYSTEM, with nothing inherited).
75
+ - Stored keys can have a `retired` list after rotation. Version 0.2 ignores it, so
76
+ after a rotation 0.2 can no longer decrypt data made with the old key.
77
+ - Text output encodes about twice as fast.
78
+
79
+ ### Fixed
80
+
81
+ - Readers no longer see an empty key store while another process replaces it on
82
+ Windows.
83
+ - A damaged key entry no longer blocks decryption with the other keys.
84
+ - `decode()` rejects tokens longer than the encoder can make, instead of using
85
+ gigabytes of memory.
86
+
87
+ ### Deprecated
88
+
89
+ - The `YACE_CODEC_TOKEN` and `YACE_CODEC_PASSWORD` environment variables still work
90
+ with `--token`, but print a warning. Use the prompt, `--token-file`, or
91
+ `--token-stdin`.
92
+
93
+ ### Security
94
+
95
+ - Releases publish only after the full test suite passes. They are built with
96
+ hash-pinned tools and actions pinned to commits, reproducibly, and publish build
97
+ provenance attestations.
98
+
99
+ ## [0.2.1] - 2026-10-15
100
+
101
+ ### Added
102
+
103
+ - `encrypt(data, token=...)` and `decrypt(encrypted, token=...)`: choose your own
104
+ secret token (any non-empty text or bytes). With a token, nothing is generated or
105
+ stored. Without one, a key is generated and kept in the key store, as before.
106
+ - `yace-codec encrypt --token` and `decrypt --token` ask for the secret token, or
107
+ read `YACE_CODEC_TOKEN`.
108
+
109
+ ### Changed
110
+
111
+ - Encrypted output is only letters and digits, with no `yace2_` prefix, so it does
112
+ not reveal that YACE made it. Output from 0.2.0 still decrypts.
113
+ - `decrypt()`'s first parameter is named `encrypted` (it was `token`).
114
+ - `password=`, `--password`, and `YACE_CODEC_PASSWORD` remain as other names for
115
+ `token=`, `--token`, and `YACE_CODEC_TOKEN`.
116
+
117
+ ## [0.2.0] - 2026-10-14
118
+
119
+ ### Added
120
+
121
+ - Encryption: `encrypt()` and `decrypt()` (also `Codec.encrypt()` /
122
+ `Codec.decrypt()`) turn text or bytes into `yace2_` tokens and back. Tokens are
123
+ authenticated (HMAC-SHA256, encrypt-then-MAC), use per-token keys derived with
124
+ HKDF-SHA256 from a random salt, and are padded to a Padmé length. They reveal neither
125
+ the key name, the creation time, the exact length, nor the data type. Everything
126
+ comes from Python's standard library.
127
+ - Secret keys in the key store (`key:<name>` entries): `ensure_key()`, `get_key()`,
128
+ `find_key()`, `key_names()`, `export_key()`, and `import_keys(..., name=...)`.
129
+ `decrypt()` tries every stored key.
130
+ - Password mode: `encrypt(data, password=...)` stretches the password with scrypt and
131
+ does not touch the key store.
132
+ - `decrypt(..., max_age=SECONDS)` rejects old tokens with `TokenExpiredError`.
133
+ - `DecryptionError` and `TokenExpiredError` (both subclasses of `DecodingError`), and
134
+ the `DEFAULT_KEY` constant.
135
+ - `yace-codec encrypt`, `yace-codec decrypt` (with `--password`, `--key`, and
136
+ `--max-age`), and `yace-codec keys list|export|import`. `keys import` needs
137
+ `--name NAME` or `--all-keys`. `YACE_CODEC_PASSWORD` can supply the password.
138
+
139
+ ### Changed
140
+
141
+ - `decode()` on a `yace2_` token points to `decrypt()`, and `decrypt()` on an
142
+ encoded token points to `decode()`.
143
+ - `import_tables()` refuses secret key entries; import them with `import_keys()`.
144
+
145
+ ## [0.1.0] - 2026-10-14
146
+
147
+ First release on PyPI, as `yace-codec` (import name `yace_codec`).
148
+
149
+ ### Added
150
+
151
+ - `yace_codec` package with `Codec`, `encode()`, `decode()`, `parse_header()`, and
152
+ `encode_bytes()` / `decode_bytes()` for binary data and any Unicode text.
153
+ - `KeyStore`: a JSON key store in the per-user data directory (override with
154
+ `YACE_CODEC_KEYSTORE`). It writes atomically, uses a lock file so concurrent
155
+ writers never lose tables, keeps the file's permissions, and can export and import
156
+ table families. `import_tables(..., family=...)` imports a single family.
157
+ - `yace-codec` command (also `python -m yace_codec`) with `encode`, `decode`, and
158
+ `tables path|list|export|import`. `tables import` needs `--family NAME` (or
159
+ `--all-families`), so a shared file cannot add tables for a family you did not
160
+ expect, and it lists the tables it adds.
161
+ - Decoding checks that a token's number of noise chunks matches its length, which
162
+ catches many truncated tokens.
163
+ - Tokens and JSON files saved as UTF-16 or with a byte order mark (as Windows
164
+ PowerShell writes them) are accepted.
165
+ - An exception hierarchy under `YaceError`, type hints (`py.typed`), and runnable
166
+ examples.
167
+
168
+ ### Changed
169
+
170
+ - The scripts in `encoder/` were replaced by the package. The algorithm, the table
171
+ format (`encodings.json`), and the token format are unchanged. Old tokens decode
172
+ with the package. New tokens decode with the original scripts when the package
173
+ generated the tables.
174
+ - New tables cover all of `string.printable` (tab, carriage return, vertical tab, and
175
+ form feed were added) and never share a code between characters, spaces, and bins.
176
+ - Tables and per-token randomness come from `secrets.SystemRandom`.
177
+ - Errors raise exceptions instead of printing a message and calling `exit()`.
178
+ - Without a name, the family `default` is used instead of random letters.
179
+ - Encoding needs a family name of 1–64 ASCII letters or underscores, also for
180
+ existing families. Families with other names can still be decoded.
181
+ - Encoding is refused when `len(text) × length ** iterations` exceeds
182
+ 2<sup>25</sup> (`MAX_ENCODED_CHARS`); with bins, tokens reach about
183
+ 1.25 × 2<sup>25</sup> characters.
184
+
185
+ ### Fixed
186
+
187
+ - Characters missing from a table were copied into the token unencoded, which
188
+ corrupted it. They now raise `UnsupportedCharacterError`.
189
+ - Shared codes in tables from the original generator could make decoding return
190
+ garbled text. The encoder no longer emits a shared space or bin code, and the
191
+ decoder recovers many affected legacy tokens.
192
+ - Empty input crashed, a code length of 1 hung, and family names with repeated
193
+ letters (such as `hello`) were rejected.
194
+ - Tables were written into the source directory with a truncate-then-write, so a
195
+ crash could erase them. They are now written atomically to a key store file.
196
+ - Importing the scripts configured the root logger and wrapped standard output, and
197
+ every encode logged three debug entries to `errors.log` for each encoding layer.
198
+
199
+ ### Removed
200
+
201
+ - `encoder/encodings.json`, the tables of the original scripts. Keep a copy if you
202
+ still have tokens made with them (see the README's migration section).
203
+ - `randomizer_data.json`, `errors.log`, and `update.log`.
204
+ - The deprecated `encoder (beta).py` and the unfinished `analyzer.py` file encoder
205
+ (use `yace-codec encode FILE` or `--binary` instead).
206
+ - Scratch files unrelated to the encoder, and compiled `__pycache__` files.
207
+
208
+ [0.3.0]: https://github.com/thisismudith/YACE/compare/v0.2.1...v0.3.0
209
+ [0.2.1]: https://github.com/thisismudith/YACE/compare/v0.2.0...v0.2.1
210
+ [0.2.0]: https://github.com/thisismudith/YACE/compare/v0.1.0...v0.2.0
211
+ [0.1.0]: https://github.com/thisismudith/YACE/releases/tag/v0.1.0
@@ -1,3 +1,5 @@
1
1
  include CHANGELOG.md
2
+ include SECURITY.md
2
3
  graft examples
4
+ graft tests
3
5
  global-exclude *.py[cod] __pycache__ .DS_Store