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
//! Implementation of the double ratchet system/encryption as specified by [Signal][1].
//!
//! **WARNING! This implementation uses P-256 NOT Curve25519 as specified by Signal!**
//!
//! The implementation follows the cryptographic recommendations provided by [Signal][2].
//! The AEAD Algorithm uses a constant Nonce. This might be changed in the future.
//!
//! # Example Usage:
//!
//! ## Standard:
//! ```
//! use double_ratchet_2::ratchet::Ratchet;
//!
//! let sk = [1; 32];                                                 // Initial Key created by a symmetric key agreement protocol
//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk);        // Creating Bobs Ratchet (returns Bobs PublicKey)
//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key);      // Creating Alice Ratchet with Bobs 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.ratchet_encrypt(&data, ad);   // Encrypting message with Alice Ratchet (Alice always needs to send the first message)
//! let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, ad); // Decrypt message with Bobs Ratchet
//! assert_eq!(data, decrypted)
//! ```
//!
//! ## With lost message:
//! ```
//! # use double_ratchet_2::ratchet::Ratchet;
//!
//! let sk = [1; 32];                                                 // Initial Key created by a symmetric key agreement protocol
//! let (mut bob_ratchet, public_key) = Ratchet::init_bob(sk);        // Creating Bobs Ratchet (returns Bobs PublicKey)
//! let mut alice_ratchet = Ratchet::init_alice(sk, public_key);      // Creating Alice Ratchet with Bobs 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.ratchet_encrypt(&data, ad); // Lost message
//! let (header2, encrypted2, nonce2) = alice_ratchet.ratchet_encrypt(&data, ad); // Successful message
//!
//! let decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, ad); // Decrypting second message first
//! let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, ad); // Decrypting latter message
//!
//! let comp = decrypted1 == data && decrypted2 == data;
//! assert!(comp);
//! ```
//!
//! ## Encryption before recieving inital message
//!
//! ```should_panic
//! use double_ratchet_2::ratchet::Ratchet;
//! let sk = [1; 32];
//! let ad = b"Associated Data";
//! let (mut bob_ratchet, _) = Ratchet::init_bob(sk);
//! let data = b"Hello World".to_vec();
//!
//! let (_, _, _) = bob_ratchet.ratchet_encrypt(&data, ad);
//! ```
//!
//! ## Encryption after recieving initial message
//! However bob can (of course) also encrypt messages. This is possible, after decrypting the first message from alice.
//!
//! ```
//! use double_ratchet_2::ratchet::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.ratchet_encrypt(&data, ad);
//! let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1, &nonce1, ad);
//!
//! let (header2, encrypted2, nonce2) = bob_ratchet.ratchet_encrypt(&data, ad);
//! let decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2, &nonce2, ad);
//!
//! assert_eq!(data, decrypted2);
//! ```
//! ## Constructing and Deconstructing Headers
//!
//! ```
//! # use double_ratchet_2::ratchet::Ratchet;
//! # use double_ratchet_2::header::Header;
//! # 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.ratchet_encrypt(&data, ad);
//! let header_bytes: Vec<u8> = header.clone().into();
//! let header_const = Header::from(header_bytes);
//! assert_eq!(header, header_const);
//! ```
//!
//! # Example Ratchet with encrypted headers
//!
//! ```
//! use double_ratchet_2::ratchet::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.ratchet_encrypt(&data, ad);
//! let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted, &nonce, ad);
//! assert_eq!(data, decrypted)
//! ```
//!
//! # Export / Import Ratchet with encrypted headers
//! This ratchet implements import and export functionality. This works over a bincode backend and
//! maybe useful for saving Ratchets to and loading from a file.
//! ```
//! # use double_ratchet_2::ratchet::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);
//! assert_eq!(im_ratchet, bob_ratchet)
//! ```
//!
//! # Features
//!
//! Currently the crate only supports one feature: ring. If feature is enabled the crate switches
//! to ring-compat and uses ring as backend for Sha512 Hashing. May result in slightly better performance.
//!
//!
//! TODO:
//! - [x] Standard Double Ratchet
//! - [x] [Double Ratchet with encrypted headers][3]
//!
//! [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

#![no_std]
#![allow(stable_features)]

extern crate alloc;

pub use p256::PublicKey;

mod aead;
mod dh;
mod kdf_root;
mod kdf_chain;

pub mod ratchet;

/// Message Header
pub mod header;