The README's install line failed: the package was never published, and nothing told npm where the @extant2000 scope lives. A tag like v1.2.3 now publishes to this project's registry with CI_JOB_TOKEN, and the README sets the scope's registry before installing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
4.0 KiB
Markdown
101 lines
4.0 KiB
Markdown
# ClaimCheck
|
|
|
|
Checks the cryptographic claims a system makes, such as "end-to-end
|
|
encrypted", against the keys, ciphers and transport settings it actually
|
|
uses.
|
|
|
|
## What it does and why
|
|
|
|
A common pattern: a feature is described as encrypted, and it is. AES-256-GCM,
|
|
correctly applied, ciphertext at rest. It is still not end-to-end encrypted,
|
|
because the server holds the key. Every cryptographic choice is sound, the
|
|
claim is false, and no review of the algorithm would catch it.
|
|
|
|
That asymmetry is what this library is built around. **Cipher strength is the
|
|
easy half and rarely the part that is wrong. The part that goes wrong is key
|
|
custody: who can read the plaintext.** A claim of "end-to-end" or
|
|
"zero-knowledge" is a claim about custody. An operator holding the key
|
|
falsifies it no matter how strong the cipher is.
|
|
|
|
In the case above, ClaimCheck fails the end-to-end claim and names who holds
|
|
the key. It passes the at-rest claim, because that one is true. Only the
|
|
claim that goes beyond its custody fails.
|
|
|
|
## What it checks
|
|
|
|
| Claim | Checked against |
|
|
|---|---|
|
|
| `end-to-end-encrypted` | Key custody. Fails if `server`, `operator` or `third-party` holds any key. |
|
|
| `zero-knowledge` | The same custody rule. |
|
|
| `encrypted-at-rest` | An at-rest cipher exists, and it is not broken and not ECB. |
|
|
| `encrypted-in-transit` | A pinned minimum TLS version of 1.2 or higher. |
|
|
| `passwords-hashed` | A password KDF (bcrypt, scrypt, argon2, PBKDF2), not a fast hash and not reversible encryption. |
|
|
| `forward-secrecy` | Every listed cipher suite uses an ephemeral (ECDHE or DHE) key exchange. |
|
|
|
|
Broken primitives (MD5, SHA-1, DES, 3DES, RC4, any ECB mode) are reported
|
|
even when nothing was claimed about them. Not advertising a property is no
|
|
reason to leave MD5 in a signature path.
|
|
|
|
A key held only in an `hsm` does not break a custody claim, because the
|
|
operator cannot read it. A `third-party` holder does: "end-to-end with a
|
|
vendor in the middle" is the marketing sense of the phrase, not the
|
|
technical one.
|
|
|
|
## Missing evidence is not a pass
|
|
|
|
A claim with nothing in the inventory to support it is reported as NOT
|
|
ASSESSED. "No key custody was described" is not evidence that custody is
|
|
safe. It only shows that custody was not described. The same applies to a
|
|
TLS setup with no pinned minimum version: the result would depend on a
|
|
runtime default that can change, so it is not assessed.
|
|
|
|
The library is pure. It takes a description of your system and returns
|
|
findings, with no filesystem access, network calls or crypto calls. The
|
|
output is in the `@extant2000/evidence-record` format, and every conclusion
|
|
cites the file or location it rests on.
|
|
|
|
## Usage
|
|
|
|
```ts
|
|
import { checkClaims, formatClaims, type CryptoInventory } from '@extant2000/claim-check'
|
|
|
|
const inventory: CryptoInventory = {
|
|
claims: ['end-to-end-encrypted', 'encrypted-at-rest', 'passwords-hashed'],
|
|
keys: [{
|
|
keyId: 'NOTES_KEY',
|
|
heldBy: ['server', 'operator'], // list every party that can obtain it
|
|
location: 'config/app.env',
|
|
protects: 'note bodies',
|
|
}],
|
|
ciphers: [
|
|
{ algorithm: 'AES', mode: 'GCM', keyBits: 256, purpose: 'at-rest', where: 'src/notes/store.ts', line: 88 },
|
|
{ algorithm: 'argon2id', purpose: 'password', where: 'src/auth.ts', line: 30 },
|
|
],
|
|
transport: [{ minTlsVersion: '1.2', where: 'config/tls.yml' }],
|
|
}
|
|
|
|
const report = checkClaims(inventory) // structured report
|
|
console.log(formatClaims(inventory)) // the same report as text
|
|
```
|
|
|
|
`heldBy` decides the custody checks, and an optimistic answer defeats the
|
|
library. If the operator can read the environment variable that holds the
|
|
key, list `operator`.
|
|
|
|
For this inventory the end-to-end claim fails at critical severity, citing
|
|
`config/app.env`, while the at-rest and password claims pass.
|
|
|
|
## Install
|
|
|
|
The package is published to the GitLab package registry, so point the
|
|
`@extant2000` scope there first:
|
|
|
|
```
|
|
npm config set @extant2000:registry https://gitlab.com/api/v4/packages/npm/
|
|
npm install @extant2000/claim-check
|
|
```
|
|
|
|
## License
|
|
|
|
MIT. See [LICENSE](LICENSE).
|