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>
4.0 KiB
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
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.