pq_crypto-seal 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/FORMAT.md +10 -1
- data/GET_STARTED.md +10 -0
- data/README.md +19 -3
- data/RELEASING.md +1 -1
- data/SECURITY.md +18 -2
- data/VENDORING.md +6 -0
- data/lib/pq_crypto/seal/binary.rb +50 -41
- data/lib/pq_crypto/seal/core.rb +184 -337
- data/lib/pq_crypto/seal/envelope.rb +158 -0
- data/lib/pq_crypto/seal/files.rb +142 -0
- data/lib/pq_crypto/seal/format.rb +193 -165
- data/lib/pq_crypto/seal/io.rb +85 -290
- data/lib/pq_crypto/seal/io_helpers.rb +184 -0
- data/lib/pq_crypto/seal/models.rb +46 -0
- data/lib/pq_crypto/seal/padding.rb +183 -28
- data/lib/pq_crypto/seal/recipients.rb +245 -0
- data/lib/pq_crypto/seal/resource_limits.rb +56 -0
- data/lib/pq_crypto/seal/secrets.rb +21 -0
- data/lib/pq_crypto/seal/streaming.rb +244 -0
- data/lib/pq_crypto/seal/version.rb +2 -1
- data/lib/pq_crypto/seal.rb +17 -5
- data/pq_crypto-seal.gemspec +23 -8
- metadata +11 -94
- data/.github/workflows/ci.yml +0 -66
- data/Gemfile +0 -7
- data/Rakefile +0 -19
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l.c +0 -246
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_aesni.c +0 -73
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_aesni.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_altivec.c +0 -70
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_altivec.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_common.h +0 -691
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_aes.c +0 -77
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_aes.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_sha3.c +0 -86
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_sha3.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_soft.c +0 -63
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_soft.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/implementations.h +0 -40
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2.c +0 -247
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_aesni.c +0 -108
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_aesni.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_altivec.c +0 -103
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_altivec.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_avx2.c +0 -79
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_avx2.h +0 -11
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_common.h +0 -795
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_neon_aes.c +0 -111
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_neon_aes.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_soft.c +0 -96
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_soft.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/implementations.h +0 -40
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4.c +0 -252
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_aesni.c +0 -117
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_aesni.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_altivec.c +0 -111
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_altivec.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx2.c +0 -112
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx2.h +0 -11
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx512.c +0 -85
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx512.h +0 -11
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_common.h +0 -808
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_neon_aes.c +0 -119
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_neon_aes.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_soft.c +0 -104
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_soft.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/implementations.h +0 -41
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2.c +0 -247
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_aesni.c +0 -103
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_aesni.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_altivec.c +0 -101
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_altivec.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_avx2.c +0 -74
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_avx2.h +0 -11
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_common.h +0 -790
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_neon_aes.c +0 -109
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_neon_aes.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_soft.c +0 -91
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_soft.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/implementations.h +0 -41
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4.c +0 -252
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_aesni.c +0 -112
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_aesni.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_altivec.c +0 -109
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_altivec.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx2.c +0 -107
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx2.h +0 -11
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx512.c +0 -79
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx512.h +0 -11
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_common.h +0 -805
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_neon_aes.c +0 -117
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_neon_aes.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_soft.c +0 -99
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_soft.h +0 -9
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/implementations.h +0 -42
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf.c +0 -87
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128l.c +0 -20
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128x2.c +0 -20
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128x4.c +0 -20
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256.c +0 -20
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256x2.c +0 -20
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256x4.c +0 -20
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_internal.h +0 -152
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_merkle.c +0 -268
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_merkle.h +0 -165
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_variant.h +0 -1119
- data/fuzz/decrypt_fuzz.rb +0 -119
- data/script/vendor_libs.rb +0 -79
- data/test/aegis_vectors_test.rb +0 -54
- data/test/golden_vectors_test.rb +0 -183
- data/test/io_test.rb +0 -125
- data/test/native_test.rb +0 -36
- data/test/seal_test.rb +0 -238
- data/test/test_helper.rb +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa301e0c50869cf3f9e1fec6924920573f895a4aa3ba9cf66cf63675a1ed0f60
|
|
4
|
+
data.tar.gz: 73f8cb33894474e63326d0ad43cad5e4e230c4c3050f5e145a7e67e9966ca027
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6749ce2e5b6e26d85bf33cd0aa93a4ce82b8fb710bbfc550404551567eab4006649e03f14088cc266786dbc9a6eb358367605eaf1145c6482857c0f6be1ba595
|
|
7
|
+
data.tar.gz: 61fbbb576c26adb08279357ed800d5245e80d3e6b264992e4afcc7a30972b8fdeae9621fd30bc9a5fcac407d004d72a07925c26e0614cfaaa38e2d504e3d5bf6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
- Release hygiene: CI Actions pinned by commit SHA, `permissions: contents: read`,
|
|
6
|
+
fuzz + gem-smoke + `release_contract_check` jobs; ignore `.DS_Store` / binaries.
|
|
7
|
+
- Aggressive internal refactor: parsing, recipient wrapping, one-shot operations,
|
|
8
|
+
streaming, atomic files, padding policies, and resource limits now live in
|
|
9
|
+
focused objects instead of large branching methods. Public API and wire v1
|
|
10
|
+
remain unchanged.
|
|
11
|
+
- Padding enforcement now validates both policy id and the canonical target;
|
|
12
|
+
parameterized fixed/bucket requirements cannot masquerade as one another.
|
|
13
|
+
- Added exact deterministic envelope/stream equivalence, official X-Wing
|
|
14
|
+
draft-10 decapsulation KATs, partial-read/write regression tests, and a
|
|
15
|
+
release-contract checker.
|
|
16
|
+
- Release gem contains production code plus only the AEGIS-256 sources needed
|
|
17
|
+
to compile; tests, CI, fuzz harnesses, RAF, and unused AEGIS families stay out.
|
|
18
|
+
- CI restores pinned Actions, sanitizer fuzz smoke, and isolated built-gem E2E.
|
|
19
|
+
|
|
20
|
+
- IO: all output paths use `write_all` (reject silent partial writes).
|
|
21
|
+
- Decrypt APIs accept `required_padding:` and can enforce Padmé / none / fixed /
|
|
22
|
+
buckets after successful AEAD (wire format unchanged).
|
|
23
|
+
- Runtime dependency pinned to `pq_crypto = 0.6.4`.
|
|
24
|
+
- Resource limits applied to `inspect_envelope`, `rebuild_recipients`,
|
|
25
|
+
`rotate_dek`, and `rebuild_recipients_file`.
|
|
26
|
+
- Default one-shot limits lowered to 64 MiB (use file/IO APIs for larger docs).
|
|
27
|
+
- Document that `rotate_dek` allocates a new `payload_id`.
|
|
28
|
+
- CI: Actions pinned by commit SHA; `permissions: contents: read`; fuzz and
|
|
29
|
+
gem-smoke jobs restored.
|
|
30
|
+
- Repository hygiene: ignore `.DS_Store` and built binaries.
|
|
31
|
+
|
|
3
32
|
## 0.1.0
|
|
4
33
|
|
|
34
|
+
|
|
5
35
|
- AEGIS streaming state rejects `update`/`final` before `initialize` (`mode` guard).
|
|
6
36
|
- Encrypt path wipes the internal plaintext copy in `ensure` (caller buffers unchanged).
|
|
7
37
|
- CI: Actions pinned by commit SHA, `permissions: contents: read`, fuzz + gem-smoke jobs.
|
data/FORMAT.md
CHANGED
|
@@ -131,9 +131,18 @@ slot_size: 2048 bytes (configurable 2048..8192, multiple of 256)
|
|
|
131
131
|
recipient_capacity: 4 (maximum 32; never derived automatically from ACL size)
|
|
132
132
|
padding: Padmé over the complete final envelope size
|
|
133
133
|
max_staging_bytes: ~1 GiB + private-metadata ceiling
|
|
134
|
-
max_plaintext_bytes
|
|
134
|
+
max_plaintext_bytes:64 MiB by default
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
Parsers reject trailing bytes on the one-shot and default IO paths. Framed
|
|
138
138
|
stream consumers that intentionally embed one envelope inside a larger stream
|
|
139
139
|
must use `encrypt_frame_io` / `decrypt_frame_io`.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
## Receiver-side padding checks (0.1.1+)
|
|
143
|
+
|
|
144
|
+
`padding_policy_id` is authenticated but does not by itself encode fixed targets
|
|
145
|
+
or bucket lists. Decryptors that need enforcement pass `required_padding:`. The
|
|
146
|
+
receiver verifies the authenticated policy id and recomputes the canonical target
|
|
147
|
+
from the authenticated inner lengths. Fixed and bucket policies require the
|
|
148
|
+
expected target or bucket list from the application.
|
data/GET_STARTED.md
CHANGED
|
@@ -28,3 +28,13 @@ Recipient-section rebuilds always require the application's complete,
|
|
|
28
28
|
authoritative public-key ACL. They do not revoke access to plaintext or old
|
|
29
29
|
envelope copies. Use `rotate_dek`/`rotate_dek_file` when a new payload key and
|
|
30
30
|
full re-encryption are required.
|
|
31
|
+
|
|
32
|
+
## Large documents
|
|
33
|
+
|
|
34
|
+
Default one-shot limits are 64 MiB (`max_plaintext_bytes` / related staging and
|
|
35
|
+
envelope ceilings). For larger objects use `encrypt_file` / `decrypt_file` or
|
|
36
|
+
`encrypt_io` / `decrypt_io` and raise the limits explicitly, for example:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
PQCrypto::Seal.decrypt_file(src, dst, with: credentials, max_plaintext_bytes: 512 * 1024 * 1024)
|
|
40
|
+
```
|
data/README.md
CHANGED
|
@@ -12,10 +12,10 @@ random DEK → AEGIS-256 → document
|
|
|
12
12
|
`libaegis` 0.10.3 is vendored and compiled into the extension. The existing
|
|
13
13
|
`pq_crypto` gem supplies the hybrid KEM and OpenSSL-backed primitives.
|
|
14
14
|
|
|
15
|
-
> **Status:** 0.1.
|
|
15
|
+
> **Status:** 0.1.1 is experimental cryptographic software; format v1; not
|
|
16
16
|
> independently audited. Read `SECURITY.md` before using it for irreplaceable data.
|
|
17
17
|
>
|
|
18
|
-
> `wrap_suite_id = 1` is pinned to `:ml_kem_768_x25519_xwing` and `pq_crypto
|
|
18
|
+
> `wrap_suite_id = 1` is pinned to `:ml_kem_768_x25519_xwing` and `pq_crypto = 0.6.4`.
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
|
|
@@ -129,7 +129,7 @@ rotated = PQCrypto::Seal.rotate_dek(
|
|
|
129
129
|
|
|
130
130
|
`rebuild_recipients` preserves the DEK and encrypted payload. It is an
|
|
131
131
|
operational migration of the current canonical copy, not protection against old
|
|
132
|
-
saved envelopes. `rotate_dek` creates a new DEK and re-encrypts the payload; it
|
|
132
|
+
saved envelopes. `rotate_dek` creates a new DEK, a **new payload_id**, and re-encrypts the payload; it
|
|
133
133
|
still cannot erase knowledge from prior copies. Rotation preserves the current
|
|
134
134
|
final envelope size by default (`padding: :preserve`); pass `:padme`, `:none`, or
|
|
135
135
|
an explicit padding policy to recalculate it.
|
|
@@ -213,3 +213,19 @@ Set `PQC_SEAL_SANITIZE=1` when compiling under ASan/UBSan. The suite covers
|
|
|
213
213
|
AEGIS one-shot/incremental equivalence, tampering, multi-recipient opening,
|
|
214
214
|
full-envelope padding, recipient rebuilds, staged file publication, and parser
|
|
215
215
|
limits.
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
## Padding enforcement on decrypt
|
|
219
|
+
|
|
220
|
+
After AEAD verification you may require a padding policy:
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
PQCrypto::Seal.decrypt(envelope, with: credentials, required_padding: :padme)
|
|
224
|
+
PQCrypto::Seal.decrypt(envelope, with: credentials, required_padding: :from_header)
|
|
225
|
+
PQCrypto::Seal.decrypt(envelope, with: credentials, required_padding: { to: 4096 })
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Omitting `required_padding` keeps padding enforcement optional. When supplied,
|
|
229
|
+
the decryptor verifies both the authenticated policy id and the canonical target
|
|
230
|
+
computed from the authenticated content and metadata lengths. Fixed and bucket
|
|
231
|
+
policies require the expected target or bucket list from the application.
|
data/RELEASING.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Releasing
|
|
2
2
|
|
|
3
3
|
1. Run `bundle exec ruby script/vendor_libs.rb --check`.
|
|
4
|
-
2. Confirm `pq_crypto` dependency remains
|
|
4
|
+
2. Confirm `pq_crypto` dependency remains `= 0.6.4` and `WRAP_KEM_ALGORITHM`
|
|
5
5
|
is still `:ml_kem_768_x25519_xwing` with the documented sizes.
|
|
6
6
|
3. Run the full CI matrix and sanitizer job.
|
|
7
7
|
4. Build with `gem build pq_crypto-seal.gemspec`.
|
data/SECURITY.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Security
|
|
2
2
|
|
|
3
3
|
This project has not received an independent cryptographic or implementation
|
|
4
|
-
audit. Do not treat version 0.1.
|
|
4
|
+
audit. Do not treat version 0.1.1 as a substitute for a reviewed storage design.
|
|
5
5
|
|
|
6
6
|
Experimental cryptographic software; format v1; not independently audited.
|
|
7
7
|
|
|
@@ -44,6 +44,22 @@ callers that need residual-data hygiene must clear their own buffers.
|
|
|
44
44
|
`Opened#data` / `Opened#metadata` returned from `open` are the caller's
|
|
45
45
|
responsibility after use.
|
|
46
46
|
|
|
47
|
+
|
|
48
|
+
## payload_id stability
|
|
49
|
+
|
|
50
|
+
`payload_id` is stable across `rebuild_recipients` / add / drop operations.
|
|
51
|
+
`rotate_dek` re-encrypts the payload with a fresh DEK and **allocates a new
|
|
52
|
+
`payload_id`** — treat the result as a new document identity. Applications that
|
|
53
|
+
need a stable external id across DEK rotation must track it outside the envelope.
|
|
54
|
+
|
|
55
|
+
## Padding policy enforcement
|
|
56
|
+
|
|
57
|
+
The authenticated header carries `padding_policy_id` only. Receivers that require
|
|
58
|
+
a specific length-hiding policy should pass `required_padding:` to decrypt/open
|
|
59
|
+
(for example `required_padding: :padme` or `required_padding: :from_header`).
|
|
60
|
+
The receiver then checks both the policy id and the canonical target computed from
|
|
61
|
+
authenticated inner lengths. Without that argument the field is informational.
|
|
62
|
+
|
|
47
63
|
## Envelope digests
|
|
48
64
|
|
|
49
65
|
`Seal.digest` hashes the complete envelope, including the mutable recipient
|
|
@@ -77,7 +93,7 @@ forensics may still retain remnants; use a suitably protected staging filesystem
|
|
|
77
93
|
|
|
78
94
|
`wrap_suite_id = 1` is permanently bound to MLKEM768-X25519 / X-Wing (draft-10
|
|
79
95
|
compatible) with fixed public-key (1216), ciphertext (1120), and shared-secret
|
|
80
|
-
(32) sizes, as implemented by `pq_crypto
|
|
96
|
+
(32) sizes, as implemented by `pq_crypto = 0.6.4`. Seal does not follow
|
|
81
97
|
`HybridKEM::CANONICAL_ALGORITHM`; a future change of that constant must not
|
|
82
98
|
alter suite 1 wire bytes. Always generate keys with
|
|
83
99
|
`PQCrypto::HybridKEM.generate(PQCrypto::Seal::WRAP_KEM_ALGORITHM)`.
|
data/VENDORING.md
CHANGED
|
@@ -12,3 +12,9 @@ libaegis 0.10.3.
|
|
|
12
12
|
The complete source snapshot is retained, while the Ruby extension compiles only the AEGIS-256 and common implementation files it exposes. No system libaegis is
|
|
13
13
|
loaded at runtime. Update the version, archive checksum, source snapshot, KATs,
|
|
14
14
|
and cross-backend tests together.
|
|
15
|
+
|
|
16
|
+
The git tree keeps the full upstream snapshot so `script/vendor_libs.rb --check`
|
|
17
|
+
can prove byte-identity against the audited archive. The published gem package
|
|
18
|
+
ships only the AEGIS-256 family plus shared `common`/`include` sources required
|
|
19
|
+
to compile the extension (see `pq_crypto-seal.gemspec`); unused families and RAF
|
|
20
|
+
remain in the repository for provenance and are not loaded at runtime.
|
|
@@ -3,59 +3,68 @@
|
|
|
3
3
|
module PQCrypto
|
|
4
4
|
module Seal
|
|
5
5
|
module Binary
|
|
6
|
-
|
|
6
|
+
INTEGER_TYPES = {
|
|
7
|
+
u8: [1, "C", 0xff],
|
|
8
|
+
u16: [2, "n", 0xffff],
|
|
9
|
+
u32: [4, "N", 0xffff_ffff],
|
|
10
|
+
u64: [8, "Q>", 0xffff_ffff_ffff_ffff]
|
|
11
|
+
}.freeze
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
end
|
|
13
|
+
class Reader
|
|
14
|
+
attr_reader :offset
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
def initialize(bytes, offset = 0)
|
|
17
|
+
@bytes = String(bytes).b
|
|
18
|
+
@offset = Integer(offset)
|
|
19
|
+
end
|
|
15
20
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
INTEGER_TYPES.each do |name, (length, directive, _max)|
|
|
22
|
+
define_method(name) { bytes(length).unpack1(directive) }
|
|
23
|
+
end
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
def bytes(length)
|
|
26
|
+
length = Integer(length)
|
|
27
|
+
Binary.ensure_available!(@bytes, offset, length)
|
|
28
|
+
value = @bytes.byteslice(offset, length).b
|
|
29
|
+
@offset += length
|
|
30
|
+
value
|
|
31
|
+
end
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
def finished?
|
|
34
|
+
offset == @bytes.bytesize
|
|
35
|
+
end
|
|
27
36
|
end
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
class << self
|
|
39
|
+
INTEGER_TYPES.each do |name, (_length, directive, max)|
|
|
40
|
+
define_method(name) { |value| [integer!(value, max)].pack(directive) }
|
|
41
|
+
define_method("read_#{name}") { |bytes, offset| read_with(bytes, offset, &name) }
|
|
42
|
+
end
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
end
|
|
44
|
+
def read_bytes(bytes, offset, length)
|
|
45
|
+
read_with(bytes, offset) { |reader| reader.bytes(length) }
|
|
46
|
+
end
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
[bytes.byteslice(offset, 8).unpack1("Q>"), offset + 8]
|
|
42
|
-
end
|
|
48
|
+
def ensure_available!(bytes, offset, length)
|
|
49
|
+
offset, length = Integer(offset), Integer(length)
|
|
43
50
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
[bytes.byteslice(offset, length).b, offset + length]
|
|
48
|
-
end
|
|
51
|
+
raise FormatError, "invalid offset" if offset.negative? || length.negative?
|
|
52
|
+
raise FormatError, "truncated envelope" if offset > bytes.bytesize || length > bytes.bytesize - offset
|
|
53
|
+
end
|
|
49
54
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
def integer!(value, max)
|
|
56
|
+
number = Integer(value)
|
|
57
|
+
raise RangeError, "integer is out of range" if number.negative? || number > max
|
|
58
|
+
|
|
59
|
+
number
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
def read_with(bytes, offset)
|
|
65
|
+
reader = Reader.new(bytes, offset)
|
|
66
|
+
[yield(reader), reader.offset]
|
|
67
|
+
end
|
|
59
68
|
end
|
|
60
69
|
end
|
|
61
70
|
end
|