Sealedge 6.1 and 6.2

Sealedge is my Rust project for cryptographic provenance of edge device data and software supply chains. A device wraps what it captures into a signed, encrypted .seal archive, and anyone with the right key can later prove where that data came from and that nobody changed it. It used to be called TrustEdge; I renamed it in April for trademark reasons, and TrustEdge Labs stays as the name of the organization behind it.

Two releases since then are worth writing about. 6.1.0 shipped on August 6 and 6.2.0 on September 2. Most of what is in them started with an external review that did not go easy on me.

The Review

The review found four critical issues. I would rather say that plainly than bury it, because it is the most useful thing that happened to the project this year.

  • C1. The platform's verify endpoint could not actually verify real .seal archives. A doubled signature prefix and a canonicalization mismatch meant the server and the CLI were signing and checking different bytes.
  • C2. Continuity verification was not bound to the signed manifest. The chain tip depended on the number of segments, not their content.
  • C3. Receipts trusted a client-supplied device ID instead of the key that actually signed.
  • C4. One Ed25519 key was doing both signing and encryption.

C1 through C3 were fixes with regression tests and golden vectors behind them. C4 was a redesign.

Content Encryption, Redone

The Ed25519 key is now signing-only. Each archive gets its own random content key, and that key is wrapped to one or more recipients with HPKE (RFC 9180) using ephemeral sender keys, which gives forward secrecy. Devices now have a separate X25519 key for this. An auditor can decrypt an archive with their own key without gaining any power to sign as the device.

This was a breaking change. The archive format moved to 0.2.0, and older 0.1.0 archives are no longer produced or accepted. For a provenance tool that is the right trade. A format that mixes up signing and encryption is not one I want anyone depending on.

A Chronicle for Each Device

A single signed archive proves that one piece of data is authentic. It says nothing about the archives that are missing. 6.1 adds a device chronicle: archives can form a hash-linked, sequence-numbered chain, and seal verify-chronicle checks the whole chain for gaps, reordering, and broken links.

The chain alone can't tell you whether someone quietly deleted the newest archives. For that, a device can submit its latest tip to the platform, which records it in an append-only ledger and returns a signed, timestamped witness receipt. Cross-checking against that receipt catches tail deletion.

Real devices also rotate keys and sometimes get compromised, so 6.1 also added key rotation and revocation. seal rekey writes a rotation entry signed by both the old key and the new one, and the chronicle walks those rotations so a chain can outlive any single key. Revocation in the platform registry only ever moves earlier and is never cleared, and the witness timestamps are what give it teeth.

6.2: Custody and Recovery

6.2 was about the unglamorous places secrets leak:

  • Key material on the import and export paths is now zeroized instead of lingering in heap copies.
  • Secret key files are created owner-only from the start and renamed into place. Before, they were written with default permissions and then locked down, which left a brief window where the key was world-readable.
  • seal unwrap is now all-or-nothing. A failure halfway through deletes the partial output instead of leaving a truncated file that looks like a complete recovery.
  • Wrapping is now streaming, so peak memory is one chunk instead of twice the payload, and every read path is size-capped. GB-scale camera captures work now.
  • The platform's own signing key is encrypted at rest, and release builds refuse to start without it.

What I Learned

The review was worth more than any feature I could have shipped instead. Four criticals sounds bad. It is much better than four criticals that nobody found. The fixes also made the design simpler: separate keys for separate jobs, one canonical set of bytes to sign, one definition of what a receipt means.

What's Next

Work since 6.2 is already on main and unreleased: a ceiling on PBKDF2 iteration counts so a hostile key file can't pin a CPU, fail-closed handling of unknown envelope versions, and a keyed verifier for full receipt chains. Binding more of the envelope metadata into what gets signed is a format change planned for the next major version.


Provenance is only as good as the keys behind it, and the review made sure of that.