Added a lot of Doc
This commit is contained in:
parent
b094b12539
commit
d65bf5d97a
3 changed files with 118 additions and 2 deletions
|
@ -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
|
||||||
|
|
104
src/lib.rs
104
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<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;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue