Skip to main content

EncryptedStorage

Struct EncryptedStorage 

Source
pub struct EncryptedStorage { /* private fields */ }
Expand description

Transparent encryption wrapper around any StorageBackend.

All data written through this wrapper is encrypted before reaching the inner storage, and decrypted when read back. The encryption is completely transparent to the rest of the database engine.

Implementations§

Source§

impl EncryptedStorage

Source

pub fn new(inner: Arc<dyn StorageBackend>, master_key: &[u8; 32]) -> Self

Create a new EncryptedStorage wrapping inner with the given 32-byte key.

Call derive_key() first to turn a human-readable password into a key. The key must be exactly 32 bytes (256 bits) — the size XChaCha20 requires.

Source

pub fn derive_key(password: &str, salt_context: &str) -> [u8; 32]

Derive a deterministic 32-byte encryption key from a password string using the Argon2id algorithm.

salt_context is typically the database file path — this ensures that the same password produces different keys for different database files, preventing cross-database attacks.

Argon2id is intentionally slow (memory-hard) to make brute-force attacks expensive. The default parameters require ~64 MB of RAM and ~0.5 s of CPU.

Trait Implementations§

Source§

impl StorageBackend for EncryptedStorage

Implement the StorageBackend trait so EncryptedStorage can be used anywhere a StorageBackend is expected — the rest of the engine doesn’t know or care that encryption is happening.

Source§

fn write_entry(&self, entry: &LogEntry) -> Result<(), DbError>

Encrypt entry and write the resulting ENC entry to the inner backend.

Source§

fn read_log(&self) -> Result<Vec<LogEntry>, DbError>

Read all ENC entries from the inner backend and decrypt them.

Entries that fail to decrypt are skipped with a warning (not a crash) so a single corrupt entry doesn’t bring down the whole database. Unencrypted entries (cmd != “ENC”) are passed through unchanged — this supports migrating an existing plaintext database to encrypted.

Source§

fn compact(&self, entries: Vec<LogEntry>) -> Result<(), DbError>

Re-encrypt all entries during compaction so the compacted file is fully encrypted with no plaintext remnants from a migration.

Each entry gets a fresh random nonce — even if the plaintext is the same as before, the ciphertext will be different (this is correct and expected).

Source§

fn read_at(&self, offset: u64, length: u32) -> Result<Vec<u8>, DbError>

Read exactly length bytes from the inner backend and decrypt the entry.

Note: in the encrypted Bitcask model, the pointer refers to the offset and length of the ENCRYPTED entry in the log.

Source§

fn stream_log_into( &self, f: &mut dyn FnMut(LogEntry, u32), ) -> Result<u64, DbError>

Stream log entries into state one at a time, without loading the full log into RAM. Implementations may load a binary snapshot first and only replay the delta lines written after the snapshot. Read more
Source§

fn get_size(&self) -> Result<u64, DbError>

Return the current size of the persistent log file in bytes. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

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

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more