\Drupal\strata\Crypto KeyRing

The key new frames are sealed with, plus the retired keys old frames still need.

A rotation cannot re-seal the whole store, so the store holds several generations at once. Re-sealing every frame means reading, decrypting, re-encrypting and re-uploading every byte of history, which for a site with a year of files is hours of work and a full month's request budget. So a rotation changes which key SEALS and leaves what is already sealed alone; the retired keys stay on the ring for as long as any frame still needs one.

The frame format carries no key fingerprint, and that is what makes a ring necessary rather than optional. A frame records the cipher id, not which key sealed it, so the only way to find the right key is to try them. The cost is one failed AEAD open per stale key per frame, and AEAD runs at 392 MB/s, so a ring of two or three keys is not measurable next to the network.

The honest limitation. When no key on the ring opens a frame, that is indistinguishable from the bytes being corrupt - a wrong key and a flipped bit both fail the Poly1305 tag. So a frame that no key opens is reported as unreadable, never as "sealed under a key you have lost", because nothing here can tell those apart.

Order matters: the active key is tried first, so the common case costs one open and the retired keys are only reached for frames that predate the rotation.

Summary

Methods
Properties
Constants
__construct
active
all
retired
isRotating
count
fingerprints
isActive
of
No public properties found
MAX_RETIRED
No protected methods found
No protected properties found
No protected constants found
No private methods found
retired
active
No private constants found

Constant

MAX_RETIRED

MAX_RETIRED = 4

Retired keys one ring will hold.

Each one costs a failed open on every frame that predates it, so a ring that grew without bound would make the oldest frames the most expensive to read. A site needing more generations than this has not finished a rotation it started.

Properties

$retired

$retired : list<\Drupal\strata\Crypto\KeyProviderInterface>

The retired keys, in the order they are tried.

Type

array<int, KeyProviderInterface> —

Methods

__construct()

__construct(\Drupal\strata\Crypto\KeyProviderInterface  $active, list<\Drupal\strata\Crypto\KeyProviderInterface>  $retired = []) : mixed

Constructs a ring.

Parameters

\Drupal\strata\Crypto\KeyProviderInterface $active

The key new frames are sealed with.

list<\Drupal\strata\Crypto\KeyProviderInterface> $retired

Keys that still open older frames, newest first.

Throws

\InvalidArgumentException

When the active key holds no value, or too many retired keys are given.

Returns

mixed —

active()

active() : \Drupal\strata\Crypto\KeyProviderInterface

The key new frames are sealed with.

Returns

\Drupal\strata\Crypto\KeyProviderInterface —

The active key.

all()

all() : list<\Drupal\strata\Crypto\KeyProviderInterface>

Every key, active first.

The order a caller must try them in: the active key opens everything written since the last rotation, which on any site that has been running is nearly everything.

Returns

list<\Drupal\strata\Crypto\KeyProviderInterface> —

The keys.

retired()

retired() : list<\Drupal\strata\Crypto\KeyProviderInterface>

The retired keys.

Returns

list<\Drupal\strata\Crypto\KeyProviderInterface> —

The keys, newest first.

isRotating()

isRotating() : bool

Whether this ring holds more than the active key.

Returns

bool —

TRUE when a rotation is in progress or has not been finished.

count()

count() : int

How many keys a caller may have to try.

Returns

int —

The count, at least one.

fingerprints()

fingerprints() : list<string>

The fingerprint of every key on the ring, active first.

A fingerprint is safe to log and to show an operator; the key itself is not.

Returns

list

The fingerprints.

isActive()

isActive(string  $fingerprint) : bool

Whether a fingerprint names the active key.

What decides whether a frame is up to date or still needs a retired key.

Parameters

string $fingerprint

The fingerprint to test.

Returns

bool —

TRUE when it is the active key's.

of()

of(string  $key) : self

A ring holding one key and nothing else.

Parameters

string $key

Raw key material.

Returns

self —

The ring.