pub struct SecretTree { /* private fields */ }
Expand description

Seeded structure that can be used to produce secrets and child SecretTrees.

Usage

During the program lifecycle, a root SecretTree should be restored from a secure persistent form (e.g., a passphrase-encrypted file) and then used to derive child trees and secrets. On the first use, the root should be initialized from a CSPRNG, such as rand::thread_rng(). The tree is not needed during the program execution and can be safely dropped after deriving necessary secrets (which zeroes out the tree seed).

It is possible to modify the derivation hierarchy over the course of program evolution by adding new secrets or abandoning the existing ones. However, the purpose of any given tree path should be fixed; that is, if some version of a program used path foo/bar to derive an Ed25519 keypair, a newer version shouldn’t use foo/bar to derive an AES-128 key. Violating this rule may lead to leaking the secret.

Examples

use secret_tree::{SecretTree, Name};
use rand::{Rng, thread_rng};
use secrecy::{ExposeSecret, Secret};

let tree = SecretTree::new(&mut thread_rng());
// Don't forget to securely store secrets! Here, we wrap them
// in a container that automatically zeroes the secret on drop.
let first_secret: Secret<[u8; 32]> = tree
    .child(Name::new("first"))
    .create_secret();

// We can derive hierarchical secrets. The secrets below
// follow logical paths `sequence/0`, `sequence/1`, .., `sequence/4`
// relative to the `tree`.
let child_store = tree.child(Name::new("sequence"));
let more_secrets: Vec<Secret<[u64; 4]>> = (0..5)
    .map(|i| Secret::new(child_store.index(i).rng().gen()))
    .collect();

// The tree is compactly stored as a single 32-byte seed.
let seed = tree.seed().to_owned();
drop(tree);

// If we restore the tree from the seed, we can restore all derived secrets.
let tree = SecretTree::from_seed(seed);
let restored_secret: Secret<[u8; 32]> = tree
    .child(Name::new("first"))
    .create_secret();
assert_eq!(
    first_secret.expose_secret(),
    restored_secret.expose_secret()
);

Implementations

Generates a tree by sampling its seed from the supplied RNG.

Creates a tree from the seed.

Restores a tree from the seed specified as a byte slice.

Errors

Returns an error if bytes has an invalid length (not SEED_LEN).

Returns the tree seed.

Converts this tree into a cryptographically secure pseudo-random number generator (CSPRNG). This RNG can then be used to reproducibly create secrets (e.g., secret keys).

Security

Self::fill() should be preferred if the secret allows it. While using a CSPRNG to generate secrets is theoretically sound, it introduces a new entity that may leak information. fill() is especially useful if the filled buffer implements zeroing on drop; the state of a CSPRNG generator returned by rng() is not zeroed on drop and thus creates a potential attack vector. (However theoretical it may be; ChaChaRng has a notably small state size - ~160 bytes, so it may be better localized and have lower risk to be accessed by the adversary than other CSPRNG implementations.)

Tries to fill the specified buffer with a key derived from the seed of this tree.

Errors

Errors if the buffer does not have length 16..=64 bytes. Use Self::rng() if the buffer size may be outside these bounds, or if the secret must be derived in a more complex way.

Fills the specified buffer with a key derived from the seed of this tree.

Panics

Panics in the same cases when Self::try_fill() returns an error.

Tries to create a secret by instantiating a buffer and filling it with a key derived from the seed of this tree. Essentially, this is a more high-level wrapper around Self::try_fill().

Errors

Returns an error if T does not have length 16..=64 bytes. Use Self::rng() if the buffer size may be outside these bounds, or if the secret must be derived in a more complex way.

Creates a secret by instantiating a buffer and filling it with a key derived from the seed of this tree.

Panics

Panics in the same cases when Self::try_create_secret() returns an error.

Produces a child with the specified string identifier.

Produces a child with the specified integer index.

Produces a child with the specified 32-byte digest (e.g., an output of SHA-256, SHA3-256 or Keccak256 hash functions).

This method can be used for arbitrarily-sized keys by first digesting them with a collision-resistant hash function.

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

Should always be Self

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.