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.
- yace_codec-0.3.0/CHANGELOG.md +211 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/MANIFEST.in +2 -0
- yace_codec-0.3.0/PKG-INFO +852 -0
- yace_codec-0.3.0/README.md +809 -0
- yace_codec-0.3.0/SECURITY.md +213 -0
- yace_codec-0.3.0/examples/encryption.py +30 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/pyproject.toml +27 -11
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/__init__.py +27 -2
- yace_codec-0.3.0/src/yace_codec/_algorithms.py +263 -0
- yace_codec-0.3.0/src/yace_codec/_files.py +120 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/_text.py +14 -8
- yace_codec-0.3.0/src/yace_codec/_winsec.py +164 -0
- yace_codec-0.3.0/src/yace_codec/cli.py +711 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/codec.py +427 -60
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/errors.py +15 -1
- yace_codec-0.3.0/src/yace_codec/keybackends.py +439 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/keystore.py +224 -58
- yace_codec-0.3.0/src/yace_codec/sealed.py +974 -0
- yace_codec-0.3.0/src/yace_codec.egg-info/PKG-INFO +852 -0
- yace_codec-0.3.0/src/yace_codec.egg-info/SOURCES.txt +56 -0
- yace_codec-0.3.0/src/yace_codec.egg-info/requires.txt +12 -0
- yace_codec-0.3.0/tests/conftest.py +122 -0
- yace_codec-0.3.0/tests/fixtures/legacy_keystore.json +1235 -0
- yace_codec-0.3.0/tests/fixtures/legacy_tokens.json +350 -0
- yace_codec-0.3.0/tests/legacy_reference.py +74 -0
- yace_codec-0.3.0/tests/test_aad.py +69 -0
- yace_codec-0.3.0/tests/test_cli.py +264 -0
- yace_codec-0.3.0/tests/test_cli_encryption.py +270 -0
- yace_codec-0.3.0/tests/test_cli_robustness.py +128 -0
- yace_codec-0.3.0/tests/test_codec.py +462 -0
- yace_codec-0.3.0/tests/test_examples.py +38 -0
- yace_codec-0.3.0/tests/test_format.py +284 -0
- yace_codec-0.3.0/tests/test_key_backends.py +219 -0
- yace_codec-0.3.0/tests/test_key_store_robustness.py +204 -0
- yace_codec-0.3.0/tests/test_keystore.py +411 -0
- yace_codec-0.3.0/tests/test_malformed.py +91 -0
- yace_codec-0.3.0/tests/test_output_format.py +195 -0
- yace_codec-0.3.0/tests/test_properties.py +61 -0
- yace_codec-0.3.0/tests/test_raw_keys.py +79 -0
- yace_codec-0.3.0/tests/test_robustness.py +264 -0
- yace_codec-0.3.0/tests/test_spec_independent.py +117 -0
- yace_codec-0.3.0/tests/test_stream.py +318 -0
- yace_codec-0.3.0/tests/test_tables.py +198 -0
- yace_codec-0.3.0/tests/test_vectors.py +70 -0
- yace_codec-0.3.0/tests/vectors/generate.py +114 -0
- yace_codec-0.3.0/tests/vectors/legacy.json +42 -0
- yace_codec-0.3.0/tests/vectors/v3.json +491 -0
- yace_codec-0.2.0/CHANGELOG.md +0 -96
- yace_codec-0.2.0/PKG-INFO +0 -847
- yace_codec-0.2.0/README.md +0 -814
- yace_codec-0.2.0/src/yace_codec/cli.py +0 -413
- yace_codec-0.2.0/src/yace_codec/sealed.py +0 -228
- yace_codec-0.2.0/src/yace_codec.egg-info/PKG-INFO +0 -847
- yace_codec-0.2.0/src/yace_codec.egg-info/SOURCES.txt +0 -23
- {yace_codec-0.2.0 → yace_codec-0.3.0}/LICENSE +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/examples/bytes_and_unicode.py +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/examples/quickstart.py +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/examples/share_tables.py +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/setup.cfg +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/__main__.py +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/py.typed +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec/tables.py +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec.egg-info/dependency_links.txt +0 -0
- {yace_codec-0.2.0 → yace_codec-0.3.0}/src/yace_codec.egg-info/entry_points.txt +0 -0
- {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
|