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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
//! A pure Rust implementation of the Double Ratchet algorithm as described by [Signal][1].
//!
//! This implementation follows the cryptographic recommendations provided by [Signal][2].
//! The AEAD algorithm uses a constant Nonce. This might be changed in the future.
//!
//! Fork of [double-ratchet-2](https://github.com/Dione-Software/double-ratchet-2).
//!
//! ## Examples
//!
//! ### Standard Usage
//!
//! Alice encrypts a message which is then decrypted by Bob.
//!
//! ```
//! use double_ratchet_rs::Ratchet;
//!
//! let sk = [1; 32]; // Shared key created by a symmetric key agreement protocol
//!
//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bob's Ratchet (returns Bob's PublicKey)
//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice's Ratchet with Bob's PublicKey
//!
//! let data = b"Hello World".to_vec(); // Data to be encrypted
//! let ad = b"Associated Data"; // Associated data
//!
//! let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, ad); // Encrypting message with Alice's Ratchet (Alice always needs to send the first message)
//! let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, ad); // Decrypt message with Bob's Ratchet
//!
//! assert_eq!(data, decrypted)
//! ```
//!
//! ### Recovering a Lost Message
//!
//! Alice encrypts 2 messages for Bob.
//! The latest message must be decrypted first.
//!
//! ```
//! use double_ratchet_rs::Ratchet;
//!
//! let sk = [1; 32]; // Shared key created by a symmetric key agreement protocol
//!
//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk); // Creating Bob's Ratchet (returns Bob's PublicKey)
//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key); // Creating Alice's Ratchet with Bob's PublicKey
//!
//! let data = b"Hello World".to_vec(); // Data to be encrypted
//! let ad = b"Associated Data"; // Associated data
//!
//! let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, ad); // Lost message
//! let (header2, encrypted2, nonce2) = alice_ratchet.encrypt(&data, ad); // Successful message
//!
//! let decrypted2 = bob_ratchet.decrypt(&header2, &encrypted2, &nonce2, ad); // Decrypting second message first
//! let decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, ad); // Decrypting latter message
//!
//! assert_eq!(data, decrypted1);
//! assert_eq!(data, decrypted2);
//! ```
//!
//! ### Encryption Before Decrypting First Message
//!
//! Bob encrypts a message before decrypting one from Alice.
//! This will result in a panic.
//!
//! ```should_panic
//! use double_ratchet_rs::Ratchet;
//!
//! let sk = [1; 32];
//!
//! let (mut bob_ratchet, _) = Ratchet::init_bob(sk);
//!
//! let data = b"Hello World".to_vec();
//! let ad = b"Associated Data";
//!
//! let (_, _, _) = bob_ratchet.encrypt(&data, ad);
//! ```
//!
//! ### Encryption After Decrypting First Message
//!
//! Bob *can* also encrypt messages.
//! This is only possible after decrypting one from Alice first though.
//!
//! ```
//! use double_ratchet_rs::Ratchet;
//!
//! let sk = [1; 32];
//!
//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk);
//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key);
//!
//! let data = b"Hello World".to_vec();
//! let ad = b"Associated Data";
//!
//! let (header1, encrypted1, nonce1) = alice_ratchet.encrypt(&data, ad);
//! let _decrypted1 = bob_ratchet.decrypt(&header1, &encrypted1, &nonce1, ad);
//!
//! let (header2, encrypted2, nonce2) = bob_ratchet.encrypt(&data, ad);
//! let decrypted2 = alice_ratchet.decrypt(&header2, &encrypted2, &nonce2, ad);
//!
//! assert_eq!(data, decrypted2);
//! ```
//!
//! ### Constructing and Deconstructing Headers
//!
//! ```
//! use double_ratchet_rs::{Header, Ratchet};
//!
//! let sk = [1; 32];
//!
//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk);
//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key);
//!
//! let data = b"hello World".to_vec();
//! let ad = b"Associated Data";
//!
//! let (header, _, _) = alice_ratchet.encrypt(&data, ad);
//! let header_bytes: Vec<u8> = header.clone().into();
//! let header_const = Header::from(header_bytes);
//!
//! assert_eq!(header, header_const);
//! ```
//!
//! ### Encrypted Headers
//!
//! ```
//! use double_ratchet_rs::RatchetEncHeader;
//!
//! let sk = [0; 32];
//! let shared_hka = [1; 32];
//! let shared_nhkb = [2; 32];
//!
//! let (mut bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb);
//! let mut alice_ratchet = RatchetEncHeader::init_alice(sk, public_key, shared_hka, shared_nhkb);
//!
//! let data = b"Hello World".to_vec();
//! let ad = b"Associated Data";
//!
//! let (header, encrypted, nonce) = alice_ratchet.encrypt(&data, ad);
//! let decrypted = bob_ratchet.decrypt(&header, &encrypted, &nonce, ad);
//!
//! assert_eq!(data, decrypted)
//! ```
//!
//! ### Exporting / Importing Ratchet w/ Encrypted Headers
//!
//! This can be used for storing and using ratchets in a file.
//!
//! ```
//! use double_ratchet_rs::RatchetEncHeader;
//!
//! let sk = [0; 32];
//! let shared_hka = [1; 32];
//! let shared_nhkb = [2; 32];
//!
//! let (bob_ratchet, public_key) = RatchetEncHeader::init_bob(sk, shared_hka, shared_nhkb);
//! let ex_ratchet = bob_ratchet.export();
//! let im_ratchet = RatchetEncHeader::import(&ex_ratchet).unwrap();
//!
//! assert_eq!(im_ratchet, bob_ratchet)
//! ```
//!
//! ## Features
//!
//! - `hashbrown`: Use `hashbrown` for `HashMap`. Enabled by default for `no_std` support.
//! - `std`: Use `std` instead of `alloc`. Can be used with `hashbrown`, but it isn't required.
//!
//! ## **M**inimum **S**upported **R**ust **V**ersion (MSRV)
//!
//! The current MSRV is 1.60.0 without `hashbrown` and 1.64.0 with `hashbrown`.
//!
//! ## License
//!
//! This project is licensed under the [MIT license](https://github.com/notsatvrn/double-ratchet-rs/blob/main/LICENSE).
//!
//! [1]: https://signal.org/docs/specifications/doubleratchet/
//! [2]: https://signal.org/docs/specifications/doubleratchet/#recommended-cryptographic-algorithms
//! [3]: https://signal.org/docs/specifications/doubleratchet/#double-ratchet-with-header-encryption
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(stable_features)]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;
pub use x25519_dalek::PublicKey;
mod aead;
mod dh;
mod header;
mod kdf_chain;
mod kdf_root;
mod ratchet;
pub use dh::*;
pub use header::*;
pub use ratchet::*;