diff --git a/crates/matrix-store-key/Cargo.toml b/crates/matrix-sdk-store-encryption/Cargo.toml similarity index 94% rename from crates/matrix-store-key/Cargo.toml rename to crates/matrix-sdk-store-encryption/Cargo.toml index 38c408a8a..efcc2d70a 100644 --- a/crates/matrix-store-key/Cargo.toml +++ b/crates/matrix-sdk-store-encryption/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "matrix-sdk-store-key" +name = "matrix-sdk-store-encryption" version = "0.1.0" edition = "2021" description = "Helpers for encrypted storage keys for the Matrix SDK" diff --git a/crates/matrix-store-key/README.md b/crates/matrix-sdk-store-encryption/README.md similarity index 71% rename from crates/matrix-store-key/README.md rename to crates/matrix-sdk-store-encryption/README.md index b311713b2..04f95d50e 100644 --- a/crates/matrix-store-key/README.md +++ b/crates/matrix-sdk-store-encryption/README.md @@ -3,30 +3,30 @@ A general purpose encryption scheme for key/value stores. # Usage ```rust -use matrix_sdk_store_key::StoreKey; +use matrix_sdk_store_encryption::StoreCipher; use serde_json::{json, value::Value}; fn main() -> anyhow::Result<()> { - let store_key = StoreKey::new()?; + let store_cipher = StoreCipher::new()?; - // Export the store key and persist it in your key/value store - let export = store_key.export("secret-passphrase")?; + // Export the store cipher and persist it in your key/value store + let export = store_cipher.export("secret-passphrase")?; let value = json!({ "some": "data", }); - let encrypted = store_key.encrypt_value(&value)?; - let decrypted: Value = store_key.decrypt_value(&encrypted)?; + let encrypted = store_cipher.encrypt_value(&value)?; + let decrypted: Value = store_cipher.decrypt_value(&encrypted)?; assert_eq!(value, decrypted); let key = "bulbasaur"; // Hash the key so people don't know which pokemon we have collected. - let hashed_key = store_key.hash_key("list-of-pokemon", key.as_ref()); - let another_table = store_key.hash_key("my-starter", key.as_ref()); - let same_key = store_key.hash_key("my-starter", key.as_ref()); + let hashed_key = store_cipher.hash_key("list-of-pokemon", key.as_ref()); + let another_table = store_cipher.hash_key("my-starter", key.as_ref()); + let same_key = store_cipher.hash_key("my-starter", key.as_ref()); assert_ne!(key.as_ref(), hashed_key); assert_ne!(hashed_key, another_table); @@ -46,7 +46,7 @@ USE AT YOUR OWN RISK! # Encryption scheme -A `StoreKey` consists of two randomly generated 32 byte-sized slices. +A `StoreCipher` consists of two randomly generated 32 byte-sized slices. The first 32 bytes are used to encrypt values. XChaCha20Poly1305 with a random nonce is used to encrypt each value. The nonce is saved with the ciphertext. @@ -57,19 +57,19 @@ keyed hash construction. ```text ┌───────────────────────────────────────┐ - │ StoreKey │ + │ StoreCipher │ │ Encryption key | Hash key seed │ │ [u8; 32] | [u8; 32] │ └───────────────────────────────────────┘ ``` -The `StoreKey` has some Matrix-specific assumptions built in, which ensure that +The `StoreCipher` has some Matrix-specific assumptions built in, which ensure that the limits of the cryptographic primitives are not exceeded. If this crate is used for non-Matrix data, users need to ensure: 1. That individual values are chunked, otherwise decryption might be susceptible to a DOS attack. -2. The `StoreKey` is periodically rotated/rekeyed. +2. The `StoreCipher` is periodically rotated/rekeyed. # WASM support diff --git a/crates/matrix-store-key/src/lib.rs b/crates/matrix-sdk-store-encryption/src/lib.rs similarity index 76% rename from crates/matrix-store-key/src/lib.rs rename to crates/matrix-sdk-store-encryption/src/lib.rs index fc6c372a6..139cff95d 100644 --- a/crates/matrix-store-key/src/lib.rs +++ b/crates/matrix-sdk-store-encryption/src/lib.rs @@ -39,7 +39,7 @@ const KDF_ROUNDS: u32 = 1000; type MacKeySeed = [u8; 32]; -/// Error type for the `StoreKey` operations. +/// Error type for the `StoreCipher` operations. #[derive(Debug, Display, thiserror::Error)] pub enum Error { /// Failed to serialize or deserialize a value {0} @@ -60,58 +60,59 @@ pub enum Error { /// /// ``` /// # let example = || { -/// use matrix_sdk_store_key::StoreKey; +/// use matrix_sdk_store_encryption::StoreCipher; /// use serde_json::{json, value::Value}; /// -/// let store_key = StoreKey::new()?; +/// let store_cipher = StoreCipher::new()?; /// -/// // Export the store key and persist it in your key/value store -/// let export = store_key.export("secret-passphrase")?; +/// // Export the store cipher and persist it in your key/value store +/// let export = store_cipher.export("secret-passphrase")?; /// /// let value = json!({ /// "some": "data", /// }); /// -/// let encrypted = store_key.encrypt_value(&value)?; -/// let decrypted: Value = store_key.decrypt_value(&encrypted)?; +/// let encrypted = store_cipher.encrypt_value(&value)?; +/// let decrypted: Value = store_cipher.decrypt_value(&encrypted)?; /// /// assert_eq!(value, decrypted); /// # Result::<_, anyhow::Error>::Ok(()) }; /// ``` #[allow(missing_debug_implementations)] -pub struct StoreKey { +pub struct StoreCipher { inner: Keys, } -impl StoreKey { - /// Generate a new random store key. +impl StoreCipher { + /// Generate a new random store cipher. pub fn new() -> Result { Ok(Self { inner: Keys::new()? }) } - /// Encrypt the store key using the given passphrase and export it. + /// Encrypt the store cipher using the given passphrase and export it. /// - /// This method can be used to persist the `StoreKey` in the key/value store - /// in a safe manner. + /// This method can be used to persist the `StoreCipher` in the key/value + /// store in a safe manner. /// - /// The `StoreKey` can later on be restored using [`StoreKey::import`]. + /// The `StoreCipher` can later on be restored using + /// [`StoreCipher::import`]. /// /// # Arguments /// /// * `passphrase` - The passphrase that should be used to encrypt the - /// store key. + /// store cipher. /// /// # Examples /// /// ``` /// # let example = || { - /// use matrix_sdk_store_key::StoreKey; + /// use matrix_sdk_store_encryption::StoreCipher; /// use serde_json::json; /// - /// let store_key = StoreKey::new()?; + /// let store_cipher = StoreCipher::new()?; /// - /// // Export the store key and persist it in your key/value store - /// let export = store_key.export("secret-passphrase"); + /// // Export the store cipher and persist it in your key/value store + /// let export = store_cipher.export("secret-passphrase"); /// /// // Save the export in your key/value store. /// # Result::<_, anyhow::Error>::Ok(()) }; @@ -122,7 +123,7 @@ impl StoreKey { let mut salt = [0u8; KDF_SALT_SIZE]; salt.try_fill(&mut rng)?; - let key = StoreKey::expand_key(passphrase, &salt, KDF_ROUNDS); + let key = StoreCipher::expand_key(passphrase, &salt, KDF_ROUNDS); let key = ChachaKey::from_slice(key.as_ref()); let cipher = XChaCha20Poly1305::new(key); @@ -137,42 +138,43 @@ impl StoreKey { keys.zeroize(); - let store_key = EncryptedStoreKey { + let store_cipher = EncryptedStoreCipher { kdf_info: KdfInfo::Pbkdf2ToChaCha20Poly1305 { rounds: KDF_ROUNDS, kdf_salt: salt }, ciphertext_info: CipherTextInfo::ChaCha20Poly1305 { nonce, ciphertext }, }; - Ok(serde_json::to_vec(&store_key).expect("Can't serialize the store key")) + Ok(serde_json::to_vec(&store_cipher).expect("Can't serialize the store cipher")) } - /// Restore a store key from an encrypted export. + /// Restore a store cipher from an encrypted export. /// /// # Arguments /// - /// * `passphrase` - The passphrase that was used to encrypt the store key. + /// * `passphrase` - The passphrase that was used to encrypt the store + /// cipher. /// - /// * `encrypted` - The exported and encrypted version of the store key. + /// * `encrypted` - The exported and encrypted version of the store cipher. /// /// # Examples /// /// ``` /// # let example = || { - /// use matrix_sdk_store_key::StoreKey; + /// use matrix_sdk_store_encryption::StoreCipher; /// use serde_json::json; /// - /// let store_key = StoreKey::new()?; + /// let store_cipher = StoreCipher::new()?; /// - /// // Export the store key and persist it in your key/value store - /// let export = store_key.export("secret-passphrase")?; + /// // Export the store cipher and persist it in your key/value store + /// let export = store_cipher.export("secret-passphrase")?; /// - /// // This is now the same as `store_key`. - /// let imported = StoreKey::import("secret-passphrase", &export)?; + /// // This is now the same as `store_cipher`. + /// let imported = StoreCipher::import("secret-passphrase", &export)?; /// /// // Save the export in your key/value store. /// # Result::<_, anyhow::Error>::Ok(()) }; /// ``` pub fn import(passphrase: &str, encrypted: &[u8]) -> Result { - let encrypted: EncryptedStoreKey = serde_json::from_slice(encrypted)?; + let encrypted: EncryptedStoreCipher = serde_json::from_slice(encrypted)?; let key = match encrypted.kdf_info { KdfInfo::Pbkdf2ToChaCha20Poly1305 { rounds, kdf_salt } => { @@ -232,15 +234,15 @@ impl StoreKey { /// /// ``` /// # let example = || { - /// use matrix_sdk_store_key::StoreKey; + /// use matrix_sdk_store_encryption::StoreCipher; /// use serde_json::json; /// - /// let store_key = StoreKey::new()?; + /// let store_cipher = StoreCipher::new()?; /// /// let key = "bulbasaur"; /// /// // Hash the key so people don't know which pokemon we have collected. - /// let hashed_key = store_key.hash_key("list-of-pokemon", key.as_ref()); + /// let hashed_key = store_cipher.hash_key("list-of-pokemon", key.as_ref()); /// /// // It's now safe to insert the key into our key/value store. /// # Result::<_, anyhow::Error>::Ok(()) }; @@ -253,7 +255,8 @@ impl StoreKey { /// Encrypt a value before it is inserted into the key/value store. /// - /// A value can be decrypted using the [`StoreKey::decrypt_value()`] method. + /// A value can be decrypted using the [`StoreCipher::decrypt_value()`] + /// method. /// /// # Arguments /// @@ -265,17 +268,17 @@ impl StoreKey { /// /// ``` /// # let example = || { - /// use matrix_sdk_store_key::StoreKey; + /// use matrix_sdk_store_encryption::StoreCipher; /// use serde_json::{json, value::Value}; /// - /// let store_key = StoreKey::new()?; + /// let store_cipher = StoreCipher::new()?; /// /// let value = json!({ /// "some": "data", /// }); /// - /// let encrypted = store_key.encrypt_value(&value)?; - /// let decrypted: Value = store_key.decrypt_value(&encrypted)?; + /// let encrypted = store_cipher.encrypt_value(&value)?; + /// let decrypted: Value = store_cipher.decrypt_value(&encrypted)?; /// /// assert_eq!(value, decrypted); /// # Result::<_, anyhow::Error>::Ok(()) }; @@ -295,7 +298,8 @@ impl StoreKey { /// Decrypt a value after it was fetchetd from the key/value store. /// - /// A value can be encrypted using the [`StoreKey::encrypt_value()`] method. + /// A value can be encrypted using the [`StoreCipher::encrypt_value()`] + /// method. /// /// # Arguments /// @@ -307,17 +311,17 @@ impl StoreKey { /// /// ``` /// # let example = || { - /// use matrix_sdk_store_key::StoreKey; + /// use matrix_sdk_store_encryption::StoreCipher; /// use serde_json::{json, value::Value}; /// - /// let store_key = StoreKey::new()?; + /// let store_cipher = StoreCipher::new()?; /// /// let value = json!({ /// "some": "data", /// }); /// - /// let encrypted = store_key.encrypt_value(&value)?; - /// let decrypted: Value = store_key.decrypt_value(&encrypted)?; + /// let encrypted = store_cipher.encrypt_value(&value)?; + /// let decrypted: Value = store_cipher.decrypt_value(&encrypted)?; /// /// assert_eq!(value, decrypted); /// # Result::<_, anyhow::Error>::Ok(()) }; @@ -429,27 +433,27 @@ enum KdfInfo { } /// Version specific info for encryption method that is used to encrypt our -/// store key. +/// store cipher. #[derive(Debug, Serialize, Deserialize, PartialEq)] enum CipherTextInfo { - /// A store key encrypted using the ChaCha20Poly1305 AEAD. + /// A store cipher encrypted using the ChaCha20Poly1305 AEAD. ChaCha20Poly1305 { /// The nonce that was used to encrypt the ciphertext. nonce: [u8; XNONCE_SIZE], - /// The encrypted store key. + /// The encrypted store cipher. ciphertext: Vec, }, } -/// An encrypted version of our store key, this can be safely stored in a +/// An encrypted version of our store cipher, this can be safely stored in a /// database. #[derive(Debug, Serialize, Deserialize, PartialEq)] -struct EncryptedStoreKey { +struct EncryptedStoreCipher { /// Info about the key derivation method that was used to expand the /// passphrase into an encryption key. pub kdf_info: KdfInfo, /// The ciphertext with it's accompanying additional data that is needed to - /// decrypt the store key. + /// decrypt the store cipher. pub ciphertext_info: CipherTextInfo, } @@ -457,29 +461,29 @@ struct EncryptedStoreKey { mod test { use serde_json::{json, Value}; - use super::{Error, StoreKey}; + use super::{Error, StoreCipher}; #[test] fn generating() { - StoreKey::new().unwrap(); + StoreCipher::new().unwrap(); } #[test] - fn exporting_store_key() -> Result<(), Error> { + fn exporting_store_cipher() -> Result<(), Error> { let passphrase = "it's a secret to everybody"; - let store_key = StoreKey::new()?; + let store_cipher = StoreCipher::new()?; let value = json!({ "some": "data" }); - let encrypted_value = store_key.encrypt_value(&value)?; + let encrypted_value = store_cipher.encrypt_value(&value)?; - let encrypted = store_key.export(passphrase)?; - let decrypted = StoreKey::import(passphrase, &encrypted)?; + let encrypted = store_cipher.export(passphrase)?; + let decrypted = StoreCipher::import(passphrase, &encrypted)?; - assert_eq!(store_key.inner.encryption_key, decrypted.inner.encryption_key); - assert_eq!(store_key.inner.mac_key_seed, decrypted.inner.mac_key_seed); + assert_eq!(store_cipher.inner.encryption_key, decrypted.inner.encryption_key); + assert_eq!(store_cipher.inner.mac_key_seed, decrypted.inner.mac_key_seed); let decrypted_value: Value = decrypted.decrypt_value(&encrypted_value)?; @@ -503,10 +507,10 @@ mod test { }, }); - let store_key = StoreKey::new()?; + let store_cipher = StoreCipher::new()?; - let encrypted = store_key.encrypt_value(&event)?; - let decrypted: Value = store_key.decrypt_value(&encrypted)?; + let encrypted = store_cipher.encrypt_value(&event)?; + let decrypted: Value = store_cipher.decrypt_value(&encrypted)?; assert_eq!(event, decrypted); @@ -515,13 +519,13 @@ mod test { #[test] fn encrypting_keys() -> Result<(), Error> { - let store_key = StoreKey::new()?; + let store_cipher = StoreCipher::new()?; - let first = store_key.hash_key("some_table", b"It's dangerous to go alone"); - let second = store_key.hash_key("some_table", b"It's dangerous to go alone"); - let third = store_key.hash_key("another_table", b"It's dangerous to go alone"); - let fourth = store_key.hash_key("another_table", b"It's dangerous to go alone"); - let fifth = store_key.hash_key("another_table", b"It's not dangerous to go alone"); + let first = store_cipher.hash_key("some_table", b"It's dangerous to go alone"); + let second = store_cipher.hash_key("some_table", b"It's dangerous to go alone"); + let third = store_cipher.hash_key("another_table", b"It's dangerous to go alone"); + let fourth = store_cipher.hash_key("another_table", b"It's dangerous to go alone"); + let fifth = store_cipher.hash_key("another_table", b"It's not dangerous to go alone"); assert_eq!(first, second); assert_ne!(first, third);