fog_crypto/lib.rs
1//! A simple storage-oriented cryptographic library that offers you freedom from choice. It
2//! supports hashing, public key signatures, public key & symmetric key encryption, key
3//! export/import, and basic key storage.
4//!
5//! Getting cryptography right can be hard. This library attempts to make things easy by only
6//! providing a small number of cryptographic primitives, makes strong decisions about the
7//! cryptographic algorithms and their implementations, and tries to limit the number of bad things
8//! an end user can do. Changing algorithms should be infrequent, and follows a planned process
9//! (see [Cryptographic Versioning](#cryptographic-versioning)). On the plus side, it's pretty hard
10//! to misuse this library in ways that leak secrets and compromise security. On the downside, this
11//! library is pretty strongly meant for working with stored data, not communication protocols, and
12//! cannot support even remotely unusual cryptographic operations. Forcing use of a single preferred
13//! set of algorithms also greatly limits hardware compatibility.
14//!
15//! # User Guidelines
16//!
17//! You probably shouldn't be using this library directly. Portions of it should instead be
18//! exported by an implementor of a Vault, and you should use those. Alternately, you might be
19//! using this through [`fog-pack`](https://crates.io/crates/fog-pack), which also re-exports
20//! portions of this library. You can expect to see these primitives:
21//!
22//! General:
23//! - [`Vault`]: A structure that can hold onto your cryptographic keys.
24//!
25//! Hashing:
26//! - [`Hash`](hash::Hash): The cryptographic hash of a sequence of bytes.
27//! - [`HashState`](hash::HashState): A structure for iteratively feeding in bytes to create a `Hash`.
28//!
29//! Signatures:
30//! - [`Signature`]: A validated cryptographic signature of a `Hash`.
31//! - [`UnverifiedSignature`]: A cryptographic signature that hasn't been verified yet.
32//! - [`IdentityKey`]: A private key for signing hashes.
33//! - [`Identity`]: A public key identity to indicate which `IdentityKey` created a given `Signature`.
34//! - [`BareIdKey`]: A private signing key that can be exported without encrypting it.
35//!
36//! Symmetric-Key Encryption:
37//! - [`StreamKey`]: A shared symmetric key for encrypting & decrypting data.
38//! - [`StreamId`]: A public, unique identifier for indicating what `StreamKey` should be used
39//! for decrypting encrypted data.
40//!
41//! Public-Key Encryption:
42//! - [`LockKey`]: A private key for decrypting data.
43//! - [`LockId`]: A public key to indicate what `LockKey` should be used for decrypting encrypted
44//! data.
45//!
46//! Encrypted Storage:
47//! - [`IdentityLockbox`]: An encrypted container that holds a `IdentityKey`.
48//! - [`StreamLockbox`]: An encrypted container that holds a `StreamKey`.
49//! - [`LockLockbox`]: An encrypted container that holds a `LockKey`.
50//! - [`DataLockbox`]: An encrypted container that holds a byte sequence.
51//!
52//! # Vault Implementor Guidelines
53//!
54//! First, re-export the structs listed in the user guidelines. If your vault is entirely in
55//! software, you probably want to use the various `ContainedXXX` structs for holding keys, and
56//! store them by exporting them for some master key. Avoid letting the keys sit around in some
57//! unencrypted form. Your master key can be created by obtaining a 32-byte random byte sequence,
58//! prepending it with a 1 (the version byte), and using [`BareStreamKey`]'s `try_from`
59//! implementation to encapsulate the sequence. Make sure to zeroize the master key after doing
60//! this!
61//!
62//! If your vault has a hardware or OS component, your hardware vault's capabilities may be
63//! limited in its ability to store all types of keys. In this case, you will need to have a
64//! software-side implementation to make up for the missing storage. A recommended approach here is
65//! to actually accept a reference to a pure-software vault on creation, and let it handle any
66//! unsupported operations. Your vault can then capture all operations that it does support.
67//!
68//! Alternately, if your hardware / OS component supports an extremely small subset of
69//! functionality, cannot perform any type of key import/export, and is meant for high risk
70//! scenarios, consider not supporting the Vault trait at all. Instead, create your own key store
71//! interface, and provide backer implementations for just the supported interfaces (your options
72//! being [`SignInterface`], [`StreamInterface`], and [`LockInterface`]).
73//!
74//! # Cryptographic Algorithms Used
75//!
76//! The currently used algorithms are:
77//!
78//! - Hashing: Blake2B with a 32-byte digest
79//! - Signing: Ed25519 with ["strict" verification][StrictVerification]
80//! - Symmetric Encryption: AEAD cipher using XChaCha20 and Poly1305.
81//! - Diffie-Hellman key exchange: X25519
82//!
83//! # Cryptographic Versioning
84//!
85//! This library has 4 core cryptographic algorithms that may be upgraded over time:
86//!
87//! - The hash algorithm
88//! - The signing algorithm
89//! - The symmetric encryption algorithm (including bulk encryption, AEAD construction, and HMAC)
90//! - The Diffie-Hellman (DH) key exchange algorithm (used for encrypting data with a public key)
91//!
92//! Upgrades should be infrequent, and are done roughly when an existing recommended algorithm is
93//! regarded as weak but not yet broken.
94//!
95//! The ideal upgrade process is:
96//!
97//! 1. A new algorithm is selected to replace an existing one.
98//! 2. The new algorithm is implemented. The relevant MAX_VERSION constant is incremented.
99//! 3. After being deployed for 1 year, the relevant DEFAULT_VERSION constant is incremented. This
100//! gives time for library users to support the new algorithm without breaking non-updated
101//! deployments.
102//! 4. After 2 more years, the relevant MIN_VERSION constant is incremented. This gives time for
103//! library users to increment the default version on all deployments, then upgrade all existing
104//! stored data as required.
105//!
106//! This is the best-case upgrade scenario. If an existing algorithm is considered broken, the
107//! DEFAULT_VERSION and MIN_VERSION will be incremented as soon as possible. "Broken" here means it
108//! is feasible for a well-funded attacker to compromise the algorithm. Breaking compatibility with
109//! deployed code is considered an acceptable choice when security is compromised.
110//!
111//! We are almost certainly going to upgrade the signing and DH exchange algorithms in the future,
112//! as we will need to move to post-quantum algorithms. There's no similar looming threat for the
113//! hash & symmetric encryption algorithms.
114//!
115//! [StrictVerification]: https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.PublicKey.html#method.verify_strict
116
117#[cfg(feature = "with-serde")]
118pub mod serde;
119
120mod error;
121pub use self::error::CryptoError;
122
123pub mod hash;
124
125pub mod identity;
126use identity::*;
127
128pub mod lock;
129use lock::*;
130
131pub mod lockbox;
132use lockbox::*;
133
134pub mod stream;
135use stream::*;
136
137use rand_core::{CryptoRng, RngCore};
138
139/// Holds a cryptographic random number generator (RNG). This trait is needed so that a RNG can be
140/// passed around as a trait object.
141pub trait CryptoSrc: CryptoRng + RngCore {}
142impl<T: CryptoRng + RngCore> CryptoSrc for T {}
143
144/// A trait to interface with long-term storage of various cryptographic keys.
145///
146/// Any implementor should store keys in three separate key-value stores: one for `IdentityKey`
147/// storage, one for `LockKey` storage, and one for `StreamKey` storage. Each provides a separate
148/// lookup by name, or the various keys may be retrieved by looking them up by their public
149/// identities.
150pub trait Vault {
151 /// Create & store a new `IdentityKey`.
152 fn new_id(&self, name: String) -> IdentityKey;
153
154 /// Create & store a new `LockKey`.
155 fn new_lock(&self, name: String) -> LockKey;
156
157 /// Create & store a new `StreamKey`.
158 fn new_stream(&self, name: String) -> StreamKey;
159
160 /// Fetch a stored `IdentityKey` by name. Returns none if no key by that name is stored.
161 fn get_id(&self, name: &str) -> Option<IdentityKey>;
162
163 /// Fetch a stored `LockKey` by name. Returns none if no key by that name is stored.
164 fn get_lock(&self, name: &str) -> Option<LockKey>;
165
166 /// Fetch a stored `StreamKey` by name. Returns none if no key by that name is stored.
167 fn get_stream(&self, name: &str) -> Option<StreamKey>;
168
169 /// Fetch a stored `IdentityKey` by its public `Identity`, also returning the name it is stored
170 /// under. Returns none if the key is not in the vault.
171 fn find_id(&self, id: Identity) -> Option<(&str, IdentityKey)>;
172
173 /// Fetch a stored `LockKey` by its public `LockId`, also returning the name it is stored
174 /// under. Returns none if the key is not in the vault.
175 fn find_lock(&self, lock: LockId) -> Option<(&str, LockKey)>;
176
177 /// Fetch a stored `StreamKey` by its public `StreamId`, also returning the name it is stored
178 /// under. Returns none if the key is not in the vault.
179 fn find_stream(&self, stream: StreamId) -> Option<(&str, StreamKey)>;
180
181 /// Change the lookup name for a `StreamKey`.
182 fn rename_id(&self, old_name: &str, new_name: String) -> bool;
183
184 /// Change the lookup name for a `StreamKey`.
185 fn rename_lock(&self, old_name: &str, new_name: String) -> bool;
186
187 /// Change the lookup name for a `StreamKey`.
188 fn rename_stream(&self, old_name: &str, new_name: String) -> bool;
189
190 /// Remove the `IdentityKey` stored under this name.
191 fn remove_id(&self, name: &str) -> bool;
192
193 /// Remove the `LockKey` stored under this name.
194 fn remove_lock(&self, name: &str) -> bool;
195
196 /// Remove the `StreamKey` stored under this name.
197 fn remove_stream(&self, name: &str) -> bool;
198
199 /// Attempt to decrypt a `LockLockbox` using any of the `LockKey` and `StreamKey` instances
200 /// stored. On success, the new `LockKey` is stored in the vault under the provided name.
201 fn decrypt_lock_key(&self, name: String, lock: &LockLockboxRef)
202 -> Result<LockKey, CryptoError>;
203
204 /// Attempt to decrypt a `IdentityLockbox` using any of the `LockKey` and `StreamKey` instances
205 /// stored. On success, the new `IdentityKey` is stored in the vault under the provided name.
206 fn decrypt_identity_key(
207 &self,
208 name: String,
209 lock: &IdentityLockboxRef,
210 ) -> Result<IdentityKey, CryptoError>;
211
212 /// Attempt to decrypt a `StreamLockbox` using any of the `LockKey` and `StreamKey` instances
213 /// stored. On success, the new `StreamKey` is stored in the vault under the provided name.
214 fn decrypt_stream_key(
215 &self,
216 name: String,
217 lock: &StreamLockboxRef,
218 ) -> Result<StreamKey, CryptoError>;
219
220 /// Attempt to decrypt a `StreamLockbox` using any of the `LockKey` and `StreamKey` instances
221 /// stored.
222 fn decrypt_data(&self, lock: &DataLockbox) -> Result<Vec<u8>, CryptoError>;
223}