diff --git a/src/ikm.rs b/src/ikm.rs index 07861ec..9fbeb1d 100644 --- a/src/ikm.rs +++ b/src/ikm.rs @@ -5,8 +5,17 @@ use std::time::{Duration, SystemTime}; pub(crate) const IKM_BASE_STRUCT_SIZE: usize = 25; pub(crate) type CounterId = u32; +/// Abstract type representing the identifier of an [InputKeyMaterial]. pub type IkmId = u32; +/// An input key material (IKM) is a secret random seed that is used to derive cryptographic keys. +/// +/// In order to manage your IKMs, each one of them has an unique identifier. An IKM is also tight +/// to a specific context in which it may be used. Keep in mind that an IKM is linked to a specific +/// algorithm, as an expiration date and can be revoked. +/// +/// This struct is exposed so you can display its informations when managing your IKMs using an +/// [InputKeyMaterialList]. It it not meant to be used otherwise. #[derive(Debug)] pub struct InputKeyMaterial { pub id: IkmId, @@ -71,6 +80,68 @@ impl InputKeyMaterial { } } +/// A list of [InputKeyMaterial] (IKM). This is where you should manage your secrets. +/// +/// The way coffio works is quite simple: you generate a secret random seed (an input key material, +/// IKM) that is used to derive cryptographic keys, which are used to encrypt your data. However, +/// if your IKM or any derived key has leaked, or if you wishes to change the encryption algorithm, +/// you need to generate an other IKM. This is why coffio uses a single opaque token capable of +/// containing several IKMs, the [InputKeyMaterialList]. This way, the transition between two IKMs +/// is smooth: you can use the new IKM to encrypt all new secrets and keep the revoked one to +/// decrypt secrets it has already encrypted and you haven't re-encrypted using the new IKM yet. +/// +/// This list is ordered. To encrypt new data, coffio will always use the last IKM that is not +/// revoked and is within its validity period. +/// +/// Encrypted data contains the [IkmId] of the IKM used to derive the key. To decrypt data, coffio +/// will therefore search for this specific IKM in the [InputKeyMaterialList]. +/// +///
+/// Never remove an IKM from the list unless you are absolutely sure that all data encrypted using +/// this IKM have been either deleted or re-encrypted using another IKM. +///
+/// +/// # Examples +/// +/// ``` +/// use coffio::{InputKeyMaterialList, Scheme}; +/// use std::time::Duration; +/// +/// // Create an empty IKM list. +/// let mut ikml = InputKeyMaterialList::new(); +/// assert_eq!(ikml.len(), 0); +/// +/// // Add an IKM to the list with the default settings. +/// let _ = ikml.add_ikm(); +/// assert_eq!(ikml.len(), 1); +/// +/// // Add an IKM to the list with custom settings. +/// let _ = ikml.add_custom_ikm( +/// Scheme::Aes128GcmWithSha256, +/// Duration::from_secs(315_569_252), +/// ); +/// assert_eq!(ikml.len(), 2); +/// +/// // Retreive the id of the first IKM. +/// let ikm_id = ikml[0].id.clone(); +/// +/// // Revoke the first IKM. +/// ikml.revoke_ikm(ikm_id); +/// assert_eq!(ikml.len(), 2); +/// +/// // Delete the first IKM. +/// ikml.delete_ikm(ikm_id); +/// assert_eq!(ikml.len(), 1); +/// +/// // Export the IKM list +/// let exported_ikml = ikml.export()?; +/// println!("My secret IKM list: {exported_ikml}"); +/// +/// // Import an IKM list +/// let ikml2 = InputKeyMaterialList::import(&exported_ikml)?; +/// assert_eq!(ikml2.len(), 1); +/// # Ok::<(), coffio::Error>(()) +/// ``` #[derive(Debug, Default)] pub struct InputKeyMaterialList { pub(crate) ikm_lst: Vec, diff --git a/src/lib.rs b/src/lib.rs index 7183f7b..2d4343c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(doc_auto_cfg)] + #[cfg(feature = "encryption")] mod canonicalization; #[cfg(feature = "encryption")] diff --git a/src/scheme.rs b/src/scheme.rs index 7df5976..bb8bb85 100644 --- a/src/scheme.rs +++ b/src/scheme.rs @@ -23,9 +23,44 @@ pub(crate) type EncryptionFunction = dyn Fn(&[u8], &[u8], &[u8], &str) -> Result pub(crate) type GenNonceFunction = dyn Fn() -> Result>; pub(crate) type SchemeSerializeType = u32; +/// The cryptographic primitives used to encrypt the data. +/// +/// Coffio does not impose an unique way to encrypt data. You can therefore choose between one of +/// the supported scheme. Each scheme has advantages and drawbacks. +/// +/// Before choosing a scheme, you should run the benchmark on the hardware where the encryption and +/// decryption process will take place. Some scheme may have hardware optimizations that you want +/// to take advantage of. Regarding the key length, the following website may help you choose one +/// that suits your requirements: [https://www.keylength.com/](https://www.keylength.com/) +/// +/// In the following scheme description, the following terms are used: +/// - `Max data size` describes the maximal size of data that can safely be encrypted using a +/// single key and nonce, which means you should never pass a `data` parameter to +/// [encrypt][crate::CipherBox::encrypt] that has a higher size. Coffio will not enforce this +/// limit, it is your responsibility to do so. +/// - `Max invocations` describes the maximal number of times you can safely call +/// [encrypt][crate::CipherBox::encrypt] with a single key, which means you should either rotate +/// your IKM or use an appropriate key periodicity before reaching this number. Coffio will neither +/// enforce this limit nor count the number of invocations, it is your responsibility to do so. #[derive(Copy, Clone, Debug, PartialEq)] pub enum Scheme { + /// `default` + /// - Key derivation: BLAKE3 derive_key mode + /// - Encryption: XChaCha20-Poly1305 + /// - Key size: 256 bits + /// - Nonce size: 192 bits + /// - Max data size: 256 GB + /// - Max invocations: no limitation + /// - Resources: [RFC 7539](https://datatracker.ietf.org/doc/html/rfc7539), + /// [draft-irtf-cfrg-xchacha](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha) XChaCha20Poly1305WithBlake3 = 1, + /// - Key derivation: HKDF-SHA256 + /// - Encryption: AES-GCM + /// - Key size: 128 bits + /// - Nonce size: 96 bits + /// - Max data size: 64 GB + /// - Max invocations: 232 + /// - Resources: [NIST SP 800-38D](https://doi.org/10.6028/NIST.SP.800-38D) Aes128GcmWithSha256 = 2, }