first commit
This commit is contained in:
54
docs/foundation/data/packer/src/chunked/crypto/aead.md
Normal file
54
docs/foundation/data/packer/src/chunked/crypto/aead.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# aead
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Wraps `@suaveplan/crypto.aeadEncrypt` / `aeadDecrypt` (XChaCha20-Poly1305) into helpers that match the v1 chunk wire format, where the ciphertext and Poly1305 tag are stored in separate fields rather than as the noble-style concatenated `ciphertext || tag` buffer. Also provides the deterministic per-chunk nonce derivation used by the chunked packer.
|
||||
|
||||
## Features
|
||||
|
||||
- `aeadSeal(key, nonce, plaintext)` — encrypts and returns `{ ciphertext, aeadTag }` as detached `Uint8Array` instances.
|
||||
- `aeadOpen(key, nonce, ciphertext, aeadTag)` — re-joins the two and decrypts; throws on tag mismatch.
|
||||
- `deriveChunkNonce(baseNonce, chunkId)` — `baseNonce[0..4] XOR chunkId-as-u32-BE`, deterministic and unique per chunk.
|
||||
- All inputs validated; failures wrapped as `PackerError(PACKER.ENCRYPTION_FAILED)`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { aeadSeal, aeadOpen, deriveChunkNonce } from "@suaveplan/packer/chunked";
|
||||
|
||||
const fileKey = new Uint8Array(32); // caller-supplied
|
||||
const baseNonce = crypto.getRandomValues(new Uint8Array(24));
|
||||
const nonce = deriveChunkNonce(baseNonce, 0);
|
||||
const { ciphertext, aeadTag } = aeadSeal(fileKey, nonce, plaintext);
|
||||
const back = aeadOpen(fileKey, nonce, ciphertext, aeadTag);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { aeadSeal, deriveChunkNonce } from "@suaveplan/packer/chunked";
|
||||
|
||||
// Seal each chunk with a derived nonce so the manifest only stores baseNonce.
|
||||
function sealAll(plaintexts: Uint8Array[], fileKey: Uint8Array, baseNonce: Uint8Array) {
|
||||
return plaintexts.map((p, i) => {
|
||||
const nonce = deriveChunkNonce(baseNonce, i);
|
||||
const { ciphertext, aeadTag } = aeadSeal(fileKey, nonce, p);
|
||||
return { ciphertext, aeadTag, nonce };
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- **`AeadSealResult`** — `{ ciphertext: Uint8Array; aeadTag: Uint8Array }`.
|
||||
- **`aeadSeal(key, nonce, plaintext): AeadSealResult`** — `key` 32 B, `nonce` 24 B. Returns ciphertext (same length as plaintext) and 16-byte tag.
|
||||
- **`aeadOpen(key, nonce, ciphertext, aeadTag): Uint8Array`** — returns plaintext. Throws `PackerError(PACKER.ENCRYPTION_FAILED)` on tag mismatch or invalid lengths.
|
||||
- **`deriveChunkNonce(baseNonce, chunkId): Uint8Array`** — 24-byte nonce, deterministic per `(baseNonce, chunkId)` pair.
|
||||
- **Constants:** `AEAD_KEY_LEN = 32`, `AEAD_NONCE_LEN = 24`, `AEAD_TAG_LEN = 16`, `FILE_ID_LEN = 32`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The seal helper detaches the returned `ciphertext` and `aeadTag` from the underlying combined buffer with `new Uint8Array(view)` so callers can mutate one without aliasing the other. Nonce derivation XORs only the first 32 bits to keep the rest of `baseNonce` intact — the manifest's `baseNonce` plus a `chunkId` is sufficient to reconstruct any chunk's nonce. The tag length is fixed at 16 (Poly1305); `AEAD_TAG_LEN` is exported for callers writing their own decoders.
|
||||
Reference in New Issue
Block a user