AtKeys class

The in-memory model of an atsign's cryptographic keys.

An AtKeys instance always holds plaintext key material — every at-rest concern (the passphrase envelope, self-encryption of the legacy fields) lives in FileAtKeysIo, not here.

Typed key material (CryptographicMaterial) sits in one of two containers, and which one is a statement about who the material belongs to:

⚠️ Identity is (enrollment, keyId), not keyId alone. Two enrollments may each hold auth:mldsa65:1. That is why the lookups are split rather than defaulted: a caller reaching for atSign-scope material with a bare keyId would otherwise compile while searching an enrollment, and find nothing.

addKey is not split, because a material states its own owner: its enrollmentId routes it, and a null one means the atSign's container.

Constructors

AtKeys({Atsign? atsign, List<CryptographicMaterial> keysList = const []})
AtKeys.fromJson(Map<String, dynamic> json)
Decodes the typed-keys document shape (version, atsign, atsignKeys, enrollments, plus legacy fields flat at the top level). Json without a version field is accepted as the legacy flat shape (delegates to _fromLegacyJson); a version other than supportedVersion throws AtKeysUnsupportedVersionException. Each container's entries are parsed and validated by parseAtKeysDocument, which returns the flattened CryptographicMaterials that are actually stored.
factory
AtKeys.legacy({String? apkamPublicKey, String? apkamPrivateKey, String? apkamSymmetricKey, String? encryptionPublicKey, String? encryptionPrivateKey, String? selfEncryptionKey, String? enrollmentId})
A legacy-shaped document holding what fileLegacyMaterial files and nothing typed: the shape of every keyfile written before the typed section existed, and of a demo atSign's credentials.
factory

Properties

apkamPrivateKey ↔ AtBytes?
getter/setter pair
apkamPublicKey ↔ AtBytes?
getter/setter pair
apkamSymmetricKey ↔ AtBytes?
getter/setter pair
atsign ↔ Atsign?
getter/setter pair
atSignKeys → Iterable<CryptographicMaterial>
The atSign's own materials — the signing root, nskey privates — with no enrollment between them and the document.
no setter
authenticatableEnrollmentIds → Iterable<String>
Every enrollment holding active authentication material — the ones this keyfile could authenticate as.
no setter
defaultEncryptionPrivateKey ↔ AtBytes?
getter/setter pair
defaultEncryptionPublicKey ↔ AtBytes?
getter/setter pair
defaultSelfEncryptionKey ↔ AtBytes?
getter/setter pair
encryptionKeyPair → RsaKeyPair?
The atSign's RSA encryption keypair: the key a legacy shared key is wrapped to, and whose private half signs public data.
no setter
enrollmentId ↔ String?
getter/setter pair
enrollmentIds → Iterable<String>
Every enrollment this keyfile holds. Writers emit one; the reader tolerates several so that emitting a second never has to break a build that predates it.
no setter
enrollmentSymmetricKey → AESKey?
The APKAM symmetric key of the enrollment the flat fields carry, which unwraps what an approval released to it; null for a keyfile that predates enrollments or holds none.
no setter
hashCode → int
The hash code for this object.
no setteroverride
holdsAuthenticationMaterial → bool
Whether this document holds any authentication material: typed, or the flat APKAM keypair. A document holding none authenticates as nothing, whatever its flat enrollmentId says.
no setter
keys → Iterable<CryptographicMaterial>
Every typed material in the document, both containers, in no particular order.
no setter
metadata ↔ Map<String, dynamic>
A legacy keyfile's entries outside the flat key schema: the atSign under atsign or name, and the self-encryption key stored under the atSign itself. The typed document has no equivalent, so a read and write cycle preserves them only here.
getter/setter pair
pendingEnrollmentIds → Iterable<String>
Every enrollment whose material is filed as CryptographicMaterialStatus.pending: submitted, and not yet approved. The ones activatePending or discardEnrollment will settle.
no setter
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
selfEncryptionKey → AESKey?
The atSign's self-encryption key, which opens the records it wrote for itself.
no setter
storedEnrollmentId → String?
The enrollment id the flat fields carry, exactly as stored: null for a keyfile from before enrollments, where enrollmentToAuthenticateAs answers primary, and never a typed enrollment's id.
no setter

