Architecture

How a record is sealed, shared and logged.

The mechanism behind the Security page, for a technical reviewer. The sizes and counts are read from the code and the records when this page is built.

The keys

Made on the owner’s device, in this order.

Each line is a key, what it is made from and how big it is. The sizes and the work factor are the code’s own constants, read when this page was built.

The Master Key is the only key that depends on the password. A new password wraps the same Master Root again, so no record is sealed a second time.

DerivationMade again at every unlock
  • SaltBLAKE3(server salt ‖ Secret Key ‖ email address)16 bytes
  • Master KeyArgon2id(password, salt; 256 MiB, 3 passes)32 bytes
  • Master Root32 random bytes, stored as nonce ‖ AES-256-GCM(Master Key, root)60 bytes wrapped
  • Content root keyHKDF-SHA-256(Master Root, "cairn:content-root:v1")32 bytes
  • Metadata root keyHKDF-SHA-256(Master Root, "cairn:metadata-root:v1")32 bytes
  • Content key, per recordHKDF-SHA-256(content root key, "cairn:content-key:v1:" ‖ record id)32 bytes
  • Metadata key, per recordHKDF-SHA-256(metadata root key, "cairn:metadata-key:v{version}:" ‖ record id)32 bytes
  • Figure key, per recordHKDF-SHA-256(content root key, "guardkin:amount-key:v{version}:" ‖ record id)32 bytes

Six primitives, and where each is used.

  • AES-256-GCMSeals every layer of a record, and wraps the Master Root. A 12-byte nonce and a 16-byte tag.
  • Argon2idTurns the password into the Master Key. The cost is libsodium’s MODERATE setting, read from the library.
  • HKDF-SHA-256Makes every key below the Master Root, each under its own context string.
  • BLAKE3Builds the salt, and hashes each audit event together with the one before it.
  • X25519Wraps a key to an advisor’s or an executor’s public key.
  • ECDSA P-256Signs each audit event, with a key held in AWS KMS in production.

The sealed record

Three layers, each stored as three fields.

A layer is stored as a nonce, its associated data and the sealed bytes. The associated data begins with the record’s id, so a layer copied onto another record fails to open.

Content and figure are sealed under keys from the content root. The outline is sealed under a key from the metadata root. That is the only reason an advisor can open one and not the others.

The sample recordSizes in bytes
  • Contentsealed under the content keynonce 12 · associated data 46 · sealed 519
  • Outlinesealed under the metadata keynonce 12 · associated data 46 · sealed 123
  • Figuresealed under the figure keynonce 12 · associated data 46 · sealed 144

The sealed bytes include the 16-byte authentication tag.

GuardKin staff

Two layers between the operator and a sealed column.

The first layer is the console’s own code. Every read selects a named list of columns, and its return types have no field for a sealed one.

The second is a database role granted 9 of the 29 columns of the records table, none of them sealed. A read of any other column is refused by the database.

The second layer backs 3 of 18 operator routes today. The rest are listed in a test that fails if a new route is added without a decision. Moving them behind the role is open work.

Operator routes3 of 18 behind the role
  • Behind the role
  • Behind the role
  • Behind the role
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
  • Own column list only
Behind the role

3 routes

Own column list only

15 routes

The grant is migration 0020. The columns it allows are drawn on the Security page.

The log

What the check does, and what it does not show.

Each service writes its own chain under its own signing key, so the check is run on one chain at a time. GuardKin’s operator console runs it on the newest events of each chain it holds a key for.

See it fail on an edited event
  1. It rebuilds each row into the event that was hashed.

  2. It recomputes the BLAKE3 hash and compares it with the stored one.

    A changed field fails here.

  3. It verifies the signature under a key pinned by its id.

    Never under a key taken from the live signer.

  4. It walks the links and the sequence numbers.

    A removed event breaks the link, and a gap in the numbers shows.

It does not show a complete rewrite by someone who holds the signing key, because nothing outside the database is notarised. A chain signed with a key it has no pin for is reported as one it cannot attest, not as intact.

Recovery and release

Two ways keys reach other people.

They are separate. Recovery belongs to the owner and needs no death. Release belongs to an executor and needs one.

  1. Recovery cards: the owner’s own way back in.

    Optional. The owner splits the Master Root into 5 cards, any 3 of which rebuild it on the owner’s device, and gives each to a person they trust. It covers a forgotten Master Password; the app also asks for the Secret Key before a new password is set. GuardKin keeps a record of who holds which card, never a card.

    The cards are plain shares of the root, so 3 holders acting together rebuild it with no Master Password and no Secret Key. If you lose your Secret Key, GuardKin cannot give it back, and the app’s recovery asks you for it. The cards are not a copy of it: they are your key itself, split five ways, so any three open your records for whoever also holds a copy of the stored data.

    A stolen database, a leaked backup or a court order for our servers yields your records only as locked bytes, and nothing GuardKin holds unlocks them. The keys are yours, and three of your five recovery cards rebuild them. The cards are a deliberate exception: an owner who loses everything still needs a way back. Three card holders alone cannot read your records, because GuardKin gives them none of your data. Three card holders and a copy of the stored data, such as a database dump or a backup, can read all of them. Choose the five with that in mind.

  2. Release: what an executor can open after a death.

    A handover opens for a death only. It needs a death certificate, sign-offs from the advisor and the firm, and 72 hours with nothing open, which the owner can cancel. Before that, the owner’s device seals each record the owner chose to release to the executor’s key. The executor receives the metadata key and, for each released record, that record’s own content key, and opens them on the executor’s own device. The server serves the executor only the released records. The executor never receives the content root.

Take the status to your reviewer.

The Trust Center says what exists, what is in preparation and what is not in place.

Architecture: how a record is sealed and shared · GuardKin