Nhảy tới nội dung

Key Management & Cryptographic Integrity

EDH's confidentiality rests on keys the operator does not hold, and its data-yield integrity rests on proofs that cannot be forged. Both collapse quietly if the underlying material is generated or verified weakly: a key derived from a fast hash, a passphrase drawn from a small space, or a "proof" that checks nothing. These failures are invisible in normal operation — everything works — and only surface under an attacker who is specifically looking. The requirements here keep the cryptography real, not merely present.

The primitives themselves (Curve25519, XSalsa20-Poly1305, SHA-256, scrypt) are assumed sound. This page is about using them correctly.

All key material must come from a CSPRNG

KM-1 (MUST). Every secret value — private keys, symmetric keys, nonces, salts, recovery phrases, passphrases, and authentication challenges — MUST be generated with a cryptographically secure random number generator (e.g. crypto.randomBytes, the WebCrypto crypto.getRandomValues, or an equivalent OS CSPRNG). A non-cryptographic PRNG (e.g. Math.random) MUST NOT be used for any of these. Generated secrets protecting health data or keys MUST carry at least 128 bits of entropy.

Rationale. Math.random is fast and predictable; its output can be reconstructed from observed values and is not uniformly distributed. A passphrase built by, say, shuffling a small word list and selecting a few words has both problems at once — a non-cryptographic source and a tiny keyspace (a few tens of thousands of possibilities), which is exhaustively searchable in moments. If such a passphrase protects an encrypted wallet or seed, the encryption is decorative. Entropy and source are independent requirements; both are mandatory.

Conformance check. Audit every site that produces a key, nonce, salt, mnemonic, or passphrase and confirm the source is a CSPRNG and the entropy is at least 128 bits. There should be no Math.random on any key path.

Password-derived keys must use a hard KDF with a random salt

KM-2 (MUST). A key derived from a human password or passphrase MUST be produced with a memory-hard or iteration-hard password KDF — scrypt, Argon2, or PBKDF2 with a high iteration count (≥ 210,000 for PBKDF2-SHA256) — using a per-record, randomly generated salt. A bare or iterated plain hash (e.g. SHA-256 looped over the input) MUST NOT be used as a password KDF, and the salt MUST NOT be a public or deterministic value (such as an account address).

Rationale. A password KDF has one job: make each guess expensive so that offline brute-force of a stolen ciphertext is infeasible. Plain SHA-256, even iterated, is enormously faster per guess than a hard KDF and is GPU/ASIC-friendly — it does not meet that job. A public, deterministic salt (the account address is both) removes the per-target cost and enables precomputation across users. If an at-rest store leaks, the only thing standing between the attacker and the plaintext is the cost-per-guess of the KDF; a weak KDF makes that cost negligible. When two correct implementations already exist in a codebase, the at-rest store MUST NOT be the one using the weak path.

KM-3 (SHOULD). When the KDF or its parameters change, records SHOULD carry a version/parameter envelope and be transparently re-derived/re-encrypted at the next unlock, so existing data migrates without a flag day.

Conformance check. Confirm the at-rest key path uses scrypt/Argon2/PBKDF2-≥210k with a random per-record salt, and that the salt is not derived from any public identifier.

Server-custodied key material must meet the same bar and be authenticated

KM-4 (MUST). Where the architecture has the server custody password-encrypted key material on a user's behalf, the encrypting passphrase MUST satisfy KM-1 and KM-2, and retrieval of that material MUST be authenticated and authorized per AC-1. Server-side custody MUST NOT weaken the derivation relative to client-side custody.

Rationale. Server custody concentrates risk: one stolen datastore exposes many users' encrypted keys at once. That raises, not lowers, the bar on the protecting passphrase and on who may fetch the ciphertext. An unauthenticated "retrieve encrypted key by address" endpoint combined with a low-entropy passphrase is a complete account-key compromise for anyone who can name the address.

Integrity proofs must be keyed, and verification must check the key

KM-5 (MUST). A value presented as proof of authenticity or integrity (a MAC, an "oracle proof", an attestation) MUST be produced with a secret key (HMAC or a signature) and MUST be verified by recomputing/validating it under that key. Verifying a proof by hashing the proof itself and comparing to a companion hash is NOT verification — the hash of attacker-supplied bytes always matches — and MUST NOT be used.

Rationale. Integrity requires a secret the attacker does not have. If verification only checks that hash(proof) == proofHash, an attacker fabricates any proof, computes its hash, and both fields agree — the check confirms nothing about origin. For EDH's data-yield oracle this would let anyone forge compliance proofs, defeating the integrity the marketplace pays for. The verification path must reference the key, not a self-consistent pair of values.

Conformance check. Submit a fabricated proof with a correctly computed companion hash and no knowledge of the oracle key. Verification MUST reject it.

Keys for MACs/oracles must be managed and fail closed

KM-6 (MUST). Secrets that key a MAC, oracle, or signing operation MUST be provisioned from a secrets manager (see Operational Security) and MUST NOT be hardcoded in source, CI configuration, or container environment literals. If such a secret is absent at startup in production, the service MUST fail closed (refuse to start or refuse the operation) rather than silently substitute an ephemeral or default key.

Rationale. A hardcoded oracle/MAC key is readable by anyone with source or task-definition access, which makes forgery trivial regardless of KM-5. A silent if missing, generate a random key fallback is worse than a crash: it produces a service that "works" but whose proofs are unverifiable across restarts and whose security depends on an accident of configuration. Fail-closed makes a misconfiguration loud instead of silently insecure.

Summary

IDRequirementPrevents
KM-1CSPRNG for all secrets; ≥128-bit entropyPredictable / brute-forceable keys & passphrases
KM-2Hard KDF + random, non-public salt for password keysOffline brute-force of at-rest data
KM-3Versioned envelope + lazy re-key on parameter changeStuck-on-weak-params data
KM-4Server-custodied keys meet KM-1/2 and are auth'd to fetchMass key compromise from one datastore
KM-5Keyed integrity proofs; verify under the keyForged "proofs" that check nothing
KM-6Manage MAC/oracle keys; fail closed if absentTrivial forgery; silently insecure fallback