| benches | ||
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
double-ratchet-rs
A pure Rust implementation of the Double Ratchet algorithm as described by Signal.
This implementation follows the cryptographic recommendations provided by Signal. The AEAD algorithm uses a constant Nonce. This might be changed in the future.
Temporary fork of double-ratchet-rs, which is published on crates.io. Use this one instead because my fork is published for a proof of concept only, not meant to stay forever.
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.
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: UsehashbrownforHashMap. Enabled by default forno_stdsupport.std: Usestdinstead ofalloc. Can be used withhashbrown, but it isn't required.
Minimum Supported Rust Version (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.