mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-08-02 10:57:33 -04:00
feat(store-encryption): Add the EncryptableValue.
This patch introduces the `EncryptableValue` trait to represent usual operations on a value to be encoded by `encrypt_value_data`.
This commit is contained in:
@@ -23,7 +23,7 @@ use std::{
|
||||
use async_trait::async_trait;
|
||||
use deadpool_sync::InteractError;
|
||||
use itertools::Itertools;
|
||||
use matrix_sdk_store_encryption::StoreCipher;
|
||||
use matrix_sdk_store_encryption::{EncryptableValue, StoreCipher};
|
||||
use ruma::{OwnedEventId, OwnedRoomId, serde::Raw, time::SystemTime};
|
||||
use rusqlite::{OptionalExtension, Params, Row, Statement, Transaction, limits::Limit};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
@@ -641,12 +641,15 @@ pub(crate) trait EncryptableStore {
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_value(&self, value: Vec<u8>) -> Result<Vec<u8>> {
|
||||
fn encode_value<V>(&self, value: V) -> Result<Vec<u8>>
|
||||
where
|
||||
V: EncryptableValue + Into<Vec<u8>>,
|
||||
{
|
||||
if let Some(key) = self.get_cypher() {
|
||||
let encrypted = key.encrypt_value_data(value)?;
|
||||
Ok(rmp_serde::to_vec_named(&encrypted)?)
|
||||
} else {
|
||||
Ok(value)
|
||||
Ok(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -448,13 +448,16 @@ impl StoreCipher {
|
||||
/// assert_eq!(value, decrypted);
|
||||
/// # anyhow::Ok(()) };
|
||||
/// ```
|
||||
pub fn encrypt_value_data(&self, mut data: Vec<u8>) -> Result<EncryptedValue, Error> {
|
||||
pub fn encrypt_value_data<D>(&self, mut data: D) -> Result<EncryptedValue, Error>
|
||||
where
|
||||
D: EncryptableValue,
|
||||
{
|
||||
let nonce = Keys::get_nonce();
|
||||
let cipher = XChaCha20Poly1305::new(self.inner.encryption_key());
|
||||
|
||||
let ciphertext = cipher.encrypt(XNonce::from_slice(&nonce), data.as_ref())?;
|
||||
let ciphertext = cipher.encrypt(XNonce::from_slice(&nonce), data.as_bytes())?;
|
||||
|
||||
data.zeroize();
|
||||
data.zeroiize();
|
||||
Ok(EncryptedValue { version: VERSION, ciphertext, nonce })
|
||||
}
|
||||
|
||||
@@ -808,6 +811,53 @@ struct EncryptedStoreCipher {
|
||||
pub ciphertext_info: CipherTextInfo,
|
||||
}
|
||||
|
||||
/// A trait to get a slice of bytes and to zeroize a data, which are the
|
||||
/// required operations for [`StoreCipher::encrypt_value_data`].
|
||||
///
|
||||
/// The goal of this trait was to call [`Zeroize`] efficiently on `Vec<u8>` and
|
||||
/// `&[u8]`. We could call `vec.iter_mut().zeroize()` but the implementation of
|
||||
/// `Zeroize` on `Vec<u8>` does a bit more than that as it clears the vector and
|
||||
/// zeroizes the spare capacity as a best effort.
|
||||
pub trait EncryptableValue {
|
||||
/// Get the encodable value as bytes.
|
||||
fn as_bytes(&self) -> &[u8];
|
||||
|
||||
/// Zeroize the encodable value.
|
||||
///
|
||||
/// Called `zeroiize` to avoid clashes with [`Zeroize::zeroize`].
|
||||
fn zeroiize(&mut self);
|
||||
}
|
||||
|
||||
impl EncryptableValue for Vec<u8> {
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
AsRef::as_ref(self)
|
||||
}
|
||||
|
||||
fn zeroiize(&mut self) {
|
||||
Zeroize::zeroize(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl EncryptableValue for String {
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
str::as_bytes(self)
|
||||
}
|
||||
|
||||
fn zeroiize(&mut self) {
|
||||
Zeroize::zeroize(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl EncryptableValue for &mut [u8] {
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
self
|
||||
}
|
||||
|
||||
fn zeroiize(&mut self) {
|
||||
self.iter_mut().zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::{Value, json};
|
||||
|
||||
Reference in New Issue
Block a user