A general purpose encryption scheme for key/value stores.

# Usage

```rust
use matrix_sdk_store_encryption::StoreCipher;
use serde_json::{json, value::Value};

fn main() -> anyhow::Result<()> {
    let store_cipher = StoreCipher::new()?;

    // 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_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_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);
    assert_eq!(another_table, same_key);

    Ok(())
}
```

## Security warning: hazmat! ⚠️

This crate only implements the low-level block cipher function, to be used
_only_ as a building block for higher-level constructions. It is NOT intended
for direct use in applications.

USE AT YOUR OWN RISK!

## Encryption scheme

The central component of the encryption scheme is the `StoreCipher` type, used
for both obfuscating keys and encrypting values of the key/value store.
A `StoreCipher` object consists of two randomly-generated 32 byte secrets.

The first secret is used to encrypt values. XChaCha20Poly1305 with a random
nonce is used to encrypt each value. The nonce is saved with the ciphertext.

The second secret is used as a seed to derive table-specific keys, used to key
a keyed hash construction, which is in turn used to hash table data. Currently
we use blake3 as the keyed hash construction.

```text
                ┌───────────────────────────────────────┐
                │             StoreCipher               │
                │   Encryption key |    Hash key seed   │
                │      [u8; 32]    |       [u8; 32]     │
                └───────────────────────────────────────┘
```

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 `StoreCipher` is periodically rotated/rekeyed.

## WASM support

This crate relies on the `random` and `getrandom` crates which don't support
WASM automatically.

Either turn the `js` feature on directly on this crate or depend on `getrandom`
with the `js` feature turned on. More info can be found in the
[`getrandom` docs](https://docs.rs/getrandom/latest/getrandom/index.html#webassembly-support).
