/microkv

Minimal and persistent key-value store designed with security in mind

Primary LanguageRustMIT LicenseMIT

microkv

Actions crates.io version Docs

Minimal and persistent key-value store designed with security in mind.

Introduction

microkv is a minimal and persistent key-value store designed with security in mind, built to prioritize secure storage for client-side application. I created this project out of a yearning to learn more about the intricacies of distributed systems, databases, and secure persistent storage.

While microkv shouldn't be used in large-scale environments that facilitate an insane volume of transactional interactions, it is still optimal for use in a production-grade system/application that may not require the complex luxuries of a full-blown database or even industry-standard KV-store like Redis or LevelDB.

Features

  • Performant

microkv's underlying map structure is based off of @bluss's indexmap implementation, which offers performance on par with built-in HashMap's amortized constant runtime, but can also provided sorted key iteration, similar to the less-performant BTreeMap. This provides a strong balance between performance and functionality.

When reading and persisting to disk, the key-value store uses bincode for fast de/serialization of the underlying structures, allowing users to insert any serializable structure without worrying about incurred overhead for storing complex data structures.

  • Secure

microkv acts almost in the sense of a secure enclave with any stored information. First, inserted values are immediately encryped using authenticated encryption with XSalsa20 (stream cipher) and Poly1305 (HMAC) from sodiumoxide, guarenteeing security and integrity. Encryped values in-memory are also memory-locked with mlock, and securely zeroed when destroyed to avoid persistence in memory pages.

microkv also provides locking support with RwLocks, which utilize mutual exclusion like mutexes, but robust in the sense that concurrent read locks can be held, but only one writer lock can be held at a time. This helps remove thread-safety and data race concerns, but also enables multiple read accesses safely.

  • Small

At its core, microkv is implemented in ~500 LOCs, making the implementation portable and auditable. It remains faithfully opinionated, meaning it will not offer extensions to other serializable formats, or any other user-involved configurability, allowing it to work right out of the box.

Usage

To install locally, simply clone the repository and install with cargo:

# .. from crates.io
$ cargo install microkv

# .. or locally
$ git clone https://github.com/ex0dus-0x/microkv
$ cargo install --path .

Here's example usage of the microkv library crate:

use microkv::MicroKV;

#[derive(Serialize, Deserialize, Debug)]
struct Identity {
    uuid: u32,
    name: String,
    sensitive_data: String,
}


fn main() {
    let unsafe_pwd: String = "my_password_123";

    // initialize in-memory database with (unsafe) cleartext password
    let db: MicroKV = MicroKV::new("my_db")
        .with_pwd_clear(unsafe_pwd);

    // ... or backed by disk, with auto-commit per transaction
    let db: MicroKV = MicroKV::open_with_base_path("my_db_on_disk", SOME_PATH)
        .expect("Failed to create MicroKV from a stored file or create MicroKV for this file")
        .set_auto_commit(true)
        .with_pwd_clear(unsafe_pwd);

    // simple interaction to default namespace
    db.put("simple", 1);
    print("{}", db.get_unwrap("simple").unwrap());
    db.delete("simple");

    // more complex interaction to default namespace
    let identity = Identity {
        uuid: 123,
        name: String::from("Alice"),
        sensitive_data: String::from("something_important_here")
    };
    db.put("complex", identity);
    let stored_identity: Identity = db.get_unwrap("complex").unwrap();
    println!("{:?}", stored_identity);
    db.delete("complex");
}

microkv also supports transactions on other namespaces to support grouping and organizing keys (thanks @fewensa!):

    let namespace_one = db.namespace("one");
    namespace_one.put("zoo", &"big".to_string()).unwrap();

microkv also includes a simple command line application that is installed alongside the package. While not entirely useful at the moment, future plans are to be able to integrate it such that it can be exposed through a Docker container.

Contributions

Interested on improving the state of this project? Check out the issue tracker for what we need help on!

License

MIT license