@obrioxia/client-decryptor
v1.0.0
Published
Decrypt Obrioxia export bundles locally using your RSA private key. No Python required. Zero dependencies.
Maintainers
Readme
@obrioxia/client-decryptor
Decrypt Obrioxia export bundles locally using your RSA private key. No Python required. Zero external dependencies. Node 18+.
Install
npm i @obrioxia/client-decryptorCLI
After install, the obrioxia-decrypt command is available:
obrioxia-decrypt --bundle export.json --private-key private.pemOr run directly without installing:
npx @obrioxia/client-decryptor --bundle export.json --private-key private.pemExit codes:
| Code | Meaning | |------|---------| | 0 | At least one field decrypted successfully | | 2 | Bundle processed, but no fields were decryptable | | 1 | Fatal error (bad args, file not found) |
Programmatic Usage
import { readFileSync } from 'node:fs';
import { decryptExportBundle } from '@obrioxia/client-decryptor';
const result = await decryptExportBundle({
privateKeyPem: readFileSync('private.pem', 'utf-8'),
bundleJson: JSON.parse(readFileSync('export.json', 'utf-8')),
});
console.log(result.decrypted_fields); // { name: "Alice", email: "alice@..." }
console.log(result.undecryptable_fields); // [] or [{ field, reason }]
console.log(result.bundle_fingerprint); // SHA-256 hex
console.log(result.metadata); // { decision_id, key_epoch, ... }
console.log(result.verification); // { is_shredded, ... }How to Get an Export Bundle
curl -H "x-api-key: YOUR_KEY" \
https://api.obrioxia.com/api/incidents/DECISION_ID/export \
-o export.jsonOutput Fields
| Field | Type | Description |
|-------|------|-------------|
| decrypted_fields | object | Map of field name → decrypted plaintext value |
| undecryptable_fields | array | List of { field, reason, detail? } for fields that could not be decrypted |
| bundle_fingerprint | string | SHA-256 hex digest of the canonical bundle |
| metadata | object | decision_id, key_epoch, timestamp_utc |
| verification | object | is_shredded, signature status if present |
undecryptable_fields Reasons
| Reason | Meaning |
|--------|---------|
| missing_wrapped_dek | The bundle has no _wrapped_dek — record may have been crypto-shredded |
| unwrap_failed | RSA key unwrap failed — wrong private key or corrupted DEK |
| shredded_or_missing | The ciphertext field is null or empty |
| decrypt_failed | AES-GCM decryption failed — AAD mismatch or corrupted ciphertext |
Crypto Protocol
- DEK wrapping: RSA-OAEP with SHA-256
- Field encryption: AES-256-GCM per field
- Field blob format:
base64(nonce_12B || ciphertext || GCM_tag_16B) - AAD:
decision_id::field_name(UTF-8) - The server never sees your private key
Tests
cd client_sdk/node
node --test