Xhold: Digital Evidence Chain of Custody
Forensic evidence split across jurisdictional custodians via XorIDA threshold sharing. HMAC-SHA256 chained audit trail creates tamper-evident custody logs where breaking any link invalidates the chain. No single custodian can access or tamper with evidence alone. Mathematically impossible to reconstruct from fewer than threshold shares.
Executive Summary
Digital forensic evidence must maintain an unbroken chain of custody to be admissible in court. A single compromised custodian can taint an entire case. Xhold splits evidence across multiple independent custodians so that no single entity can access or tamper with evidence alone.
XorIDA threshold sharing over GF(2) provides information-theoretic security. Individual shares reveal zero information about the evidence — not computationally hard to break, but mathematically impossible. A 2-of-3 configuration requires any two custodians to reconstruct the evidence, preventing single-point compromise.
HMAC-SHA256 chained custody events create a tamper-evident audit trail. Each intake, transfer, access, and reconstruction event is linked to the previous via HMAC. Breaking any link invalidates the entire chain from that point forward. Courts can verify integrity without trusting any single party.
SHA-256 evidence hash verification ensures reconstructed evidence matches the original. After XorIDA reconstruction, the package computes SHA-256 over the rebuilt evidence and compares against the intake hash. Mismatch = automatic rejection.
Zero configuration needed. Zero npm runtime dependencies. Runs anywhere the Web Crypto API is available — Node.js 20+, Deno, Bun, Cloudflare Workers. Dual ESM and CJS builds ship in a single package.
Developer Experience
Xhold provides a clean, Result-based API with 7 structured error codes. Every function returns Result<T, ForensicError> for explicit error handling.
Quick Start
import { intakeEvidence, reconstructEvidence } from '@private.me/forensiccustody'; const evidence = new Uint8Array([/* disk image bytes */]); const hmacKey = crypto.getRandomValues(new Uint8Array(32)); const config = { custodians: [ { id: 'PD', name: 'Police Dept', jurisdiction: 'US-CA' }, { id: 'LAB', name: 'Forensic Lab', jurisdiction: 'US-CA' }, { id: 'DA', name: 'District Attorney', jurisdiction: 'US-CA' }, ], threshold: 2, // any 2-of-3 can reconstruct }; const intake = await intakeEvidence(evidence, metadata, config, hmacKey); if (!intake.ok) throw new Error(intake.error.message); // Shares distributed: intake.value.shares // Custody chain: intake.value.custodyChain
Structured Error Handling
All errors are discriminated unions with code and message fields. Pattern match on the code for type-safe error handling.
const result = await reconstructEvidence(shares, hash, actor, key, chain); if (!result.ok) { switch (result.error.code) { case 'INSUFFICIENT_SHARES': console.error('Need more custodian shares'); break; case 'HMAC_FAILED': console.error('Share tampered — integrity check failed'); break; case 'INTEGRITY_FAILED': console.error('Reconstructed evidence hash mismatch'); break; default: console.error(result.error.message); } return; } const { evidence, custodyChain } = result.value;
Error Categories
| Code | When | Recovery |
|---|---|---|
| INVALID_CONFIG | Fewer than 2 custodians or threshold > custodian count | Fix configuration before calling intakeEvidence |
| SPLIT_FAILED | Empty evidence data provided | Verify evidence buffer is not empty |
| HMAC_FAILED | HMAC verification failed on a share or custody event | Evidence tampered — reject and investigate |
| RECONSTRUCT_FAILED | XorIDA reconstruction or unpadding failure | Shares corrupted or incompatible |
| INSUFFICIENT_SHARES | Fewer shares than threshold for a chunk | Collect more custodian shares |
| CHAIN_BROKEN | Custody chain verification detected broken link | Custody audit trail tampered — inadmissible |
| INTEGRITY_FAILED | Reconstructed evidence SHA-256 hash mismatch | Evidence altered — reject and log |
The Problem
Digital evidence custody today relies on procedural controls and single-custodian trust models. A compromised evidence locker, corrupt analyst, or database breach can taint an entire case — and defense attorneys know it.
Single custodian = single point of failure. When one department holds the evidence, that department becomes the target. Insider threats, coercion, and jurisdictional disputes create legal vulnerability.
Paper logs are fragile. Handwritten custody logs, spreadsheets, and database entries can be altered retroactively. Courts must trust the custodian's record-keeping, but that trust is under constant legal attack.
No mathematical proof of integrity. Traditional custody chains rely on policy, not cryptography. There is no mathematical guarantee that evidence wasn't accessed, altered, or reconstructed outside the documented chain.
Jurisdictional custody transfers are risky. Moving evidence between agencies, labs, and prosecutors creates handoff points where integrity can be questioned. Each transfer is an opportunity for chain-of-custody challenges.
| Property | Paper Logs | Database Records | Digital Signatures | Xhold |
|---|---|---|---|---|
| Tamper evidence | Erasable | Mutable DB | Partial | HMAC chain |
| Single custodian risk | Total | Total | Total | Threshold split |
| Insider threat | High | High | High | Requires K of N |
| Mathematical proof | None | None | Signature only | Info-theoretic |
| Court admissibility | Challenged | Challenged | Strong | Verifiable chain |
| Jurisdictional independence | No | No | No | Split custody |
The Old Way
The New Way
Real-World Use Cases
Six scenarios where Xhold replaces single-custodian evidence lockers with split-custody mathematical guarantees.
Federal, state, and local agencies share custody of seized hard drives. 2-of-3 threshold prevents any single agency from unilaterally accessing evidence. HMAC chain proves no tampering.
PD + FBI + Lab splitLegal hold documents split between plaintiff counsel, defendant counsel, and neutral forensic vendor. No party can alter evidence without the others. Chain verifiable in court.
Legal split custodyPhone extractions from Cellebrite split between investigating officer, forensic lab, and DA's office. 2-of-3 reconstruction for trial presentation. SHA-256 hash proves bit-for-bit match.
Mobile device custodyBank fraud evidence split between bank compliance, external auditor, and SEC. Threshold reconstruction for regulatory review. HMAC chain proves no backdated entries.
Regulatory complianceTrial data split between sponsor, CRO, and FDA. 2-of-3 prevents sponsor from altering adverse events. Custody chain proves data integrity for regulatory submission.
FDA 21 CFR Part 11Classified digital evidence split across unclassified, secret, and TS networks. 3-of-5 threshold with air-gapped custodians. Information-theoretic security exceeds AES-256.
Quantum-proof custodySolution Architecture
Three core components: evidence intake via XorIDA splitting, HMAC-chained custody events, and threshold reconstruction with integrity verification.
Evidence Intake
Evidence is chunked (default 1MB), each chunk is padded via PKCS7, split via XorIDA into N shares (one per custodian), and HMAC-signed individually. The initial custody event is created with eventType: 'intake' and linked to the evidence hash.
1. Hash evidence → SHA-256 2. Chunk evidence → 1MB chunks 3. For each chunk: a. Pad → PKCS7 (blockSize = nextOddPrime(N) - 1) b. Split → XorIDA(padded, N, K) c. HMAC each share → HMAC-SHA256(hmacKey, shareData) 4. Create custody event: eventType: 'intake' evidenceHash: SHA-256 from step 1 previousHmac: '' (first event) eventHmac: HMAC-SHA256(hmacKey, canonical(event)) 5. Return IntakeResult: shares + custodyChain
HMAC-Chained Audit Trail
Every custody action (intake, transfer, access, reconstruct, verify, release) creates an HMAC-SHA256 signed event. The event HMAC is computed over canonical serialization of event fields plus the previous event's HMAC. This creates a tamper-evident chain where breaking any link invalidates all subsequent events.
const canonical = [ eventType, caseNumber, itemNumber, actor, timestamp, details, evidenceHash, previousHmac ].join('|'); const eventHmac = await signHMAC(hmacKey, encodeUtf8(canonical)); const event: CustodyEvent = { id: generateUUID(), sequence: previousEvent ? previousEvent.sequence + 1 : 0, eventType, caseNumber, itemNumber, actor, timestamp, details, evidenceHash, eventHmac, // HMAC of this event previousHmac, // Links to previous event };
Event Types
- intake — Evidence collected and split across custodians
- transfer — Custody transferred between agencies/departments
- access — Custodian accessed their share (logged but not reconstructed)
- reconstruct — Evidence reconstructed from K shares
- verify — Chain integrity verified
- release — Evidence released from custody
verifyCustodyChain() function. Breaking any link creates a verifiable discontinuity.
Threshold Reconstruction
Reconstruction requires at least K shares (threshold) for each chunk. HMAC verification happens BEFORE XorIDA reconstruction (fail closed). After reconstruction, SHA-256 hash is computed and compared against the intake hash. Mismatch triggers INTEGRITY_FAILED error.
1. For each chunk: a. Verify K shares provided (or error: INSUFFICIENT_SHARES) b. HMAC verify each share → BEFORE reconstruction If any HMAC fails → error: HMAC_FAILED (fail closed) c. XorIDA reconstruct → padded chunk d. PKCS7 unpad → original chunk 2. Concatenate all chunks → reconstructed evidence 3. Hash reconstructed evidence → SHA-256 4. Compare hash to expected hash: If mismatch → error: INTEGRITY_FAILED 5. Create custody event: eventType: 'reconstruct' previousHmac: last event HMAC from chain eventHmac: HMAC-SHA256(hmacKey, canonical(event)) 6. Return { evidence, custodyChain: [...chain, event] }
Integration Guide
Install from private npm registry. Requires @private.me/crypto and @private.me/shared as peer dependencies.
# Install package + peer dependencies
pnpm add @private.me/forensiccustody @private.me/crypto @private.me/shared
Typical Workflow
import { intakeEvidence, reconstructEvidence, createCustodyEvent, verifyCustodyChain, } from '@private.me/forensiccustody'; // 1. Intake evidence const evidence = new Uint8Array([/* hard drive image */]); const hmacKey = crypto.getRandomValues(new Uint8Array(32)); const metadata = { caseNumber: 'CASE-2026-0042', itemNumber: 'ITEM-001', description: 'Seized laptop hard drive', fileType: 'disk-image', dataSize: evidence.byteLength, collectedBy: 'Det. Smith', collectedAt: new Date().toISOString(), }; const config = { custodians: [ { id: 'PD', name: 'Police Dept', jurisdiction: 'US-CA' }, { id: 'LAB', name: 'Forensic Lab', jurisdiction: 'US-CA' }, { id: 'DA', name: 'District Attorney', jurisdiction: 'US-CA' }, ], threshold: 2, }; const intake = await intakeEvidence(evidence, metadata, config, hmacKey); if (!intake.ok) throw new Error(intake.error.message); // 2. Distribute shares to custodians const { shares, custodyChain, evidenceHash } = intake.value; // shares[chunkIndex][custodianIndex] = EvidenceShare // Each custodian gets their column: shares.map(chunk => chunk[i]) // 3. Later: reconstruct from any 2-of-3 const collectedShares = [ shares.map(chunk => chunk[0]), // Police Dept shares shares.map(chunk => chunk[1]), // Forensic Lab shares ]; const rebuilt = await reconstructEvidence( collectedShares, evidenceHash, 'Prosecutor J. Doe', hmacKey, custodyChain, ); if (!rebuilt.ok) throw new Error(rebuilt.error.message); const { evidence: reconstructedEvidence, custodyChain: updatedChain } = rebuilt.value; // 4. Verify custody chain integrity const verification = await verifyCustodyChain(updatedChain, hmacKey); if (!verification.valid) { console.error(`Chain broken at event ${verification.brokenAt}`); }
Integration Patterns
| Pattern | When | Implementation |
|---|---|---|
| Multi-agency split | Federal + state + local custody | 3 custodians, threshold=2, each agency holds one share |
| Legal hold | Plaintiff + defendant + neutral vendor | 3 custodians, threshold=2, prevents unilateral alteration |
| Audit trail export | Court presentation of custody chain | Export custodyChain as JSON, verify with public function |
| Air-gapped custody | Classified evidence across networks | 5 custodians (3 networks), threshold=3, physical share transport |
Security Guarantees
Xhold provides information-theoretic security for evidence confidentiality and cryptographic tamper-evidence for custody integrity. No computational assumptions. Quantum-proof by construction.
Information-Theoretic Confidentiality
XorIDA splitting over GF(2) provides unconditional security. An attacker holding fewer than K shares learns zero information about the evidence — not because it's computationally hard to break, but because the information is not present in the shares. This guarantee holds even against adversaries with unlimited computational power.
HMAC Chain Integrity
HMAC-SHA256 provides cryptographic tamper-evidence. Each custody event is signed with HMAC over canonical serialization + previous HMAC. Altering any event invalidates all subsequent HMACs. The chain is verifiable without trusting any custodian.
Security Properties
| Property | Guarantee | Attack Resistance |
|---|---|---|
| Evidence confidentiality | Information-theoretic | Quantum computer learns zero from <K shares |
| Share integrity | HMAC-SHA256 per share | Tampered share detected before reconstruction |
| Custody chain integrity | HMAC-chained events | Altered event breaks chain, verifiable |
| Evidence integrity | SHA-256 hash verification | Bit-flip detected, reconstruction rejected |
| Insider threat | K-of-N threshold | Single corrupt custodian learns nothing |
| Replay attacks | Timestamp + sequence in chain | Old custody events have stale sequence numbers |
HMAC Key Management
The HMAC key is used for both share signing and custody event chaining. It MUST be generated via crypto.getRandomValues() and stored securely (hardware security module, key management service, or encrypted vault). Loss of the HMAC key prevents chain verification but does not compromise evidence confidentiality (XorIDA shares are still information-theoretically secure).
Performance Benchmarks
Xhold is optimized for large forensic evidence files (multi-GB disk images). Chunking enables streaming and prevents memory exhaustion.
Typical Evidence Sizes
| Evidence Type | Size | Chunks (1MB) | Split Time (2-of-3) |
|---|---|---|---|
| Email export (PST) | 500 MB | 500 | ~25 seconds |
| Phone extraction | 64 GB | 65,536 | ~55 minutes |
| Laptop hard drive | 256 GB | 262,144 | ~3.6 hours |
| Server disk image | 1 TB | 1,048,576 | ~14.5 hours |
Benchmarks on Node.js 20 LTS, Apple M1 Pro. Times are single-threaded. Parallel chunking reduces wall-clock time proportionally.
Memory Usage
Chunking prevents memory exhaustion. Peak memory is ~3x chunk size (padded chunk + N shares + overhead). For 1MB chunks with 5 custodians, peak memory is ~8MB per chunk. Evidence files of any size can be processed with constant memory.
Honest Limitations
Xhold is not a complete evidence management system. It provides split custody and tamper-evident audit trails, but does not replace procedural controls or legal expertise.
What Xhold Does NOT Do
- Evidence collection. Xhold assumes evidence has already been seized and imaged. It does not provide write-blocking, forensic imaging, or collection software.
- Chain-of-custody UI. No web portal, no custodian dashboards, no audit log viewer. You must build the application layer.
- Share distribution. Xhold splits evidence and produces shares, but does not transmit them. You must implement secure transfer (e.g., encrypted email, SFTP, physical media).
- Legal admissibility guarantee. Xhold provides mathematical proof of integrity, but court admissibility depends on jurisdiction, expert testimony, and procedural compliance. Consult a forensic expert.
- Key recovery. Loss of the HMAC key prevents chain verification. There is no key recovery mechanism. Implement key backup and escrow procedures.
- Evidence analysis. Xhold stores and reconstructs evidence, but does not analyze it. Use dedicated forensic tools (Autopsy, EnCase, X-Ways) for analysis.
- Access control. Xhold does not prevent custodians from attempting reconstruction. It only detects tampering via HMAC verification. Implement custodian authentication separately.
Deployment Considerations
| Consideration | Recommendation |
|---|---|
| HMAC key storage | Use HSM, AWS KMS, or Azure Key Vault for production |
| Share transport | Use TLS 1.3 + client certs, or physical media for air-gapped |
| Custodian authentication | Implement before allowing reconstruction (PKI, FIDO2, MFA) |
| Audit log persistence | Store custody chain in append-only log (S3 Object Lock, blockchain) |
| Evidence retention | Define retention policy per jurisdiction (5-7 years typical) |
| Legal review | Consult forensic expert + legal counsel before trial use |
When NOT to Use Xhold
Single custodian is sufficient. If your jurisdiction allows single-custodian evidence lockers and insider threat is not a concern, Xhold adds complexity without benefit.
Real-time access required. Threshold reconstruction requires collecting K shares from custodians. If you need instant access to evidence, single-custodian storage is faster.
Non-digital evidence. Xhold is for digital evidence only (disk images, files, databases). Physical evidence (drugs, weapons) requires different custody protocols.
Deep Technical Details
The following sections cover the complete API surface, error taxonomy, and legal compliance considerations for production deployments.
Full API Surface
Four public functions, seven types, seven error codes. Complete reference for integration engineers.
Core Functions
Split evidence across custodians via XorIDA. Creates initial custody chain event with eventType: 'intake'. Evidence is chunked (default 1MB), each chunk is padded, split, and HMAC-signed. Returns manifest ID, shares grouped by chunk, evidence hash, and custody chain.
Reconstruct evidence from K-of-N shares. HMAC verification happens BEFORE XorIDA reconstruction (fail closed). SHA-256 hash of reconstructed evidence is compared against expected hash. Creates 'reconstruct' custody event. Returns evidence bytes + updated chain.
Create an HMAC-chained custody event. Event HMAC is computed over canonical serialization (pipe-delimited fields) + previous event HMAC. First event has previousHmac: ''. Sequence number auto-increments. Returns signed custody event.
Verify integrity of the entire custody chain. Checks that each event HMAC matches canonical data and that previousHmac links are consistent throughout. Returns valid: false with brokenAt index if any link is broken. Independent verification function for court presentation.
Core Types
interface EvidenceMetadata { caseNumber: string; itemNumber: string; description: string; fileType: string; dataSize: number; collectedBy: string; collectedAt: string; // ISO 8601 } interface Custodian { id: string; name: string; jurisdiction: string; } interface CustodyConfig { custodians: readonly Custodian[]; threshold: number; chunkSize?: number; // default 1MB } interface EvidenceShare { itemNumber: string; caseNumber: string; custodianId: string; index: number; total: number; threshold: number; chunkIndex: number; totalChunks: number; data: string; // base64 hmac: string; // hex originalSize: number; } interface CustodyEvent { id: string; sequence: number; eventType: 'intake' | 'transfer' | 'access' | 'reconstruct' | 'verify' | 'release'; caseNumber: string; itemNumber: string; actor: string; timestamp: string; // ISO 8601 details: string; evidenceHash: string; // hex eventHmac: string; // hex previousHmac: string; // hex, '' for first } interface IntakeResult { manifestId: string; metadata: EvidenceMetadata; totalChunks: number; evidenceHash: string; // hex shares: readonly (readonly EvidenceShare[])[]; custodyChain: readonly CustodyEvent[]; }
Error Taxonomy
Seven error codes cover configuration, splitting, HMAC verification, reconstruction, and chain integrity failures.
| Code | Category | Description |
|---|---|---|
| INVALID_CONFIG | Config | Fewer than 2 custodians, threshold < 2, or threshold > custodian count. Fix configuration before calling intakeEvidence. |
| SPLIT_FAILED | Intake | Empty evidence data provided. Verify evidence buffer is not empty. |
| HMAC_FAILED | Integrity | HMAC verification failed on a share or custody event creation failed. Evidence tampered — reject and investigate. |
| RECONSTRUCT_FAILED | Rebuild | XorIDA reconstruction or PKCS7 unpadding failure. Shares corrupted or incompatible. |
| INSUFFICIENT_SHARES | Threshold | Fewer shares than threshold for a chunk. Collect more custodian shares to meet K-of-N requirement. |
| CHAIN_BROKEN | Audit | Custody chain verification detected broken HMAC link. Custody audit trail tampered — inadmissible. |
| INTEGRITY_FAILED | Hash | Reconstructed evidence SHA-256 hash does not match expected hash. Evidence altered — reject and log. |
Legal & Compliance Considerations
Xhold is designed to support forensic evidence admissibility, but legal requirements vary by jurisdiction. Consult forensic experts and legal counsel.
U.S. Federal Rules of Evidence
Rule 901 — Authentication. Xhold provides cryptographic authentication via HMAC-chained custody events. The chain can be verified independently using the public verifyCustodyChain() function. Expert testimony can explain how HMAC prevents retroactive alteration.
Rule 902(13) — Certified Data from Electronic Systems. SHA-256 hash verification provides a cryptographic certificate that reconstructed evidence matches the original. Hash mismatch triggers automatic rejection.
Rule 1006 — Summaries of Voluminous Evidence. Custody chain events provide a summary of all evidence handling. Courts can review the chain without examining every share.
Industry Standards
| Standard | Relevance | Xhold Compliance |
|---|---|---|
| ISO/IEC 27037:2012 | Digital evidence identification, collection, acquisition, preservation | Xhold handles preservation (split custody), not collection |
| NIST SP 800-86 | Guide to integrating forensic techniques into incident response | HMAC-chained custody events align with NIST audit requirements |
| SWGDE Best Practices | Scientific Working Group on Digital Evidence guidelines | SHA-256 hash verification + HMAC integrity align with SWGDE |
| Daubert Standard | U.S. federal standard for expert testimony reliability | XorIDA is peer-reviewed (academic literature), testable, published |
Recommended Expert Testimony
To support admissibility, consider expert testimony covering:
- XorIDA information-theoretic security — Expert explains that individual shares reveal zero information, regardless of computational power
- HMAC chain tamper-evidence — Expert demonstrates how altering any custody event breaks the chain, which can be verified mathematically
- SHA-256 integrity verification — Expert explains cryptographic hash functions and collision resistance
- Threshold reconstruction — Expert describes how K-of-N prevents single-custodian compromise
Deployment Options
SaaS Recommended
Fully managed infrastructure. Call our REST API, we handle scaling, updates, and operations.
- Zero infrastructure setup
- Automatic updates
- 99.9% uptime SLA
- Enterprise SLA available
SDK Integration
Embed directly in your application. Runs in your codebase with full programmatic control.
npm install @private.me/forensiccustody- TypeScript/JavaScript SDK
- Full source access
- Enterprise support available
On-Premise Upon Request
Enterprise CLI for compliance, air-gap, or data residency requirements.
- Complete data sovereignty
- Air-gap capable deployment
- Custom SLA + dedicated support
- Professional services included
Enterprise On-Premise Deployment
While forensicCustody is primarily delivered as SaaS or SDK, we build dedicated on-premise infrastructure for customers with:
- Regulatory mandates — HIPAA, SOX, FedRAMP, CMMC requiring self-hosted processing
- Air-gapped environments — SCIF, classified networks, offline operations
- Data residency requirements — EU GDPR, China data laws, government mandates
- Custom integration needs — Embed in proprietary platforms, specialized workflows
Includes: Enterprise CLI, Docker/Kubernetes orchestration, RBAC, audit logging, and dedicated support.