diff --git a/Cargo.toml b/Cargo.toml index c939129..9bf207f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "rosenpass", + "rosenpass-ciphers", "rosenpass-util", "rosenpass-constant-time", "rosenpass-sodium", diff --git a/rosenpass-ciphers/src/lib.rs b/rosenpass-ciphers/src/lib.rs index f9e6e00..14fe2ac 100644 --- a/rosenpass-ciphers/src/lib.rs +++ b/rosenpass-ciphers/src/lib.rs @@ -3,3 +3,9 @@ pub mod aead { decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN, }; } + +pub mod xaead { + pub use rosenpass_sodium::aead::xchacha20poly1305_ietf::{ + decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN, + }; +} diff --git a/rosenpass-sodium/src/aead/mod.rs b/rosenpass-sodium/src/aead/mod.rs index c4e2b4e..0f10c84 100644 --- a/rosenpass-sodium/src/aead/mod.rs +++ b/rosenpass-sodium/src/aead/mod.rs @@ -1 +1,2 @@ pub mod chacha20poly1305_ietf; +pub mod xchacha20poly1305_ietf; diff --git a/rosenpass-sodium/src/aead/xchacha20poly1305_ietf.rs b/rosenpass-sodium/src/aead/xchacha20poly1305_ietf.rs new file mode 100644 index 0000000..a5d86c2 --- /dev/null +++ b/rosenpass-sodium/src/aead/xchacha20poly1305_ietf.rs @@ -0,0 +1,63 @@ +use libsodium_sys as libsodium; +use std::ffi::c_ulonglong; +use std::ptr::{null, null_mut}; + +pub const KEY_LEN: usize = libsodium::crypto_aead_xchacha20poly1305_IETF_KEYBYTES as usize; +pub const TAG_LEN: usize = libsodium::crypto_aead_xchacha20poly1305_ietf_ABYTES as usize; +pub const NONCE_LEN: usize = libsodium::crypto_aead_xchacha20poly1305_IETF_NPUBBYTES as usize; + +#[inline] +pub fn encrypt( + ciphertext: &mut [u8], + key: &[u8], + nonce: &[u8], + ad: &[u8], + plaintext: &[u8], +) -> anyhow::Result<()> { + assert!(ciphertext.len() == plaintext.len() + NONCE_LEN + TAG_LEN); + assert!(key.len() == libsodium::crypto_aead_xchacha20poly1305_IETF_KEYBYTES as usize); + let (n, ct) = ciphertext.split_at_mut(NONCE_LEN); + n.copy_from_slice(nonce); + let mut clen: u64 = 0; + sodium_call!( + crypto_aead_xchacha20poly1305_ietf_encrypt, + ct.as_mut_ptr(), + &mut clen, + plaintext.as_ptr(), + plaintext.len() as c_ulonglong, + ad.as_ptr(), + ad.len() as c_ulonglong, + null(), // nsec is not used + nonce.as_ptr(), + key.as_ptr() + )?; + assert!(clen as usize == ct.len()); + Ok(()) +} + +#[inline] +pub fn decrypt( + plaintext: &mut [u8], + key: &[u8], + ad: &[u8], + ciphertext: &[u8], +) -> anyhow::Result<()> { + assert!(ciphertext.len() == plaintext.len() + NONCE_LEN + TAG_LEN); + assert!(key.len() == KEY_LEN); + let (n, ct) = ciphertext.split_at(NONCE_LEN); + let mut mlen: u64 = 0; + sodium_call!( + crypto_aead_xchacha20poly1305_ietf_decrypt, + plaintext.as_mut_ptr(), + &mut mlen as *mut c_ulonglong, + null_mut(), // nsec is not used + ct.as_ptr(), + ct.len() as c_ulonglong, + ad.as_ptr(), + ad.len() as c_ulonglong, + n.as_ptr(), + key.as_ptr() + )?; + assert!(mlen as usize == plaintext.len()); + Ok(()) +} diff --git a/rosenpass/src/msgs.rs b/rosenpass/src/msgs.rs index 61f478d..b77af50 100644 --- a/rosenpass/src/msgs.rs +++ b/rosenpass/src/msgs.rs @@ -45,7 +45,7 @@ use super::RosenpassError; use crate::{pqkem::*, sodium}; -use rosenpass_ciphers::aead; +use rosenpass_ciphers::{aead, xaead}; // Macro magic //////////////////////////////////////////////////////////////// @@ -385,7 +385,7 @@ impl TryFrom for MsgType { pub const BISCUIT_PT_LEN: usize = Biscuit::<()>::LEN; /// Length in bytes of an encrypted Biscuit (cipher text) -pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + sodium::XAEAD_NONCE_LEN + sodium::XAEAD_TAG_LEN; +pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN; #[cfg(test)] mod test_constants { @@ -393,6 +393,7 @@ mod test_constants { msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN}, sodium, }; + use rosenpass_ciphers::xaead; #[test] fn sodium_keysize() { @@ -408,7 +409,7 @@ mod test_constants { fn biscuit_ct_len() { assert_eq!( BISCUIT_CT_LEN, - BISCUIT_PT_LEN + sodium::XAEAD_NONCE_LEN + sodium::XAEAD_TAG_LEN + BISCUIT_PT_LEN + xaead::NONCE_LEN + xaead::TAG_LEN ); } } diff --git a/rosenpass/src/protocol.rs b/rosenpass/src/protocol.rs index 6272741..a68c3ed 100644 --- a/rosenpass/src/protocol.rs +++ b/rosenpass/src/protocol.rs @@ -76,7 +76,7 @@ use crate::{ sodium::*, }; use anyhow::{bail, ensure, Context, Result}; -use rosenpass_ciphers::aead; +use rosenpass_ciphers::{aead, xaead}; use rosenpass_util::{cat, mem::cpy_min, ord::max_usize, time::Timebase}; use std::collections::hash_map::{ Entry::{Occupied, Vacant}, @@ -152,7 +152,7 @@ pub type PeerId = Public; pub type SessionId = Public; pub type BiscuitId = Public; -pub type XAEADNonce = Public; +pub type XAEADNonce = Public<{ xaead::NONCE_LEN }>; pub type MsgBuf = Public; @@ -1309,7 +1309,7 @@ impl HandshakeState { let k = bk.get(srv).key.secret(); let pt = biscuit.all_bytes(); - xaead_enc_into(biscuit_ct, k, &*n, &ad, pt)?; + xaead::encrypt(biscuit_ct, k, &*n, &ad, pt)?; self.mix(biscuit_ct) } @@ -1335,7 +1335,7 @@ impl HandshakeState { // Allocate and decrypt the biscuit data let mut biscuit = Secret::::zero(); // pt buf let mut biscuit = (&mut biscuit.secret_mut()[..]).biscuit()?; // slice - xaead_dec_into( + xaead::decrypt( biscuit.all_bytes_mut(), bk.get(srv).key.secret(), &ad, diff --git a/rosenpass/src/sodium.rs b/rosenpass/src/sodium.rs index b0945c5..48e8fb9 100644 --- a/rosenpass/src/sodium.rs +++ b/rosenpass/src/sodium.rs @@ -6,10 +6,8 @@ use rosenpass_constant_time::xor_into; use rosenpass_util::attempt; use static_assertions::const_assert_eq; use std::os::raw::c_ulonglong; -use std::ptr::{null as nullptr, null_mut as nullptr_mut}; +use std::ptr::null as nullptr; -pub const XAEAD_TAG_LEN: usize = libsodium::crypto_aead_xchacha20poly1305_ietf_ABYTES as usize; -pub const XAEAD_NONCE_LEN: usize = libsodium::crypto_aead_xchacha20poly1305_IETF_NPUBBYTES as usize; pub const NONCE0: [u8; libsodium::crypto_aead_chacha20poly1305_IETF_NPUBBYTES as usize] = [0u8; libsodium::crypto_aead_chacha20poly1305_IETF_NPUBBYTES as usize]; pub const NOTHING: [u8; 0] = [0u8; 0]; @@ -31,62 +29,6 @@ macro_rules! sodium_call { ($name:ident) => { sodium_call!($name, ) }; } -#[inline] -pub fn xaead_enc_into( - ciphertext: &mut [u8], - key: &[u8], - nonce: &[u8], - ad: &[u8], - plaintext: &[u8], -) -> Result<()> { - assert!(ciphertext.len() == plaintext.len() + XAEAD_NONCE_LEN + XAEAD_TAG_LEN); - assert!(key.len() == libsodium::crypto_aead_xchacha20poly1305_IETF_KEYBYTES as usize); - let (n, ct) = ciphertext.split_at_mut(XAEAD_NONCE_LEN); - n.copy_from_slice(nonce); - let mut clen: u64 = 0; - sodium_call!( - crypto_aead_xchacha20poly1305_ietf_encrypt, - ct.as_mut_ptr(), - &mut clen, - plaintext.as_ptr(), - plaintext.len() as c_ulonglong, - ad.as_ptr(), - ad.len() as c_ulonglong, - nullptr(), // nsec is not used - nonce.as_ptr(), - key.as_ptr() - )?; - assert!(clen as usize == ct.len()); - Ok(()) -} - -#[inline] -pub fn xaead_dec_into( - plaintext: &mut [u8], - key: &[u8], - ad: &[u8], - ciphertext: &[u8], -) -> Result<()> { - assert!(ciphertext.len() == plaintext.len() + XAEAD_NONCE_LEN + XAEAD_TAG_LEN); - assert!(key.len() == libsodium::crypto_aead_xchacha20poly1305_IETF_KEYBYTES as usize); - let (n, ct) = ciphertext.split_at(XAEAD_NONCE_LEN); - let mut mlen: u64 = 0; - sodium_call!( - crypto_aead_xchacha20poly1305_ietf_decrypt, - plaintext.as_mut_ptr(), - &mut mlen as *mut c_ulonglong, - nullptr_mut(), // nsec is not used - ct.as_ptr(), - ct.len() as c_ulonglong, - ad.as_ptr(), - ad.len() as c_ulonglong, - n.as_ptr(), - key.as_ptr() - )?; - assert!(mlen as usize == plaintext.len()); - Ok(()) -} - #[inline] fn blake2b_flexible(out: &mut [u8], key: &[u8], data: &[u8]) -> Result<()> { const KEY_MIN: usize = libsodium::crypto_generichash_KEYBYTES_MIN as usize;