Expand description

A Rust implementation of Olm and Megolm

vodozemac is a Rust reimplementation of libolm, a cryptographic library used for end-to-end encryption in Matrix. At its core, it is an implementation of the Olm and Megolm cryptographic ratchets, along with a high-level API to easily establish cryptographic communication channels employing those ratchets with other parties. It also implements some other miscellaneous cryptographic functionality which is useful for building Matrix clients, such as SAS.

Olm

Olm is an implementation of the Double Ratchet algorithm, very similar to that employed by the Signal Protocol. It allows the establishment of a 1-to-1 private communication channel, with perfect forward secrecy and self-healing properties.

A detailed technical specification can be found at https://gitlab.matrix.org/matrix-org/olm/-/blob/master/docs/olm.md.

For more information on using vodozemac for Olm, see the olm module.

Megolm

Megolm is an AES-based single ratchet for group conversations with a large number of participants, where using Olm would be cost prohibitive because it would imply encrypting each message individually for each participant. Megolm sidesteps this by encrypting messages with a symmetric ratchet, shared once with each participant and then reused for a sequence of messages before rotating.

This is a trade-off in which we lose Olm’s self-healing properties, because someone in possession of a Megolm session at a particular state can derive all future states. However, if the attacker is only able to obtain the session in a ratcheted state, they cannot use it to decrypt messages encrypted with an earlier state. This preserves forward secrecy.

A detailed technical specification can be found at https://gitlab.matrix.org/matrix-org/olm/-/blob/master/docs/megolm.md.

For more information on using vodozemac for Megolm, see the megolm module.

Features

Supported

Unsupported

Planned

Feature flags

Low-level API

Feature: low-level-api (default: off)

Vodozemac exposes some lower-level structs and functions that are only useful in very advanced use cases. These should not be needed by the vast majority of users.

Extreme care must be taken when using such APIs, as incorrect usage can lead to broken sessions.

Pickling

vodozemac supports serializing its entire internal state into a form a “pickle”. The state can subsequently be restored from such a pickle (“unpickled”) in order to continue operation. This is used to support some Matrix features like device dehydration.

Legacy pickles

The legacy pickle format is a simple binary format used by libolm. Implemented for interoperability with current clients which are using libolm. Only unpickling is supported.

Modern pickles

The crate also implements a modern pickling mechanism using Serde. The exact serialization format is not mandated nor specified by this crate, but you can serialize to and deserialize from any format supported by Serde.

The following structs support pickling:

For example, the following will print out the JSON representing the serialized Account and will leave no new copies of the account’s secrets in memory:

use anyhow::Result;
use vodozemac::olm::{Account, AccountPickle};

const PICKLE_KEY: [u8; 32] = [0u8; 32];

fn main() -> Result<()>{
    let mut account = Account::new();

    account.generate_one_time_keys(10);
    account.generate_fallback_key();

    let pickle = account.pickle().encrypt(&PICKLE_KEY);

    let account2: Account = AccountPickle::from_encrypted(&pickle, &PICKLE_KEY)?.into();

    assert_eq!(account.identity_keys(), account2.identity_keys());

    Ok(())
}

You can unpickle a pickle-able struct directly from its serialized form:

    let mut json_str = serde_json::to_string(&some_account.pickle())?;
    // This will produce an account which is identical to `some_account`.
    let account: Account = serde_json::from_str::<AccountPickle>(&json_str)?.into();

    json_str.zeroize();

However, the pickle-able structs do not implement serde::Serialize themselves. If you want to serialize to a format other than JSON, you should instead call the .pickle() method to obtain a special serializable struct. This struct does implement Serialize and can therefore be serialized into any format supported by serde. To get back to the original struct from such as serializeable struct, just call .unpickle().

use anyhow::Result;
use vodozemac::olm::Account;

fn main() -> Result<()> {
    let account = Account::new();
    let account: Account = account.pickle().into();  // this is identity

    Ok(())
}

Modules

An implementation of the Megolm ratchet.

An implementation of the Olm double ratchet.

User-friendly key verification using short authentication strings (SAS).

Structs

Struct representing a Curve25519 public key.

A struct collecting both a public, and a secret, Ed25519 key.

An Ed25519 public key, used to verify digital signatures.

An Ed25519 secret key, used to create digital signatures.

An Ed25519 digital signature, can be used to verify the authenticity of a message.

A Protobuf message decoding error.

Enums

Errors that can occur while decoding.

Error type describing the different ways message decoding can fail.

Error type describing failures that can happen when we try decode or use a cryptographic key.

Error type describing the various ways libolm pickles can fail to be decoded.

Error type describing the various ways Vodozemac pickles can fail to be decoded.

Error type describing signature verification failures.