1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
// Copyright 2021 The Matrix.org Foundation C.I.C.
// Copyright 2021 Damir Jelić, Denis Kasak
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! An implementation of the Olm double ratchet.
//!
//! ## Overview
//!
//! The core component of the crate is the [`Account`], representing a single
//! Olm participant. An Olm [`Account`] consists of a collection of key pairs,
//! though often documentation will shorten this to just "keys". These are:
//!
//! 1. An Ed25519 *signing key pair* representing the stable cryptographic
//! identity of the participant (the participant's "fingerprint").
//! 2. A Curve25519 *sender key pair* (also sometimes called the *identity key
//! pair*, somewhat confusingly).
//! 3. A number of one-time key pairs.
//! 4. A current and previous (if any) "fallback" key pair.
//!
//! While the key in 1 is used for signing but not encryption, the keys in 2-4
//! participate in a triple Diffie-Hellman key exchange (3DH) with another Olm
//! participant, thereby establishing an Olm session on each side of the
//! communication channel. Ultimately, this session is used for deriving the
//! concrete encryption keys for a particular message.
//!
//! Olm sessions are represented by the [`Session`] struct. Such a session is
//! created by calling [`Account::create_outbound_session`] on one of the
//! participating accounts, passing it the Curve25519 sender key and one
//! Curve25519 one-time key of the other side. The protocol is asynchronous, so
//! the participant can start sending messages to the other side even before the
//! other side has created a session, producing so-called pre-key messages (see
//! [`PreKeyMessage`]).
//!
//! Once the other participant receives such a pre-key message, they can create
//! their own matching session by calling [`Account::create_inbound_session`]
//! and passing it the pre-key message they received and the Curve25519 sender
//! key of the other side. This completes the establishment of the Olm
//! communication channel.
//!
//! ```
//! use anyhow::Result;
//! use vodozemac::olm::{Account, InboundCreationResult, OlmMessage, SessionConfig};
//!
//! fn main() -> Result<()> {
//! let alice = Account::new();
//! let mut bob = Account::new();
//!
//! bob.generate_one_time_keys(1);
//! let bob_otk = *bob.one_time_keys().values().next().unwrap();
//!
//! let mut alice_session = alice
//! .create_outbound_session(SessionConfig::version_2(), bob.curve25519_key(), bob_otk);
//!
//! bob.mark_keys_as_published();
//!
//! let message = "Keep it between us, OK?";
//! let alice_msg = alice_session.encrypt(message);
//!
//! if let OlmMessage::PreKey(m) = alice_msg.clone() {
//! let result = bob.create_inbound_session(alice.curve25519_key(), &m)?;
//!
//! let mut bob_session = result.session;
//! let what_bob_received = result.plaintext;
//!
//! assert_eq!(alice_session.session_id(), bob_session.session_id());
//!
//! assert_eq!(message.as_bytes(), what_bob_received);
//!
//! let bob_reply = "Yes. Take this, it's dangerous out there!";
//! let bob_encrypted_reply = bob_session.encrypt(bob_reply).into();
//!
//! let what_alice_received = alice_session
//! .decrypt(&bob_encrypted_reply)?;
//! assert_eq!(what_alice_received, bob_reply.as_bytes());
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ## Sending messages
//!
//! To encrypt a message, just call [`Session::encrypt()`]. This will
//! either produce an [`OlmMessage::PreKey`] or [`OlmMessage::Normal`]
//! depending on whether the session is fully established. A session is fully
//! established once you receive (and decrypt) at least one message from the
//! other side.
mod account;
mod messages;
pub(crate) mod session;
mod session_config;
mod session_keys;
mod shared_secret;
pub use account::{
Account, AccountPickle, IdentityKeys, InboundCreationResult, OneTimeKeyGenerationResult,
SessionCreationError,
};
pub use messages::{Message, MessageType, OlmMessage, PreKeyMessage};
pub use session::{ratchet::RatchetPublicKey, DecryptionError, Session, SessionPickle};
pub use session_config::SessionConfig;
pub use session_keys::SessionKeys;