Added a lot of Doc

This commit is contained in:
Hannes 2021-05-13 17:46:45 +02:00
parent b094b12539
commit d65bf5d97a
3 changed files with 118 additions and 2 deletions

View file

@ -6,7 +6,7 @@ use serde::{Serialize, Deserialize};
#[cfg(test)] #[cfg(test)]
use crate::dh::gen_key_pair; use crate::dh::gen_key_pair;
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub struct Header { pub struct Header {
pub public_key: PublicKey, pub public_key: PublicKey,
pub pn: usize, // Previous Chain Length pub pn: usize, // Previous Chain Length
@ -20,7 +20,9 @@ struct ExHeader {
n: usize n: usize
} }
// Message Header
impl Header { impl Header {
#[doc(hidden)]
pub fn new(dh_pair: &DhKeyPair, pn: usize, n: usize) -> Self { pub fn new(dh_pair: &DhKeyPair, pn: usize, n: usize) -> Self {
Header { Header {
public_key: dh_pair.public_key, public_key: dh_pair.public_key,
@ -28,7 +30,7 @@ impl Header {
n, n,
} }
} }
#[doc(hidden)]
pub fn concat(&self) -> Vec<u8> { pub fn concat(&self) -> Vec<u8> {
let ex_header = ExHeader{ let ex_header = ExHeader{
public_key: self.public_key.to_bytes(), public_key: self.public_key.to_bytes(),
@ -61,6 +63,12 @@ impl From<&[u8]> for Header {
} }
} }
impl Into<Vec<u8>> for Header {
fn into(self) -> Vec<u8> {
self.concat()
}
}
impl PartialEq for Header { impl PartialEq for Header {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if self.public_key == other.public_key if self.public_key == other.public_key

View file

@ -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<u8> = 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] #![no_std]
#![allow(stable_features)] #![allow(stable_features)]
extern crate alloc; extern crate alloc;
pub use x25519_dalek::PublicKey;
mod aead; mod aead;
mod dh; mod dh;
mod kdf_root; mod kdf_root;
@ -13,3 +116,4 @@ pub mod ratchet;
/// Message Header /// Message Header
pub mod header; pub mod header;

View file

@ -23,6 +23,7 @@ pub struct Ratchet {
} }
impl Ratchet { impl Ratchet {
/// Init Ratchet with other [PublicKey]. Initialized second.
pub fn init_alice(sk: [u8; 32], bob_dh_public_key: PublicKey) -> Self { pub fn init_alice(sk: [u8; 32], bob_dh_public_key: PublicKey) -> Self {
let dhs = DhKeyPair::new(); let dhs = DhKeyPair::new();
let (rk, cks) = kdf_rk(&sk, 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) { pub fn init_bob(sk: [u8; 32]) -> (Self, PublicKey) {
let dhs = DhKeyPair::new(); let dhs = DhKeyPair::new();
let public_key = dhs.public_key; let public_key = dhs.public_key;
@ -57,6 +59,7 @@ impl Ratchet {
(ratchet, public_key) (ratchet, public_key)
} }
/// Encrypt Plaintext with [Ratchet]. Returns Message [Header] and ciphertext.
pub fn ratchet_encrypt(&mut self, plaintext: &[u8]) -> (Header, Vec<u8>) { pub fn ratchet_encrypt(&mut self, plaintext: &[u8]) -> (Header, Vec<u8>) {
let (cks, mk) = kdf_ck(&self.cks.unwrap()); let (cks, mk) = kdf_ck(&self.cks.unwrap());
self.cks = Some(cks); 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<u8> { pub fn ratchet_decrypt(&mut self, header: &Header, ciphertext: &[u8]) -> Vec<u8> {
let plaintext = self.try_skipped_message_keys(header, ciphertext); let plaintext = self.try_skipped_message_keys(header, ciphertext);
match plaintext { match plaintext {