Skip to main content

KeyRing

Struct KeyRing 

Source
pub struct KeyRing { /* private fields */ }
Expand description

Holds the (versioned) key material used for field protection.

  • RSA public key: enough to write encrypted fields; the private key is only needed to read them back, so a log-producing service can run without it.
  • HMAC key: required to write and search FieldProtection::Hmac fields (FieldProtection::Sha256 needs no key). A keyed MAC is what stops an attacker with disk access from recovering low-entropy values (SSNs, phone numbers, …) by brute-forcing the digest; without the key the stored digests are useless.

Rotation. Each key carries a KeyVersion; the highest version of each kind is active and protects every new write, and the version is recorded on the stored value itself (StoredValue::Hmac / StoredValue::Rsa) and on persisted index tokens. Older versions stay in the ring as read-side material: decrypt picks the private key the record names, and searches probe HMAC digests under every held version, so rotating keys never silently severs old data. The version-less builders (with_hmac_key, …) install version 1 — a ring that never rotates needs no version bookkeeping.

Implementations§

Source§

impl KeyRing

Source

pub fn new() -> Self

Source

pub fn with_public_pem(self, pem: &str) -> Result<Self>

Source

pub fn with_private_pem(self, pem: &str) -> Result<Self>

Source

pub fn with_hmac_key(self, key: impl AsRef<[u8]>) -> Self

Set the secret key for searchable-hash (HMAC-SHA-256) fields (version 1).

Source

pub fn with_public_pem_version( self, version: KeyVersion, pem: &str, ) -> Result<Self>

Add the RSA public key of one key version.

Source

pub fn with_private_pem_version( self, version: KeyVersion, pem: &str, ) -> Result<Self>

Add the RSA private key of one key version (the matching public key is derived if it was not given separately).

Source

pub fn with_hmac_key_version( self, version: KeyVersion, key: impl AsRef<[u8]>, ) -> Result<Self>

Add the HMAC key of one key version.

Source

pub fn with_generated_rsa( self, version: KeyVersion, bits: usize, ) -> Result<Self>

Add a freshly generated in-memory RSA keypair under version (tests, demos and rotation drills — production should load persistent keys).

Source

pub fn with_generated_hmac(self, version: KeyVersion) -> Result<Self>

Add a freshly generated random HMAC key under version.

Source

pub fn generate_ephemeral(bits: usize) -> Result<Self>

Generate an in-memory RSA keypair and a random HMAC key, both version 1 (useful for tests and demos — production should load persistent keys).

Source

pub fn active_hmac_version(&self) -> Option<KeyVersion>

Version of the HMAC key new writes are digested with (the highest one).

Source

pub fn active_rsa_version(&self) -> Option<KeyVersion>

Version of the RSA key new writes are encrypted with (the highest one).

Source

pub fn hmac_versions(&self) -> Vec<KeyVersion>

Every held HMAC key version, newest first — the probe order for multi-version digest matching (recent keys hit most often).

Source

pub fn has_rsa_private(&self, version: KeyVersion) -> bool

Whether version’s RSA private key is held (re-key needs every version still referenced by stored values).

Source

pub fn hmac_hex(&self, data: &[u8]) -> Result<(KeyVersion, String)>

Keyed digest under the active HMAC key, used when writing HMAC-protected fields. Returns the version the digest was made with, which the caller persists next to the digest.

Source

pub fn hmac_hex_with(&self, version: KeyVersion, data: &[u8]) -> Result<String>

Keyed digest under one specific HMAC key version — the probe side of multi-version search.

Source

pub fn index_token_digest( &self, field: &str, protection: FieldProtection, token: &str, ) -> Result<(KeyVersion, String)>

Digest of one blind-index token (crate::schema::FieldIndex) under the active key. Returns the key version used (KEYLESS for keyless protections), which the caller persists next to the digests.

The input is domain-separated ("idx:" + field + NUL + token) so an index digest can never collide with — or be replayed as — the field’s own stored digest. The digest function follows the field’s protection: keyless protections (None/Sha256) use SHA-256, keyed ones (Hmac/Rsa) use the HMAC key, so the tokens of an encrypted field cannot be brute-forced offline any more than the field itself.

Source

pub fn index_token_digest_with( &self, version: KeyVersion, field: &str, protection: FieldProtection, token: &str, ) -> Result<String>

index_token_digest under one specific key version — the probe side of multi-version search. version is ignored for keyless protections.

Source

pub fn protect( &self, value: &Value, protection: FieldProtection, ) -> Result<StoredValue>

Apply a schema-declared protection to a plain value, under the active key of the relevant kind. The key version is recorded on the stored value so reads outlive rotations.

Source

pub fn can_sign(&self) -> bool

Whether this ring can produce signatures (i.e. the active RSA version holds its private key). Write-only deployments (public keys only) cannot sign — checkpointing keys off this.

Source

pub fn sign(&self, data: &[u8]) -> Result<(KeyVersion, Vec<u8>)>

RSA PKCS#1 v1.5 signature over SHA-256(data) with the active private key; returns the key version so verifiers can pick the matching public key after a rotation. PKCS#1 v1.5 (not PSS) because it is deterministic: re-signing identical checkpoint bytes yields identical signatures, which keeps externally anchored copies byte-comparable.

Source

pub fn verify_signature( &self, key_version: KeyVersion, data: &[u8], signature: &[u8], ) -> Result<()>

Verify a signature produced by sign under the named key version. Needs only that version’s public key, so an auditor can verify without decryption capability.

Source

pub fn decrypt(&self, stored: &StoredValue) -> Result<Vec<u8>>

Recover the canonical bytes of an RSA-protected value, with the private key of the version the value was written under.

Source

pub fn rewrap(&self, stored: &StoredValue) -> Result<StoredValue>

Re-wrap the data key of an RSA-protected value under the active public key: the old version’s private key unwraps the DEK, the active public key re-wraps it. Nonce and ciphertext are untouched (the DEK itself never changed), so this is cheap and cannot corrupt the payload. Values already at the active version pass through unchanged.

Trait Implementations§

Source§

impl Clone for KeyRing

Source§

fn clone(&self) -> KeyRing

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Default for KeyRing

Source§

fn default() -> KeyRing

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V