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::*;