add std support, wording changes, code improvements

This commit is contained in:
satvrn 2023-07-19 21:50:47 +00:00
parent 45916848ad
commit 2b559b79f9
7 changed files with 65 additions and 36 deletions

View file

@ -1,12 +1,12 @@
[package]
name = "double-ratchet-rs"
authors = ["satvrn", "Hannes Furmans"]
description = "A pure Rust implementation of the Double Ratchet Algorithm as specified by Signal."
description = "A pure Rust implementation of the Double Ratchet algorithm as described by Signal."
homepage = "https://github.com/notsatvrn/double-ratchet-rs"
repository = "https://github.com/notsatvrn/double-ratchet-rs"
readme = "README.md"
keywords = ["double-ratchet", "crypto", "cryptography", "signal"]
version = "0.4.5"
version = "0.4.6"
edition = "2021"
license = "MIT"
@ -19,7 +19,7 @@ aes-gcm-siv = "0.11"
sha2 = {version = "0.10", default-features = false}
serde = {version = "1.0", default-features = false, features = ["derive"]}
postcard = {version = "1.0", default-features = false, features = ["alloc"]}
hashbrown = {version = "0.14", features = ["serde"]}
hashbrown = {version = "0.14", features = ["serde"], optional = true}
zeroize = {version = "1.6", default-features = false, features = ["zeroize_derive"]}
[dev-dependencies]
@ -31,3 +31,7 @@ harness = false
[profile.release]
lto = true
[features]
default = ["hashbrown"]
std = ["sha2/std", "serde/std", "postcard/use-std", "zeroize/std"]

View file

@ -5,10 +5,10 @@
# double-ratchet-rs
A pure Rust implementation of the Double Ratchet Algorithm as specified by [Signal][1].
A pure Rust implementation of the Double Ratchet algorithm as described by [Signal][1].
This implementation follows the cryptographic recommendations provided by [Signal][2].
The AEAD Algorithm uses a constant Nonce. This might be changed in the future.
The AEAD algorithm uses a constant Nonce. This might be changed in the future.
Fork of [double-ratchet-2](https://github.com/Dione-Software/double-ratchet-2).
@ -163,9 +163,14 @@ let im_ratchet = RatchetEncHeader::import(&ex_ratchet).unwrap();
assert_eq!(im_ratchet, bob_ratchet)
```
## Features
- `hashbrown`: Use `hashbrown` for `HashMap`. Enabled by default for `no_std` support.
- `std`: Use `std` instead of `alloc`. Can be used with `hashbrown`, but it isn't required.
## **M**inimum **S**upported **R**ust **V**ersion (MSRV)
The current MSRV is 1.61.0.
The current MSRV is 1.60.0 without `hashbrown` and 1.64.0 with `hashbrown`.
## License
@ -174,4 +179,3 @@ This project is licensed under the [MIT license](https://github.com/notsatvrn/do
[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

View file

@ -1,13 +1,15 @@
use aes_gcm_siv::aead::AeadInPlace;
use aes_gcm_siv::{Aes256GcmSiv, KeyInit, Nonce};
use alloc::vec::Vec;
use rand_core::{OsRng, RngCore};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
pub fn encrypt(mk: &[u8; 32], data: &[u8], associated_data: &[u8]) -> (Vec<u8>, [u8; 12]) {
let cipher = Aes256GcmSiv::new_from_slice(mk).expect("Encryption failure {}");
let mut nonce_data = [0u8; 12];
OsRng::fill_bytes(&mut OsRng, &mut nonce_data);
OsRng.fill_bytes(&mut nonce_data);
let nonce = Nonce::from_slice(&nonce_data);
let mut buffer = Vec::new();

View file

@ -24,7 +24,7 @@ impl PartialEq for DhKeyPair {
impl Debug for DhKeyPair {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("DhKeyPair")
.field("private_key", &self.private_key.to_bytes())
.field("private_key", self.private_key.as_bytes())
.field("public_key", self.public_key.as_bytes())
.finish()
}
@ -38,7 +38,7 @@ impl Default for DhKeyPair {
impl DhKeyPair {
pub fn new() -> Self {
let secret = StaticSecret::random_from_rng(&mut OsRng);
let secret = StaticSecret::random_from_rng(OsRng);
let public = PublicKey::from(&secret);
DhKeyPair {
private_key: secret,
@ -58,11 +58,6 @@ pub fn gen_shared_secret() -> SharedSecret {
alice_pair.key_agreement(&bob_pair.public_key)
}
#[cfg(test)]
pub fn gen_key_pair() -> DhKeyPair {
DhKeyPair::new()
}
#[cfg(test)]
mod tests {
use crate::dh::DhKeyPair;

View file

@ -4,14 +4,13 @@ use crate::aead::encrypt;
use crate::dh::DhKeyPair;
use aes_gcm_siv::aead::AeadInPlace;
use aes_gcm_siv::{Aes256GcmSiv, KeyInit, Nonce};
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
use x25519_dalek::PublicKey;
#[cfg(test)]
use crate::dh::gen_key_pair;
use zeroize::Zeroize;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Serialize, Deserialize, Debug, Zeroize, Clone, PartialEq, Eq)]
#[zeroize(drop)]
pub struct Header {
@ -93,7 +92,7 @@ impl EncryptedHeader {
#[cfg(test)]
pub fn gen_header() -> Header {
let dh_pair = gen_key_pair();
let dh_pair = DhKeyPair::new();
let pn = 10;
let n = 50;
Header::new(&dh_pair, pn, n)

View file

@ -1,7 +1,7 @@
//! A pure Rust implementation of the Double Ratchet Algorithm as specified by [Signal][1].
//! A pure Rust implementation of the Double Ratchet algorithm as described by [Signal][1].
//!
//! This implementation follows the cryptographic recommendations provided by [Signal][2].
//! The AEAD Algorithm uses a constant Nonce. This might be changed in the future.
//! The AEAD algorithm uses a constant Nonce. This might be changed in the future.
//!
//! Fork of [double-ratchet-2](https://github.com/Dione-Software/double-ratchet-2).
//!
@ -156,9 +156,14 @@
//! assert_eq!(im_ratchet, bob_ratchet)
//! ```
//!
//! ## Features
//!
//! - `hashbrown`: Use `hashbrown` for `HashMap`. Enabled by default for `no_std` support.
//! - `std`: Use `std` instead of `alloc`. Can be used with `hashbrown`, but it isn't required.
//!
//! ## **M**inimum **S**upported **R**ust **V**ersion (MSRV)
//!
//! The current MSRV is 1.61.0.
//! The current MSRV is 1.60.0 without `hashbrown` and 1.64.0 with `hashbrown`.
//!
//! ## License
//!
@ -168,19 +173,24 @@
//! [2]: https://signal.org/docs/specifications/doubleratchet/#recommended-cryptographic-algorithms
//! [3]: https://signal.org/docs/specifications/doubleratchet/#double-ratchet-with-header-encryption
#![no_std]
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(stable_features)]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;
pub use x25519_dalek::PublicKey;
mod aead;
mod dh;
mod header;
mod kdf_chain;
mod kdf_root;
mod ratchet;
mod header;
pub use ratchet::*;
pub use dh::*;
pub use header::*;
pub use ratchet::*;

View file

@ -2,15 +2,20 @@
use crate::aead::{decrypt, encrypt};
use crate::dh::DhKeyPair;
use crate::header::{Header, EncryptedHeader};
use crate::header::{EncryptedHeader, Header};
use crate::kdf_chain::kdf_ck;
use crate::kdf_root::{kdf_rk, kdf_rk_he};
use alloc::vec::Vec;
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use x25519_dalek::PublicKey;
use zeroize::Zeroize;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[cfg(any(not(feature = "std"), feature = "hashbrown"))]
use hashbrown::HashMap;
#[cfg(all(feature = "std", not(feature = "hashbrown")))]
use std::collections::HashMap;
const MAX_SKIP: usize = 100;
/// A standard ratchet.
@ -115,7 +120,12 @@ impl Ratchet {
self.mkskipped
.remove(&(header.public_key.to_bytes(), header.n))
.unwrap();
Some(decrypt(&mk, enc_data, &header.concat(associated_data), nonce))
Some(decrypt(
&mk,
enc_data,
&header.concat(associated_data),
nonce,
))
} else {
None
}
@ -156,7 +166,7 @@ impl Ratchet {
Some(d) => d,
None => {
if Some(header.public_key) != self.dhr {
if self.ckr != None {
if self.ckr.is_some() {
self.skip_message_keys(header.pn).unwrap();
}
self.dhratchet(header);
@ -298,7 +308,11 @@ impl RatchetEncHeader {
/// Encrypt bytes with a [RatchetEncHeader].
/// Requires bytes and associated bytes.
/// Returns an [EncryptedHeader], encrypted bytes, and a nonce.
pub fn encrypt(&mut self, data: &[u8], associated_data: &[u8]) -> (EncryptedHeader, Vec<u8>, [u8; 12]) {
pub fn encrypt(
&mut self,
data: &[u8],
associated_data: &[u8],
) -> (EncryptedHeader, Vec<u8>, [u8; 12]) {
let (cks, mk) = kdf_ck(&self.cks.unwrap());
self.cks = Some(cks);
let header = Header::new(&self.dhs, self.pn, self.ns);
@ -425,7 +439,8 @@ impl RatchetEncHeader {
nonce: &[u8; 12],
associated_data: &[u8],
) -> (Vec<u8>, Header) {
let (data, header) = self.try_skipped_message_keys(enc_header, enc_data, nonce, associated_data);
let (data, header) =
self.try_skipped_message_keys(enc_header, enc_data, nonce, associated_data);
if let Some(d) = data {
return (d, header.unwrap());
};