Methods

activatePending(String enrollmentId) → void
Moves every CryptographicMaterialStatus.pending material of enrollmentId to active: the approval of an enrollment whose keypair was filed at submission.
addKey(CryptographicMaterial material) → void
Files material in the container its own enrollmentId names — that enrollment's when it has one, the atSign's when it is null.
adoptMaterials(Iterable<CryptographicMaterial> materials, {required String enrollmentId}) → void
Adopts materials — what an enrollment request's metadataBuilder filed into the construction keys it was handed — tagged with the enrollment id they now belong to.
atSignKeysForKeyId(String keyId) → Iterable<CryptographicMaterial>
Every atSign-scope material sharing keyId.
authenticationAlgorithmFor(String? enrollmentId) → SigningAlgoType?
The algorithm half of authenticationFor, without building an AtChops.
authenticationFor(String? enrollmentId) → ({SigningAlgoType? algorithm, AtChops chops})
The AtChops and the PKAM signing algorithm enrollmentId authenticates with — the one place either half of an APKAM keypair is resolved.
authenticationKeyPairFor(String? enrollmentId) → ({SigningAlgoType algorithm, String privateKey, String publicKey})?
The authentication keypair enrollmentId proves possession of, and the algorithm that signs with it.
discardEnrollment(String enrollmentId) → void
Removes enrollmentId from the keyfile: its snapshot and every material filed under it.
enrollmentInfo(String enrollmentId) → AtKeysEnrollment?
What this keyfile records about enrollmentId besides its keys, or null when it holds no such enrollment.
enrollmentToAuthenticateAs() → String
The enrollment this keyfile authenticates as: the one holding active typed authentication material, else the flat stored enrollmentId, else EnrollmentConstants.primaryEnrollmentId for a keyfile that predates enrollments.
fileApkamMaterial({required String enrollmentId, required CryptographicMaterialAlgorithm algorithm, required String publicKey, required String privateKey}) → void
Files a freshly minted APKAM keypair as an enrollment's authentication material, under the keyId auth:<algorithm>:<generation>.
fileLegacyMaterial({String? apkamPublicKey, String? apkamPrivateKey, String? apkamSymmetricKey, String? encryptionPublicKey, String? encryptionPrivateKey, String? selfEncryptionKey, String? enrollmentId}) → void
Files what a LEGACY keyfile carries flat: the atSign's RSA encryption keypair and self-encryption key, and the APKAM keypair, symmetric key and id of the one enrollment such a document holds. A null argument leaves its field as it was.
fileSigningMaterial({required String enrollmentId, required CryptographicMaterialAlgorithm algorithm, required String publicKey, required String privateKey}) → void
Files a signing keypair for enrollmentId under sign:<algorithm>:<generation>.
getAtSignKey(String keyId, CryptographicMaterialRole type) → CryptographicMaterial?
Looks up one of the atSign's own materials by (keyId, role).
getKey(String enrollmentId, String keyId, CryptographicMaterialRole type) → CryptographicMaterial?
Looks up one of enrollmentId's materials by (keyId, role) — type is a CryptographicMaterialRole token.
keysForEnrollment(String enrollmentId) → Iterable<CryptographicMaterial>
Returns every material tagged with enrollmentId.
keysForKeyId(String enrollmentId, String keyId) → Iterable<CryptographicMaterial>
Every material of enrollmentId sharing keyId — e.g. the public+private halves of one keypair.
nextAtSignGeneration(String role, CryptographicMaterialAlgorithm algorithm) → int
The generation an atSign-scope keypair of role and algorithm should be filed under next — one past the highest already there, or 1.
nextAuthenticationGeneration(String enrollmentId, CryptographicMaterialAlgorithm algorithm) → int
The generation number fileApkamMaterial will use next for enrollmentId's algorithm — one past the highest already filed, or 1.
nextSigningGeneration(String enrollmentId, CryptographicMaterialAlgorithm algorithm) → int
The generation fileSigningMaterial will use next for enrollmentId's algorithm — one past the highest already filed, or 1.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
recordEnrollmentSnapshot(String enrollmentId, {Map<String, String>? namespaces, String? appName, String? deviceName}) → void
Records the enrollment record's namespaces / appName / deviceName against enrollmentId, creating the enrollment slot if this is the first thing filed for it.
replaceKey(String enrollmentId, String keyId, Iterable<CryptographicMaterial> replacements, {CryptographicMaterialStatus to = CryptographicMaterialStatus.retired}) → void
Retires keyId and files replacements in one call — a key rotation, as a single operation rather than two the caller has to sequence.
resolveAuthenticatingEnrollment() → String?
The one enrollment this keyfile authenticates as, for a caller that has no id of its own to supply — a cold start holding nothing but the file.
retireAtSignKey(String keyId, {CryptographicMaterialStatus to = CryptographicMaterialStatus.retired}) → void
retireKey for the atSign's own material — the signing root, an nskey private.
retireKey(String enrollmentId, String keyId, {CryptographicMaterialStatus to = CryptographicMaterialStatus.retired}) → void
Marks every material of enrollmentId's keyId as to (CryptographicMaterialStatus.retired by default). Key material is never removed — retired/dead bytes are still needed to decrypt data they protected — so this is the delete operation. Status only moves forward (pending → active → retired → dead): a same-status call is a no-op and a backward transition throws, as does an unknown keyId or to: CryptographicMaterialStatus.active, which is activatePending's move alone.
retireSigningKeys(String enrollmentId, CryptographicMaterialAlgorithm algorithm, {CryptographicMaterialStatus to = CryptographicMaterialStatus.retired}) → List<String>
Retires every active signing keypair enrollmentId holds for algorithm, returning the keyIds it moved — empty when it holds none, which is the ordinary case on a client whose in-use set has not changed.
signingAlgorithmForEnrollment(String enrollmentId) → SigningAlgoType?
The algorithm of enrollmentId's active authentication material — what PKAM must sign with — or null when the enrollment has no typed authentication material this build recognises (a legacy flat-fields enrollment reports null: its RSA keypair lives in the flat fields, not the typed section).
signingKeysFor(String enrollmentId) → List<({SigningAlgoType algorithm, String privateKey, String publicKey})>
Every active signing keypair enrollmentId holds, strongest algorithm first — one entry per algorithm, which is what a multi-signature writer iterates and what a _apsk array is composed from.
toJson() → Map<String, dynamic>
Encodes this AtKeys to the typed-keys document shape. Legacy fields merge flatly into the top level alongside version/atsign/atsignKeys/enrollments — upgrading a legacy file is additive, not a format swap. Falls back to the legacy flat shape (see _toLegacyJson) when there's no atsign and no typed key material.
toString() → String
A string representation of this object.
inherited
withdrawnSigningKeysFor(String enrollmentId) → List<({SigningAlgoType algorithm, String publicKey, CryptographicMaterialStatus status})>
The public half of every signing keypair enrollmentId has withdrawn from signing, strongest algorithm first, each with the status the keyfile gives it — the entries an _apsk advertisement carries alongside the active ones, so that envelopes signed before a key was withdrawn still verify.

Operators

operator ==(Object other) → bool
The equality operator.
override

Static Methods

isRoleKeyId(String keyId, String role) → bool
Whether keyId names a keypair of role — <role>:<algo>:<generation> exactly, the shape keyIdPrefix composes and every generation parse reads.
keyIdPrefix(String role, CryptographicMaterialAlgorithm algorithm) → String
The keyId prefix a role/algorithm pair is filed under — <role>:<algorithm>:, completed by a generation number.

Constants

supportedVersion → const int