{"id":50551815,"url":"https://github.com/supermagnum/splitdisk","last_synced_at":"2026-06-04T04:02:14.843Z","repository":{"id":349687644,"uuid":"1196684034","full_name":"Supermagnum/splitdisk","owner":"Supermagnum","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-07T04:06:46.000Z","size":81,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-07T06:17:03.155Z","etag":null,"topics":["brainpool","brainpoolp256r1","drive","encryption","framework","luks","shamir-secret-sharing"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Supermagnum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T00:04:51.000Z","updated_at":"2026-04-07T04:06:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Supermagnum/splitdisk","commit_stats":null,"previous_names":["supermagnum/splitdisk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/Supermagnum/splitdisk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Supermagnum%2Fsplitdisk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Supermagnum%2Fsplitdisk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Supermagnum%2Fsplitdisk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Supermagnum%2Fsplitdisk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Supermagnum","download_url":"https://codeload.github.com/Supermagnum/splitdisk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Supermagnum%2Fsplitdisk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33888302,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["brainpool","brainpoolp256r1","drive","encryption","framework","luks","shamir-secret-sharing"],"created_at":"2026-06-04T04:02:13.522Z","updated_at":"2026-06-04T04:02:14.836Z","avatar_url":"https://github.com/Supermagnum.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# SplitDisk — Tool Specification\n\n**Version:** 0.2-draft  \n**Language:** Rust (stable toolchain, `x86_64-unknown-linux-musl` for embedded binary)  \n**Status:** Specification only — not yet implemented  \n**License:** GPL-3.0 (matching Galdralag-firmware)  \n**CESS conformance:** CESS-FULL (targets CESS v0.2-draft; see §4 and §15)  \n**Glossary:** [Plain-language definitions of technical terms](docs/GLOSSARY.md)  \n**AI contributors:** [AGENTS.md](AGENTS.md) (see also [CLAUDE.md](CLAUDE.md)); Cursor rules live in `.cursor/rules/*.mdc`\n\n---\n\n## 1. Purpose\n\nSplitDisk is a command-line tool and initramfs-resident assembly agent for\nsplitting a disk image or filesystem into **k-of-n physical USB shares**, each\nbootable, such that any k drives inserted in sequence can reconstruct and write\nthe original content to a target disk. Members holding drives are not informed\nof their share index, the total number of shares, or the threshold required.\n\nOptional integration with the **Galdralag hardware security token** (Baochip-1x\nrunning Galdralag firmware) provides on-device PIN verification, Shamir\nkey-share storage, and Brainpool/post-quantum encryption without requiring any\ncustom host-side cryptographic driver beyond a standard CCID stack.\n\n---\n\n## 2. Threat Model and Design Goals\n\n| Goal | Description |\n|------|-------------|\n| **Holder anonymity** | A drive holder does not know their share index, the value of k or n, or the content. |\n| **Coercion resistance** | A holder genuinely cannot answer \"how many others are there?\" or \"are you required?\" |\n| **Physical confidentiality** | Drive contents look like opaque binary blobs. No filenames, labels, or metadata reveal the scheme. |\n| **Multi-factor unlock** | Each drive requires PIN (≥ 5 alphanumeric characters) and optionally biometric before its share is accepted. |\n| **Long-term security** | Encryption must remain secure for decades. Hybrid classical + post-quantum where available. |\n| **Fault tolerance** | n \u003e k so that absent or unavailable members do not prevent reconstruction. |\n| **Integrity** | Each share chunk is hashed with BLAKE3; corruption is detected before reconstruction begins. |\n| **Resumable assembly** | If power is lost mid-write, assembly can resume from a checkpoint. |\n| **Verified write** | Reconstruction is dry-run tested against the source hash before the operator is permitted to destroy the original. |\n| **Source destruction** | After verified write, the source drive or image file can be overwritten with random data so the plaintext cannot be recovered from the enrollment machine. |\n| **CESS conformance** | All cryptographic primitives conform to CESS v0.2 algorithm registry; NSA-designed and NIST-only primitives are excluded. |\n\nNon-goals: network transmission of shares, online key management, integration\nwith cloud storage.\n\n---\n\n## 3. Architecture Overview\n\nSplitDisk consists of two programs:\n\n- **`splitdisk-create`** — run once on an air-gapped enrollment machine to\n  produce n share carriers (USB drives, Galdralag tokens, or a mix) from a\n  source disk image.\n- **`splitdisk-assemble`** — a statically linked binary embedded in the\n  initramfs of every share USB drive, or invoked on the assembly machine when\n  all shares are Galdralag tokens. Orchestrates reconstruction.\n\n**USB drive mode:**\n\n```\n┌─────────────────────────────────────────────────────┐\n│                  splitdisk-create                   │\n│                                                     │\n│  source image ──► [encrypt] ──► [Reed-Solomon       │\n│                                  split k-of-n]      │\n│                       │                             │\n│               [SSS split of session key]            │\n│                       │                             │\n│          ┌────────────┼────────────┐                │\n│        USB 1        USB 2  ...   USB n              │\n│   (bootable,    (bootable,      (bootable,           │\n│    chunk 1,      chunk 2,        chunk n,            │\n│    key share 1)  key share 2)    key share n)        │\n└─────────────────────────────────────────────────────┘\n\nAt boot time on any share USB:\n\n┌─────────────────────────────────────────────────────┐\n│               splitdisk-assemble (initramfs)        │\n│                                                     │\n│  Boot USB ──► read own chunk + key share silently   │\n│  Loop until k shares collected:                     │\n│    insert drive ──► PIN check ──► biometric check   │\n│    ──► read chunk + key share ──► progress bar +1   │\n│  Reconstruct session key via SSS                    │\n│  Decrypt + Reed-Solomon decode                      │\n│  Write to target disk with checkpoint journal        │\n└─────────────────────────────────────────────────────┘\n```\n\n**Galdralag token mode:**\n\n```\n┌─────────────────────────────────────────────────────┐\n│                  splitdisk-create                   │\n│                                                     │\n│  source image ──► [encrypt] ──► [Reed-Solomon       │\n│                                  split k-of-n]      │\n│                       │                             │\n│               [SSS split of session key]            │\n│                       │                             │\n│     ┌─────────────────┼─────────────────┐           │\n│  Token 1           Token 2  ...      Token n        │\n│  RRAM: key share   RRAM: key share   RRAM: key share│\n│  SD:   chunk 1     SD:   chunk 2     SD:   chunk n  │\n└─────────────────────────────────────────────────────┘\n\nAt assembly time (any machine, no bootable share USB needed):\n\n┌─────────────────────────────────────────────────────┐\n│               splitdisk-assemble                    │\n│                                                     │\n│  Loop until k tokens inserted:                      │\n│    insert token ──► CCID session ──► PIN on token   │\n│    ──► read chunk from SD ──► read key share        │\n│        from RRAM ──► progress bar +1                │\n│  Reconstruct session key via SSS                    │\n│  Decrypt + Reed-Solomon decode                      │\n│  Write to target disk with checkpoint journal        │\n└─────────────────────────────────────────────────────┘\n```\n\nMixed mode (some USB drives, some tokens) is also supported within the same\nscheme. The assembly agent handles both share types transparently.\n\n---\n\n## 4. Cryptographic Design\n\nSplitDisk targets **CESS-FULL** conformance (CESS v0.2-draft). All primitives\nare drawn from the CESS Algorithm Registry. NSA-designed primitives (AES,\nSHA-2, SHA-3) and NIST-only curves (P-256, P-384, P-521) are excluded. ML-KEM\nis excluded per CESS policy; FrodoKEM-1344 is the approved post-quantum KEM\nwhere PQ is enabled.\n\n### 4.1 Encryption Layer\n\nAll encryption uses a **hybrid** scheme for long-term security:\n\n```\nSession key: 32 random bytes from hardware TRNG or OS CSPRNG\n\nClassical KEM:    Ephemeral ECDH over BrainpoolP384r1 (default, outer session)\n                  or BrainpoolP512r1 (inner profile, --cipher brainpool512)\n                  RFC 5639, BSI TR-03111\n                  Shared secret: x-coordinate, fixed-length big-endian encoding\n                  Point validation: mandatory (invalid curve points rejected)\n\nPost-quantum KEM: FrodoKEM-1344 (feature-gated, --features pq)\n                  Hybrid only; never standalone\n\nKDF:              HKDF-BLAKE3 (RFC 5869 structure, HMAC-BLAKE3 as PRF)\n                  info strings: \"cess-kem-v1\" (KEM), \"cess-pin-v1\" (PIN wrap),\n                  \"cess-outer-envelope-v1\" (outer K_outer)\n\nCombined (hybrid):\n  session_key = HKDF-BLAKE3(\n    ikm  = classical_shared_secret || pq_shared_secret,\n    info = \"cess-kem-v1\"\n  )\n\nBulk cipher (select one):\n  ChaCha20-Poly1305           (RFC 8439, 32-byte key, 12-byte nonce)  [default]\n  Serpent-256-CTR + Poly1305  (32-byte key, RFC 8439 MAC layout)\n  Twofish-256-CTR + Poly1305  (256-bit key, 128-bit block, same MAC layout)\n  Cascade: ChaCha20-Poly1305 inner + Serpent-256-CTR+Poly1305 outer\n  Cascade: ChaCha20-Poly1305 inner + Twofish-256-CTR+Poly1305 outer\n  Cascade: Twofish inner      + Serpent outer\n  Triple cascade: ChaCha inner + Serpent middle + Twofish outer\n\nSuite selection is encoded as a CESS suite_id (16-bit, see §15).\n```\n\n**Outer wrapper (Mode A):** When `--mode a` is used (default for USB drive\nmode), an outer ChaCha20-Poly1305 layer keyed from ephemeral BrainpoolP384r1\nECDH conceals the suite_id and inner ciphertext from observers. The suite_id\nis never transmitted in cleartext. See CESS v0.2 §6.6 and §8.\n\n**Simple mode (Mode B):** When `--mode b` is used, the cipher profile is\npre-agreed and no suite_id appears on the wire. Suitable for simpler deployments\nwhere metadata concealment is not required.\n\n**BrainpoolP256r1 + ChaCha20-Poly1305:** A lightweight profile using\nBrainpoolP256r1 is available for less sensitive deployments via\n`--cipher brainpool256`. This operates in Mode B (no outer wrapper, suite\nprofile visible); it is outside the CESS-FULL normative profile but supported\nas a documented extension. Shared secret is the x-coordinate, 32-byte\nfixed-length big-endian encoding.\n\n### 4.2 Data Splitting\n\nReed-Solomon erasure coding splits the encrypted image into n chunks, any k\nof which suffice to reconstruct.\n\n```\nchunk_size ≈ image_size / k   (plus RS parity overhead ~10%)\n```\n\nEach chunk is prefixed with a BLAKE3 hash for integrity verification before\nreconstruction begins.\n\n### 4.3 Key Splitting\n\nThe 32-byte session key is split using Shamir's Secret Sharing over GF(2⁸)\n(reduction polynomial `x^8 + x^4 + x^3 + x + 1`, identical to CESS §5.1)\ninto n shares, threshold k.\n\nEach key share is encrypted at rest on the USB using the PIN-derived key\n(see §5.2), so raw access to the drive bytes does not expose the share.\n\n### 4.4 Crate Policy\n\nAll cryptographic primitives come from audited crates. Nothing is implemented\nin-tree. Crates are selected for `no_std` + musl compatibility where required\nby the embedded initramfs binary.\n\n| Crate | Purpose | Audit status |\n|-------|---------|--------------|\n| `chacha20poly1305` | Bulk AEAD (primary) | RustCrypto audited |\n| `serpent` | Serpent-256 bulk cipher | Review pending |\n| `twofish` | Twofish-256 bulk cipher | Review pending |\n| `poly1305` | MAC for Serpent/Twofish CTR modes | RustCrypto audited |\n| `p384` | BrainpoolP384r1 ECDH base | RustCrypto audited |\n| `hkdf` | HKDF structure (RFC 5869) | RustCrypto audited |\n| `blake3` | BLAKE3 integrity and HKDF PRF | Audited (NCC Group, Kudelski) |\n| `argon2` | PIN hashing (Argon2id) | RustCrypto audited |\n| `vsss-rs` | Shamir secret sharing GF(2⁸) | Independent review |\n| `reed-solomon-erasure` | Data splitting | Review pending |\n| `zeroize` | Secret memory clearing | RustCrypto audited |\n| `subtle` | Constant-time comparisons | RustCrypto audited |\n| `sequoia-openpgp` | Optional GPG envelope (Brainpool keys) | Active maintenance |\n| `pqcrypto-frodo` | FrodoKEM-1344 (feature-gated) | Pending independent audit |\n\nOne can also check integrity of crates with this when the pr is closed:\nhttps://github.com/rust-lang/cargo/issues/16850\n\n\nPost-quantum features are gated behind `--features pq` and carry a warning\nthat the underlying crates have not been independently audited, matching the\npolicy in Galdralag firmware and CESS §7.3.\n\n---\n\n## 5. Authentication Per Drive\n\n### 5.1 Factor Overview\n\nEach drive requires the holder to present:\n\n| Factor | Mechanism | Required |\n|--------|-----------|----------|\n| Something they have | The USB drive | Always |\n| Something they know | PIN ≥ 5 alphanumeric characters | Always |\n| Something they are | Biometric (iris/retina scan) | Optional per drive |\n\nAll factors are checked before the drive's key share is released into memory.\nFailure in any factor does not indicate which factor failed — the UI reports\nonly \"Authentication failed. Please remove drive.\"\n\n### 5.2 PIN\n\n- Minimum length: 5 alphanumeric characters, enforced at input boundary before\n  any hash comparison.\n- Hashing: Argon2id (RFC 9106) with a per-drive random 16-byte salt,\n  memory = 64 MiB, iterations = 3, parallelism = 4 (CESS §5.4 profile).\n- The Argon2id hash is stored in the drive's hidden data partition.\n- PIN-derived key: `K_pin = HKDF-BLAKE3(argon2id_output, info=\"cess-pin-v1\")`\n  → 32 bytes, wrapping the key share with ChaCha20-Poly1305 (default) or the\n  profile's registered AEAD.\n- Attempt limit: 5 per drive insertion (configurable 3–10 at creation time).\n- On limit exhaustion: drive is ejected and must be re-inserted. The PIN hash\n  is not modified (no lockout wipe, unlike a hardware token).\n- Cool-down: 30-second delay after each failed attempt.\n\n### 5.3 Biometric\n\nBiometric support is **optional** and configured per drive at enrollment time.\n\nSupported hardware: USB iris scanners with Linux drivers (e.g. IriShield MK\nseries, or compatible devices exposing a V4L2 or proprietary SDK interface).\n\nEnrollment flow:\n1. Capture iris image on the enrollment machine using the scanner.\n2. Extract ISO/IEC 19794-6 feature template.\n3. Encrypt template with `K_pin` (PIN must be correct first).\n4. Store encrypted template in hidden partition alongside PIN hash.\n\nVerification flow:\n1. PIN verified first.\n2. `K_pin` derived → template decrypted in memory.\n3. Iris capture performed.\n4. Feature extraction and comparison against stored template, within a\n   configurable tolerance threshold (Hamming distance on iris codes,\n   threshold ≤ 0.32 by default, following ISO recommendations).\n5. On match: key share released. Template and derived keys zeroized from memory.\n6. On failure: 3 biometric attempts per successful PIN entry, then drive ejected.\n\nThe biometric template never leaves the drive unencrypted. No central biometric\ndatabase exists.\n\n### 5.4 Galdralag Hardware Token Integration (Optional)\n\nWhen `--galdralag` mode is used, the Galdralag Baochip-1x token is the\n**complete share** — no separate USB drive is needed or issued to the member.\nThe token holds both the encrypted data chunk and the key share in its\non-device storage (RRAM vault or optional SD card), and presents itself to\nthe assembly machine over USB. The member carries only the token.\n\n**Storage tiers on the token:**\n\n| Storage | Capacity | Used for |\n|---------|----------|----------|\n| RRAM vault | Small (key material only) | SSS key share, PIN policy, metadata |\n| Optional SD card | Large (bulk data) | Encrypted data chunk |\n\nIf the token has an SD card fitted, the data chunk is stored there. If no SD\ncard is present, the token cannot hold a data chunk and `--galdralag` mode\nrequires SD card presence — `splitdisk-create` will check and abort if the\ncard is absent or insufficient at enrollment time.\n\n**What the token provides during assembly:**\n\n- **Data chunk** — streamed from SD card over USB to the assembly machine.\n- **Key share** — held in RRAM vault, released only after PIN and optional\n  biometric verification on the token itself.\n- **BrainpoolP384r1 or BrainpoolP512r1 ECDH** — wraps the key share\n  in transit using the token's on-device keys.\n- **Authenticated ephemeral ECDH session** — forward-secret channel between\n  token and assembly agent; the key share never appears on the USB bus in\n  plaintext.\n- **Hardware TRNG** — used for all randomness during enrollment and assembly.\n- **Hardware PIN counter with zeroization** — 3–10 configurable attempts;\n  on exhaustion the token zeroizes its RRAM, permanently destroying the share.\n\n**Assembly agent behaviour:**\n\nThe agent detects a Galdralag token by its CCID descriptor on any USB port.\nWhen detected, it opens an ephemeral ECDH session, requests PIN entry (handled\non the token's own PIN policy, not the software attempt counter), reads the\ndata chunk from the SD card, and retrieves the decrypted key share over the\nauthenticated channel. No separate USB drive insertion is prompted for that\nshare.\n\n**Requirements:**\n\n- CCID-capable host (`pcscd` + `ccid` driver included in initramfs)\n- Token fitted with SD card of sufficient capacity (`ceil(image_size / k) + 10%`)\n- Token provisioned at enrollment via `galdra device shamir-store` and\n  `galdra device chunk-write`\n\n**Mixed modes** are supported: some members can hold USB drives (standard\nmode) and others can hold Galdralag tokens, within the same k-of-n scheme.\nThe assembly agent handles both transparently in the same insertion loop.\n\n---\n\n## 6. USB Drive Layout\n\nEach drive presents a standard bootable layout. To an observer mounting the\ndrive on any operating system, it looks like a minimal bootable Linux USB with\nsome unremarkable binary files.\n\n```\n/dev/sdX1   FAT32  ~256 MiB   EFI System Partition\n  /EFI/BOOT/BOOTX64.EFI       Standard EFI bootloader (GRUB or systemd-boot)\n  /boot/vmlinuz               Linux kernel (minimal config)\n  /boot/initramfs.img         initramfs containing splitdisk-assemble\n\n/dev/sdX2   ext4   remainder  System partition\n  /usr/bin/splitdisk-assemble (statically linked, stripped)\n  /share/chunk.bin            Encrypted RS data chunk (opaque bytes)\n  /share/auth/pin.hash        Argon2id PIN hash\n  /share/auth/retina.enc      Encrypted biometric template (if enrolled)\n  /share/meta.bin             Encrypted metadata (share index, k, n, chunk hash)\n```\n\n`meta.bin` is encrypted with `K_pin`, so share index and scheme parameters are\nnot visible without the correct PIN. The partition label is blank. The volume\nUUID is randomly generated and not reused across drives.\n\nGRUB is configured with `GRUB_TIMEOUT=0` and no menu. The screen is blank\nduring boot until the assembly agent TUI appears.\n\n---\n\n## 7. Assembly Agent TUI\n\nThe TUI is built with `ratatui` and runs fullscreen. It intentionally reveals\nno information about share indices or member count.\n\n### 7.1 Startup Screen\n\n```\n┌─────────────────────────────────────────────────────┐\n│                                                     │\n│            SECURE ASSEMBLY SYSTEM                   │\n│                                                     │\n│   Insert drives one at a time.                      │\n│   Remove each drive when prompted.                  │\n│                                                     │\n│   Progress: ░░░░░░░░░░                              │\n│                                                     │\n│   Waiting for first drive...                        │\n│                                                     │\n└─────────────────────────────────────────────────────┘\n```\n\nThe booting drive's own share is read silently and automatically at startup.\nProgress advances by one without user interaction.\n\n### 7.2 PIN Entry\n\n```\n┌─────────────────────────────────────────────────────┐\n│                                                     │\n│   Drive detected.                                   │\n│                                                     │\n│   Enter PIN: ▓▓▓▓▓▓▓▓░                             │\n│              (minimum 5 characters)                 │\n│                                                     │\n│   Press Enter to confirm.                           │\n│                                                     │\n└─────────────────────────────────────────────────────┘\n```\n\nInput is masked with `▓` characters. Backspace supported. No character count\ndisplayed (avoid leaking PIN length).\n\n### 7.3 Biometric Prompt (if enrolled)\n\n```\n┌─────────────────────────────────────────────────────┐\n│                                                     │\n│   Look into the scanner.                            │\n│                                                     │\n│   [ Scanning... ████████░░ ]                        │\n│                                                     │\n└─────────────────────────────────────────────────────┘\n```\n\n### 7.4 Progress\n\n```\n┌─────────────────────────────────────────────────────┐\n│                                                     │\n│            SECURE ASSEMBLY SYSTEM                   │\n│                                                     │\n│   Progress: ████████░░░░░░░░░░░░   3 drives read    │\n│                                                     │\n│   Please insert another drive.                      │\n│                                                     │\n└─────────────────────────────────────────────────────┘\n```\n\nNo member names, no share IDs, no indication of how many remain.\n\n### 7.5 Duplicate Detection\n\nIf the same drive is inserted twice (detected by comparing a hidden drive\nfingerprint stored in `meta.bin`), the progress bar does not advance:\n\n```\n   This drive has already been read. Please insert a different one.\n```\n\nNo indication that it is \"drive 4\" or \"already seen drive 4.\"\n\n### 7.6 Reconstruction\n\nWhen k shares are collected:\n\n```\n┌─────────────────────────────────────────────────────┐\n│                                                     │\n│   All required drives collected.                    │\n│                                                     │\n│   Verifying integrity...      ████████████  100%   │\n│   Reconstructing...           ████████████  100%   │\n│   Decrypting...               ██████░░░░░░   63%   │\n│   Writing to disk...          ████░░░░░░░░   41%   │\n│                                                     │\n│   Target: /dev/sdb  (238.5 GiB)                    │\n│                                                     │\n└─────────────────────────────────────────────────────┘\n```\n\n### 7.7 Target Disk Selection\n\nBefore writing, the agent lists available block devices (excluding share USBs)\nand prompts for confirmation. It checks that the target is large enough and\nwarns if it is not.\n\n### 7.8 Failure Screens\n\nAll failure messages are generic:\n\n```\n   Authentication failed. Please remove drive.\n   Integrity check failed. Drive may be corrupted.\n   Target disk too small. Minimum required: 128.4 GiB.\n```\n\n---\n\n## 8. splitdisk-create CLI\n\n### 8.1 Basic Usage\n\n```bash\nsplitdisk-create \\\n  --input /dev/sda \\\n  --drives /dev/sdb /dev/sdc /dev/sdd /dev/sde /dev/sdf /dev/sdg \\\n  --threshold 3 \\\n  --cipher brainpool384 \\\n  --bulk-cipher chacha20 \\\n  --pin-attempts 5 \\\n  --shred\n```\n\nThis creates a 3-of-6 scheme using BrainpoolP384r1 + ChaCha20-Poly1305 in\nMode A (outer wrapper concealing suite identity). The tool announces required\ndrive sizes, writes all 6 drives, verifies reconstruction with 3 drives, then\noffers to shred the source.\n\n### 8.2 Options\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| `--input \u003cpath\u003e` | Source block device or image file | Required |\n| `--drives \u003cpaths\u003e` | Target USB devices (exactly n) | Required |\n| `--threshold \u003ck\u003e` | Minimum shares for reconstruction | Required |\n| `--cipher \u003cn\u003e` | `brainpool256`, `brainpool384`, `brainpool512` | `brainpool384` |\n| `--bulk-cipher \u003cn\u003e` | `chacha20`, `serpent`, `twofish`, `cascade-cs`, `cascade-ct`, `cascade-ts`, `cascade-cst` | `chacha20` |\n| `--mode \u003cn\u003e` | `a` (outer wrapper, suite concealed) or `b` (pre-agreed, no wrapper) | `a` |\n| `--gpg-recipients \u003cfps\u003e` | Wrap session key for GPG recipients (Brainpool keys) | None |\n| `--pin-attempts \u003cn\u003e` | Failed PIN attempts before cooldown per insertion | `5` |\n| `--biometric` | Enroll biometric at creation time (requires scanner) | Off |\n| `--galdralag` | Store key shares on Galdralag tokens instead of drives | Off |\n| `--features pq` | Enable FrodoKEM-1344 post-quantum hybrid (feature-gated) | Off |\n| `--label \u003ctext\u003e` | Boot-time display label (shown before PIN prompt) | None |\n| `--checkpoint-dir \u003cpath\u003e` | Directory on target disk for resume journal | `/var/splitdisk` |\n| `--shred` | Offer to overwrite source with random data after verified write | Off |\n| `--shred-passes \u003cn\u003e` | Reserved; always 1 (multiple passes not meaningful on modern media) | `1` |\n\n**Bulk cipher shorthand for `--bulk-cipher`:**\n\n| Value | Meaning |\n|-------|---------|\n| `chacha20` | ChaCha20-Poly1305 single layer |\n| `serpent` | Serpent-256-CTR + Poly1305 single layer |\n| `twofish` | Twofish-256-CTR + Poly1305 single layer |\n| `cascade-cs` | ChaCha inner + Serpent outer (CESS default cascade) |\n| `cascade-ct` | ChaCha inner + Twofish outer |\n| `cascade-ts` | Twofish inner + Serpent outer |\n| `cascade-cst` | Triple: ChaCha inner + Serpent middle + Twofish outer |\n\n### 8.3 Pre-flight: Carrier Requirement Announcement\n\nBefore any writes, `splitdisk-create` inspects the source image and the chosen\nk and n parameters, then prints a clear human-readable summary and requires\nexplicit confirmation before proceeding.\n\n**USB drive mode example:**\n\n```\nSource:        /dev/sda  (476.9 GiB)\nScheme:        3-of-6 (any 3 drives reconstruct the content)\nCipher:        BrainpoolP384r1 + ChaCha20-Poly1305  [Mode A]\nCESS suite_id: 0x0001\n\nYou will need:   6 × USB drives, each at least 128 GiB\n                 (chunk size: ~159 GiB per drive including boot environment\n                  and Reed-Solomon parity overhead)\n\nDrives provided: /dev/sdb  256 GiB  ✓\n                 /dev/sdc  256 GiB  ✓\n                 /dev/sdd  256 GiB  ✓\n                 /dev/sde  256 GiB  ✓\n                 /dev/sdf  256 GiB  ✓\n                 /dev/sdg  128 GiB  ✗  INSUFFICIENT — need 159 GiB\n\nWARNING: /dev/sdg is too small. Aborting.\n```\n\n**Galdralag token mode example:**\n\n```\nSource:        /dev/sda  (476.9 GiB)\nScheme:        3-of-6 (any 3 tokens reconstruct the content)\nCipher:        BrainpoolP384r1 + ChaCha20-Poly1305  [Mode A]\nCESS suite_id: 0x0001\n\nYou will need:   6 × Galdralag tokens, each with SD card ≥ 159 GiB\n                 Key shares fit in RRAM — no minimum RRAM size beyond firmware.\n\nTokens detected:\n  Token A  SD: 256 GiB  RRAM: OK  ✓\n  Token B  SD: 256 GiB  RRAM: OK  ✓\n  Token C  SD: 256 GiB  RRAM: OK  ✓\n  Token D  SD: 256 GiB  RRAM: OK  ✓\n  Token E  SD: 256 GiB  RRAM: OK  ✓\n  Token F  SD:  64 GiB  RRAM: OK  ✗  INSUFFICIENT — SD needs ≥ 159 GiB\n\nWARNING: Token F SD card is too small. Aborting.\n```\n\nIf all carriers are sufficient:\n\n```\nAll 6 carriers are sufficient.\n\nThis operation will DESTROY all data on the 6 carriers listed above.\nType YES to continue, or press Ctrl-C to abort: _\n```\n\nRequired size per carrier:\n\n```\nrequired_per_carrier = ceil(image_size / k)\n                     + rs_parity_overhead       (~10% of chunk size)\n                     + boot_environment_size    (512 MiB, USB drives only)\n```\n\n### 8.4 Enrollment Session\n\n`splitdisk-create` performs enrollment interactively after pre-flight passes:\n\n1. Reads and BLAKE3-hashes the source image (streaming, reports progress).\n2. Generates 32-byte session key from hardware TRNG or OS CSPRNG.\n3. Encrypts image with chosen cipher suite (streaming, reports progress).\n4. Splits ciphertext into n chunks via Reed-Solomon.\n5. Splits session key into n shares via SSS (vsss-rs).\n6. For each drive in sequence:\n   a. Writes bootloader, kernel, initramfs (produced by `splitdisk-image`; see §10).\n   b. Writes data chunk.\n   c. Prompts operator to set PIN for this drive (entered twice for confirmation,\n      minimum 5 alphanumeric characters enforced before hashing).\n   d. If `--biometric`: prompts to scan iris for this drive's holder.\n   e. Encrypts key share and metadata with PIN-derived key.\n   f. Writes encrypted share data.\n   g. Reads back and verifies written chunk against source BLAKE3 hash.\n7. **Post-write verification** — see §8.5.\n8. **Source shredding** — see §8.6.\n\nThe session key is zeroized from memory immediately after step 6 completes.\n\n### 8.5 Post-write Verification\n\nAfter all n drives are written, `splitdisk-create` performs a mandatory\nreconstruction dry-run using exactly k drives to confirm the scheme is viable\nbefore the operator is permitted to shred the source.\n\nThe operator is prompted to insert any k of the n drives one at a time. For\neach inserted drive:\n\n```\nVerification — insert any 3 of your 6 drives for reconstruction test.\n\nDrive 1 of 3: insert a drive now...\n  ✓ Drive accepted. Chunk hash verified.\n\nDrive 2 of 3: insert a drive now...\n  ✓ Drive accepted. Chunk hash verified.\n\nDrive 3 of 3: insert a drive now...\n  ✓ Drive accepted. Chunk hash verified.\n\nReconstructing session key...   ✓\nDecrypting and decoding...      ✓\nOutput hash matches source:     ✓  (BLAKE3: a3f9…c214)\n\nVerification successful. All 3 tested drives can reconstruct the content.\n```\n\nThe reconstructed output is written to a temporary memory-mapped buffer and\nits BLAKE3 hash is compared against the hash of the source image taken in\nstep 1 of §8.4. The temporary output is zeroized and discarded after\nverification; it is never written to a persistent disk.\n\n**Verification is not optional and cannot be skipped.**\n\n### 8.6 Source Shredding\n\nSource shredding is offered only after §8.5 verification succeeds. It is\nexplicitly opt-in — the operator must pass `--shred` at invocation time, and\nconfirm again interactively before shredding begins.\n\n```\nVerification complete. The source drive or image can now be securely erased.\n\nTarget for shredding:  /dev/sda  (476.9 GiB)\n\nWARNING: This will PERMANENTLY AND IRRECOVERABLY destroy all data on /dev/sda.\n         The content now exists only on the 6 USB drives.\n         Ensure all drives are physically secured before proceeding.\n\nType SHRED to overwrite with random data, or press Ctrl-C to skip: _\n```\n\nShred procedure:\n\n1. Open the source block device or file for writing.\n2. Stream random bytes from the OS CSPRNG (`/dev/urandom` via `getrandom(2)`)\n   over the entire device in 4 MiB blocks, reporting progress.\n3. Call `fsync(2)` after each block to ensure writes reach the storage medium.\n4. On completion, call `ioctl(BLKFLSBUF)` to flush the kernel block cache.\n5. Report final status with bytes written and time elapsed.\n\n```\nShredding /dev/sda...\n\n  ████████████████████████████  100%   476.9 GiB / 476.9 GiB\n  Time elapsed: 14m 32s\n  Bytes written: 512,110,190,592\n\nShred complete. The source has been overwritten with random data.\n```\n\nNotes on shred effectiveness:\n\n- On **HDDs**: a single overwrite pass with random data is sufficient to\n  prevent software-based recovery.\n- On **SSDs and flash storage**: wear levelling may preserve some data in\n  overprovisioned cells. The tool prints a warning for detected SSDs and\n  recommends ATA Secure Erase or NVMe Format after the overwrite.\n- On **image files**: the file is overwritten in place then unlinked. The tool\n  warns that filesystem journalling or snapshots on the host may retain copies.\n\n---\n\n## 9. Checkpoint and Resume\n\nIf assembly is interrupted mid-write, a journal file is written to the target\ndisk tracking which chunks have been fully written, the byte offset of the last\nconfirmed write, and a BLAKE3 hash of each written segment.\n\nOn next boot, if a partial journal is detected, the agent offers to resume\nrather than restart. Resume requires the same k drives to be re-inserted (key\nmaterial is not cached between boots).\n\n---\n\n## 10. Boot Image Build System (`splitdisk-image`)\n\nA dedicated Rust binary, `splitdisk-image`, is responsible for producing the\nbootable per-drive USB image. It is invoked internally by `splitdisk-create`\nduring enrollment (step 6a of §8.4) and can also be run standalone for\ntesting. No external shell scripts, `dracut`, `mkinitcpio`, or manually\nmaintained `cpio` archives are required; the entire boot image is assembled\nfrom Rust.\n\n### 10.1 Design Goals\n\n- **Pure Rust toolchain**: the image builder is a normal Rust binary that runs\n  on the enrollment machine (Linux x86-64). It does not shell out to system\n  tools beyond the minimum required for block device I/O.\n- **Reproducible output**: given the same kernel blob and `splitdisk-assemble`\n  binary, the output image is byte-for-byte identical across runs (except for\n  the per-drive random UUID and share data).\n- **Self-contained**: the `splitdisk-assemble` binary embedded in the initramfs\n  is statically linked against musl libc (`x86_64-unknown-linux-musl`) and\n  requires no shared libraries in the initramfs environment.\n\n### 10.2 Components Produced\n\n`splitdisk-image` produces a raw disk image for a single share USB drive,\ncontaining:\n\n| Component | How produced |\n|-----------|--------------|\n| GPT partition table | Written directly using the `gpt` crate |\n| EFI System Partition (FAT32, ~256 MiB) | Constructed using the `fatfs` crate; contains GRUB EFI binary and GRUB config |\n| GRUB EFI binary | Bundled as a compiled-in byte slice (fetched at build time via `build.rs` from a pinned upstream release, verified by SHA-256 → BLAKE3 of the blob) |\n| Linux kernel (bzImage) | Bundled as a compiled-in byte slice (pinned version, verified) |\n| initramfs (cpio.gz) | Assembled entirely in Rust; see §10.3 |\n| System partition (ext4) | Written using the `ext4-rs` or equivalent crate |\n| Share data | Written to system partition by `splitdisk-create` after image base is laid down |\n\n### 10.3 initramfs Assembly\n\nThe initramfs is a gzip-compressed cpio archive assembled entirely in Rust\nusing the `cpio` crate (or equivalent). It contains the minimum set of\nentries required for `splitdisk-assemble` to run:\n\n```\n/init                       → shell script or compiled init stub invoking\n                              splitdisk-assemble\n/usr/bin/splitdisk-assemble → statically linked, stripped Rust binary\n                              (x86_64-unknown-linux-musl)\n/usr/lib/pcsc/drivers/      → CCID driver shared objects (bundled)\n/etc/reader.conf.d/         → pcscd reader config\n/dev/                       → empty; populated by the kernel at boot\n/proc/                      → empty; mounted by init\n/sys/                       → empty; mounted by init\n/tmp/                       → empty tmpfs mount point\n```\n\n`pcscd` is invoked as a subprocess by `splitdisk-assemble` at runtime (or\nlinked statically if a suitable no_std/musl build is available). The CCID\ndriver `.so` files are bundled as byte slices extracted at build time from a\npinned upstream release and verified by BLAKE3 hash before embedding.\n\nThe `init` entry is a minimal compiled Rust binary (part of the\n`splitdisk-image` crate's output) that mounts `/proc`, `/sys`, and a tmpfs\non `/tmp`, then exec's `splitdisk-assemble`. It does not use a shell.\n\n### 10.4 GRUB Configuration\n\nGRUB is configured with:\n\n```\nset timeout=0\nset default=0\n\nmenuentry \"SplitDisk\" {\n    linux /boot/vmlinuz quiet loglevel=0 rd.udev.log_level=0\n    initrd /boot/initramfs.img\n}\n```\n\nNo menu is shown. The kernel command line suppresses all console output until\n`splitdisk-assemble` takes control of the terminal for its TUI.\n\n### 10.5 Kernel Configuration\n\nThe bundled kernel is built from a minimal `defconfig` plus the following\nadditions, compiled and pinned as a byte slice in `build.rs`:\n\n| Config option | Reason |\n|---------------|--------|\n| `CONFIG_USB_SUPPORT` | USB host stack |\n| `CONFIG_USB_XHCI_HCD` | USB 3.x host controller |\n| `CONFIG_USB_EHCI_HCD` | USB 2.0 host controller |\n| `CONFIG_USB_STORAGE` | USB mass storage (share drives) |\n| `CONFIG_USB_SERIAL` | USB serial (CCID fallback) |\n| `CONFIG_USB_CHIPIDEA` | CCID smartcard transport |\n| `CONFIG_PCMCIA` | Smartcard reader support |\n| `CONFIG_SCSI` | Required for USB storage |\n| `CONFIG_EXT4_FS` | Read system partition |\n| `CONFIG_VFAT_FS` | Read EFI partition |\n| `CONFIG_TMPFS` | /tmp for runtime state |\n| `CONFIG_PROC_FS` | /proc |\n| `CONFIG_SYSFS` | /sys |\n| `CONFIG_TTY` | Terminal for TUI |\n| `CONFIG_VT` | Virtual terminal |\n| `CONFIG_FB` | Framebuffer (TUI rendering) |\n| `CONFIG_DRM` | GPU-neutral display |\n| `CONFIG_CRYPTO_CHACHA20` | Kernel-side not required; userspace only |\n\nNetwork, sound, Bluetooth, Wi-Fi, and all non-essential drivers are disabled.\nThe resulting bzImage is expected to be well under 10 MiB.\n\n### 10.6 Build Reproducibility and Pinning\n\nAll bundled blobs (GRUB EFI binary, Linux kernel bzImage, CCID driver `.so`\nfiles) are:\n\n1. Fetched at crate build time by `build.rs` from pinned upstream URLs.\n2. Verified against a BLAKE3 hash embedded in the source tree.\n3. Embedded as `include_bytes!()` byte slices in the Rust binary.\n\nThis means `splitdisk-image` has no runtime dependency on GRUB, a kernel\nbuild system, or any external initramfs tooling on the enrollment machine.\nA fresh `cargo build` on any Linux x86-64 host with network access and the\nRust stable toolchain produces a functional `splitdisk-image` binary.\n\n### 10.7 Standalone Usage\n\n```bash\n# Produce a base USB image (no share data yet) for testing:\nsplitdisk-image \\\n  --output /tmp/base.img \\\n  --size 512MiB\n\n# Inspect the produced image:\nfdisk -l /tmp/base.img\n```\n\n`splitdisk-create` calls `splitdisk-image` internally and then writes share\ndata into the system partition of the produced image before flashing to the\ntarget USB device.\n\n---\n\n## 11. Workspace Layout\n\n```\nsplitdisk/\n├── AGENTS.md                   (AI contributor guidelines; normative with README)\n├── CLAUDE.md                   (pointer to AGENTS.md for Claude Code)\n├── Cargo.toml                  (workspace)\n├── .cursor/rules/              (Cursor IDE rules, split *.mdc files)\n├── crates/\n│   ├── splitdisk-create/       (enrollment tool)\n│   ├── splitdisk-assemble/     (initramfs agent)\n│   ├── splitdisk-image/        (boot image builder; see §10)\n│   ├── splitdisk-core/         (shared: crypto, RS, SSS wrappers, metadata format)\n│   ├── splitdisk-auth/         (PIN, biometric, Galdralag token integration)\n│   └── splitdisk-tui/          (ratatui UI components)\n└── docs/\n    ├── SPEC.md                 (this document)\n    ├── GLOSSARY.md             (plain-language term definitions)\n    ├── CRYPTO.md               (detailed cryptographic rationale)\n    └── GALDRALAG.md            (Galdralag integration guide)\n```\n\n---\n\n## 12. Galdralag Integration Summary\n\nWhen `--galdralag` is passed to `splitdisk-create`, each member receives only\na **Galdralag Baochip-1x token**. No separate USB drive is issued. The token\nis the complete share — it holds both the encrypted data chunk (on SD card)\nand the key share (in RRAM vault).\n\n| Aspect | USB drive mode | Galdralag token mode |\n|--------|----------------|----------------------|\n| What the member carries | USB drive | Galdralag token only |\n| Data chunk storage | USB drive partition | Token SD card |\n| Key share storage | Encrypted in USB hidden partition | On-device RRAM vault |\n| PIN enforcement | Software attempt counter | Hardware PIN counter with zeroization |\n| Biometric | USB iris scanner + software | Optional; token PIN suffices |\n| Encryption of key share in transit | HKDF-BLAKE3 + ChaCha20-Poly1305 | BrainpoolP384r1 ECDH on-device |\n| Forward secrecy | Not applicable | Authenticated ephemeral ECDH session |\n| TRNG | OS CSPRNG | Hardware TRNG on Baochip-1x |\n| SD card required | No | Yes (for data chunk storage) |\n| Mixed mode with USB shares | N/A | Yes — both types can coexist in one scheme |\n\n---\n\n## 13. Security Considerations\n\n- **Enrollment machine must be air-gapped** and have its memory securely erased\n  after creating drives. `splitdisk-create` calls `zeroize` on all key material,\n  but physical RAM remanence is a risk.\n- **Drive firmware attacks**: an adversary with physical access to a drive before\n  it reaches its holder could modify the bootloader or initramfs. Mitigations:\n  tamper-evident packaging, and optionally signing the initramfs with Ed25519\n  (matching the pattern used by Galdralag firmware's boot0 verification).\n- **Rubber hose or 5$ hammer**: a holder can be coerced into providing their PIN. The k-of-n\n  threshold ensures one holder's coercion is insufficient for reconstruction.\n  The holder genuinely does not know how many others exist.\n- **Share count leakage**: the progress bar reveals how many shares have been\n  collected, which after k successes reveals k to an observer watching the\n  screen. This is an accepted trade-off; the total n remains hidden.\n- **Post-quantum**: FrodoKEM-1344 is feature-gated and marked experimental.\n  Enable only when an independently audited `no_std` Rust crate is available,\n  following the same policy as Galdralag firmware and CESS §7.3.\n- **Biometric template privacy**: templates are stored only on the individual's\n  own drive, encrypted at rest. No operator or other member can access another\n  member's biometric data.\n- **Boot image integrity**: all bundled blobs in `splitdisk-image` are BLAKE3-\n  verified at build time (§10.6). Implementers SHOULD verify the BLAKE3 hashes\n  of pinned blobs out-of-band before shipping drives.\n\n---\n\n## 14. Out of Scope\n\n- Network-based share distribution or retrieval\n- Cloud key management\n- Windows or macOS host support for `splitdisk-create` (Linux only; assembly\n  runs on the embedded Linux in initramfs on any x86-64 machine)\n- WebAuthn / FIDO2\n- VeraCrypt or LUKS integration (SplitDisk manages its own encryption layer)\n\n---\n\n## 15. CESS Conformance and Suite Identifiers\n\nSplitDisk targets **CESS-FULL** conformance (CESS v0.2 ). The following\ntable maps `--cipher` + `--bulk-cipher` combinations to their CESS `suite_id`\nvalues. Suite IDs are used internally and, in Mode A, are transmitted inside\nthe authenticated outer ChaCha20-Poly1305 envelope only — never in cleartext.\n\n| `--cipher` | `--bulk-cipher` | CESS `suite_id` | Notes |\n|------------|-----------------|-----------------|-------|\n| `brainpool384` | `chacha20` | `0x0001` | CESS-CORE default |\n| `brainpool384` | `serpent` | `0x0002` | |\n| `brainpool384` | `cascade-cs` | `0x0003` | CESS default cascade |\n| `brainpool384` | `twofish` | `0x0004` | |\n| `brainpool384` | `cascade-ct` | `0x0005` | |\n| `brainpool384` | `cascade-ts` | `0x0006` | |\n| `brainpool384` | `cascade-cst` | `0x0007` | Triple cascade |\n| `brainpool512` | `chacha20` | `0x0011` | |\n| `brainpool512` | `serpent` | `0x0012` | |\n| `brainpool512` | `cascade-cs` | `0x0013` | |\n| `brainpool512` | `twofish` | `0x0014` | |\n| `brainpool512` | `cascade-ct` | `0x0015` | |\n| `brainpool512` | `cascade-ts` | `0x0016` | |\n| `brainpool512` | `cascade-cst` | `0x0017` | Triple cascade |\n| `brainpool256` | `chacha20` | N/A (Mode B only) | Extension; outside CESS-FULL normative profile |\n\nNote: `suite_id` values above are provisional pending final assignment in\n`ALGORITHM-REGISTRY.md`. The lookup table in that file is authoritative.\n\n---\n\n## 16. Dependencies Summary\n\n```toml\n# Core crypto\nchacha20poly1305 = \"0.10\"\nserpent          = \"0.1\"          # Serpent-256 CTR\ntwofish          = \"0.1\"          # Twofish-256 CTR\npoly1305         = \"0.8\"          # MAC for CTR-mode ciphers\nhkdf             = \"0.12\"\nargon2           = \"0.5\"\nblake3           = \"1\"\nzeroize          = { version = \"1\", features = [\"derive\"] }\nsubtle           = \"2\"\n\n# Curves\np384             = \"0.13\"         # BrainpoolP384r1 / BrainpoolP512r1\n\n# Key splitting\nvsss-rs          = \"3\"            # Shamir, GF(2⁸)\n\n# Data splitting\nreed-solomon-erasure = \"6\"\n\n# Boot image builder (splitdisk-image crate only)\ngpt              = \"3\"            # GPT partition table construction\nfatfs            = \"0.3\"          # FAT32 EFI partition construction\ncpio             = \"0.2\"          # initramfs cpio archive assembly\nflate2           = \"1\"            # gzip compression for initramfs\n\n# TUI\nratatui          = \"0.26\"\n\n# USB / block device I/O\nnix              = \"0.29\"\nrusb             = \"0.9\"          # USB device enumeration\n\n# OpenPGP (optional GPG envelope)\nsequoia-openpgp  = \"1\"\n\n# Post-quantum (feature-gated, experimental)\npqcrypto-frodo   = { version = \"0.1\", optional = true }   # FrodoKEM-1344\n```\n\n---\n\n*This specification is a design document. No warranty of correctness is made.\nCryptographic choices and security decisions should be reviewed by a qualified\ncryptographer before implementation or deployment.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupermagnum%2Fsplitdisk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupermagnum%2Fsplitdisk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupermagnum%2Fsplitdisk/lists"}