add std
support, wording changes, code improvements
This commit is contained in:
parent
45916848ad
commit
2b559b79f9
7 changed files with 65 additions and 36 deletions
10
Cargo.toml
10
Cargo.toml
|
@ -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"]
|
||||
|
|
12
README.md
12
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
22
src/lib.rs
22
src/lib.rs
|
@ -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::*;
|
||||
|
|
|
@ -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());
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue