From d65bf5d97a5ace2e1b0fd1ce6add242ed0b156c6 Mon Sep 17 00:00:00 2001 From: Hannes Date: Thu, 13 May 2021 17:46:45 +0200 Subject: [PATCH] Added a lot of Doc --- src/header.rs | 12 +++++- src/lib.rs | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ src/ratchet.rs | 4 ++ 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/src/header.rs b/src/header.rs index 28fdf43..46ad285 100644 --- a/src/header.rs +++ b/src/header.rs @@ -6,7 +6,7 @@ use serde::{Serialize, Deserialize}; #[cfg(test)] use crate::dh::gen_key_pair; -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct Header { pub public_key: PublicKey, pub pn: usize, // Previous Chain Length @@ -20,7 +20,9 @@ struct ExHeader { n: usize } +// Message Header impl Header { + #[doc(hidden)] pub fn new(dh_pair: &DhKeyPair, pn: usize, n: usize) -> Self { Header { public_key: dh_pair.public_key, @@ -28,7 +30,7 @@ impl Header { n, } } - + #[doc(hidden)] pub fn concat(&self) -> Vec { let ex_header = ExHeader{ public_key: self.public_key.to_bytes(), @@ -61,6 +63,12 @@ impl From<&[u8]> for Header { } } +impl Into> for Header { + fn into(self) -> Vec { + self.concat() + } +} + impl PartialEq for Header { fn eq(&self, other: &Self) -> bool { if self.public_key == other.public_key diff --git a/src/lib.rs b/src/lib.rs index 741fdd9..0739fec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,111 @@ +//! Implementation of the double ratchet system/encryption as specified by [Signal][1]. +//! +//! 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 (header, encrypted) = alice_ratchet.ratchet_encrypt(&data); // Encrypting message with Alice Ratchet (Alice always needs to send the first message) +//! let decrypted = bob_ratchet.ratchet_decrypt(&header, &encrypted); // 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 (header1, encrypted1) = alice_ratchet.ratchet_encrypt(&data); // Lost message +//! let (header2, encrypted2) = alice_ratchet.ratchet_encrypt(&data); // Successful message +//! +//! let decrypted2 = bob_ratchet.ratchet_decrypt(&header2, &encrypted2); // Decrypting second message first +//! let decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1); // 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 (mut bob_ratchet, _) = Ratchet::init_bob(sk); +//! let data = b"Hello World".to_vec(); +//! +//! let (_, _) = bob_ratchet.ratchet_encrypt(&data); +//! ``` +//! +//! ## 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 (header1, encrypted1) = alice_ratchet.ratchet_encrypt(&data); +//! let _decrypted1 = bob_ratchet.ratchet_decrypt(&header1, &encrypted1); +//! +//! let (header2, encrypted2) = bob_ratchet.ratchet_encrypt(&data); +//! let decrypted2 = alice_ratchet.ratchet_decrypt(&header2, &encrypted2); +//! +//! 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 (header, _) = alice_ratchet.ratchet_encrypt(&data); +//! let header_bytes: Vec = header.clone().into(); +//! let header_const = Header::from(header_bytes); +//! assert_eq!(header, header_const); +//! ``` +//! +//! # 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 +//! - [ ] [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 x25519_dalek::PublicKey; + mod aead; mod dh; mod kdf_root; @@ -13,3 +116,4 @@ pub mod ratchet; /// Message Header pub mod header; + diff --git a/src/ratchet.rs b/src/ratchet.rs index fb54f8d..c6226cd 100644 --- a/src/ratchet.rs +++ b/src/ratchet.rs @@ -23,6 +23,7 @@ pub struct Ratchet { } impl Ratchet { + /// Init Ratchet with other [PublicKey]. Initialized second. pub fn init_alice(sk: [u8; 32], bob_dh_public_key: PublicKey) -> Self { let dhs = DhKeyPair::new(); let (rk, cks) = kdf_rk(&sk, @@ -40,6 +41,7 @@ impl Ratchet { } } + /// Init Ratchet without other [PublicKey]. Initialized first. Returns [Ratchet] and [PublicKey]. pub fn init_bob(sk: [u8; 32]) -> (Self, PublicKey) { let dhs = DhKeyPair::new(); let public_key = dhs.public_key; @@ -57,6 +59,7 @@ impl Ratchet { (ratchet, public_key) } + /// Encrypt Plaintext with [Ratchet]. Returns Message [Header] and ciphertext. pub fn ratchet_encrypt(&mut self, plaintext: &[u8]) -> (Header, Vec) { let (cks, mk) = kdf_ck(&self.cks.unwrap()); self.cks = Some(cks); @@ -95,6 +98,7 @@ impl Ratchet { } } + /// Decrypt ciphertext with ratchet. Requires Header. Returns plaintext. pub fn ratchet_decrypt(&mut self, header: &Header, ciphertext: &[u8]) -> Vec { let plaintext = self.try_skipped_message_keys(header, ciphertext); match plaintext {