First public release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# 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
|
||||
|
||||
```
|
||||
npm install @extant2000/claim-check
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT. See [LICENSE](LICENSE).
|
||||
Reference in New Issue
Block a user