From a52a160b771de7f04a35123e675191309c89d9d0 Mon Sep 17 00:00:00 2001 From: Jaco Malan Date: Sat, 17 Jun 2023 03:23:53 +0200 Subject: [PATCH 1/2] Added KdfMasterKey struct --- src/lib.rs | 47 +++++++++++++------------------ src/sodium.rs | 77 ++++++++++++++++++++++++++++----------------------- 2 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ca8762a..6035357 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,27 +4,23 @@ //! ```rust //! use tablesalt::sodium; //! -//! fn main() { -//! let s = sodium::Sodium::new(); -//! let hash = s.crypto_generichash(b"Some message", None, 32); +//! let s = sodium::Sodium::new(); +//! let hash = s.crypto_generichash(b"Some message", None, 32); //! -//! println!("blake2b hash: {}", hex::encode(&hash)); -//! } +//! println!("blake2b hash: {}", hex::encode(&hash)); //! ``` //! //! # Hashing a multi-part message. //! ```rust //! use tablesalt::sodium; +//! +//! let s = sodium::Sodium::new(); +//! let mut state = s.crypto_generichash_init(None, 32); +//! state.update(b"Some "); +//! state.update(b"message"); +//! let hash = state.finalize(); //! -//! fn main() { -//! let s = sodium::Sodium::new(); -//! let mut state = s.crypto_generichash_init(None, 32); -//! state.update(b"Some "); -//! state.update(b"message"); -//! let hash = state.finalize(); -//! -//! println!("blake2b hash: {}", hex::encode(&hash)); -//! } +//! println!("blake2b hash: {}", hex::encode(&hash)); //! ``` pub mod sodium; @@ -53,7 +49,7 @@ mod tests { fn test_crypto_generichash_with_key() { let hash = sodium::Sodium::new().crypto_generichash(b"Some message!", Some(b"key"), 64); assert_eq!( - hex::encode(&hash), + hex::encode(hash), concat!( "6368da700e596f77afc013867dd108a9f442c4d56b7a55d6cd4943303aef461", "9f0148de2ae7948a901a1147c57e3ec0faf69bf021e3e50a537462760fbca3615" @@ -153,20 +149,19 @@ mod tests { #[test] fn test_generate_master_key() { let s = sodium::Sodium::new(); - let key = s.crypto_kdf_keygen(); + let key = s.crypto_kdf_keygen(b"Examples"); println!("Key: {}", hex::encode(key)); } #[test] fn test_generate_subkey() { let s = sodium::Sodium::new(); - let ctx = String::from("Some context"); - let key = s.crypto_kdf_keygen(); + let key = s.crypto_kdf_keygen(b"Examples"); println!("Master Key: {}", hex::encode(&key)); - let s1 = s.crypto_kdf_derive_from_key(&key, &ctx, 1, 16); - let s2 = s.crypto_kdf_derive_from_key(&key, &ctx, 2, 32); - let s3 = s.crypto_kdf_derive_from_key(&key, &ctx, 3, 64); + let s1 = key.derive_subkey(1, 16); + let s2 = key.derive_subkey(2, 32); + let s3 = key.derive_subkey(3, 64); assert_eq!(s1.len(), 16); assert_eq!(s2.len(), 32); @@ -177,21 +172,19 @@ mod tests { #[should_panic] fn test_subkey_too_short() { let s = sodium::Sodium::new(); - let ctx = String::from("Some context"); - let key = s.crypto_kdf_keygen(); + let key = s.crypto_kdf_keygen(b"Examples"); println!("Master Key: {}", hex::encode(&key)); - let _ = s.crypto_kdf_derive_from_key(&key, &ctx, 1, 15); + let _ = key.derive_subkey(1, 15); } #[test] #[should_panic] fn test_subkey_too_long() { let s = sodium::Sodium::new(); - let ctx = String::from("Some context"); - let key = s.crypto_kdf_keygen(); + let key = s.crypto_kdf_keygen(b"Examples"); println!("Master Key: {}", hex::encode(&key)); - let _ = s.crypto_kdf_derive_from_key(&key, &ctx, 1, 65); + let _ = key.derive_subkey(1, 65); } } diff --git a/src/sodium.rs b/src/sodium.rs index bb4ffd1..bc9ecc3 100644 --- a/src/sodium.rs +++ b/src/sodium.rs @@ -1,5 +1,5 @@ use libsodium_sys as ffi; -use std::{ffi::CString, marker::PhantomData, mem::MaybeUninit, rc::Rc}; +use std::{marker::PhantomData, mem::MaybeUninit, rc::Rc}; #[non_exhaustive] #[derive(Copy, Clone, Debug)] @@ -147,16 +147,14 @@ impl Sodium { /// ```rust /// use tablesalt::sodium::{self, SecretStreamTag}; /// - /// fn main() { - /// let s = sodium::Sodium::new(); - /// let key = s.crypto_secretstream_keygen(); - /// let mut stream = s.crypto_secretstream_init_push(key); - /// let ciphertext1 = stream.push(b"Hello, ", SecretStreamTag::Message); - /// let ciphertext2 = stream.push(b"World!", SecretStreamTag::Final); + /// let s = sodium::Sodium::new(); + /// let key = s.crypto_secretstream_keygen(); + /// let mut stream = s.crypto_secretstream_init_push(key); + /// let ciphertext1 = stream.push(b"Hello, ", SecretStreamTag::Message); + /// let ciphertext2 = stream.push(b"World!", SecretStreamTag::Final); /// - /// println!("Ciphertext 1: {}", hex::encode(&ciphertext1)); - /// println!("Ciphertext 2: {}", hex::encode(&ciphertext2)); - /// } + /// println!("Ciphertext 1: {}", hex::encode(&ciphertext1)); + /// println!("Ciphertext 2: {}", hex::encode(&ciphertext2)); /// ``` pub fn crypto_secretstream_init_push( self, @@ -230,41 +228,44 @@ impl Sodium { /// /// # Returns /// A [`Vec`] containing the generated master key. - pub fn crypto_kdf_keygen(self) -> Vec { - let mut result = Vec::::with_capacity(ffi::crypto_kdf_KEYBYTES as usize); + pub fn crypto_kdf_keygen( + self, + context: &[u8; ffi::crypto_kdf_CONTEXTBYTES as usize], + ) -> KdfMasterKey { + let mut buffer = MaybeUninit::new([0u8; ffi::crypto_kdf_KEYBYTES as usize]); // SAFETY: We know that crypto_kdf_keygen will write crypto_kdf_KEYBYTES into - // result, so it is safe to set it's length to that. - unsafe { - ffi::crypto_kdf_keygen(result.as_mut_ptr()); - result.set_len(ffi::crypto_kdf_KEYBYTES as usize); - } + // `buffer`, so it is safe to assume it is initialized. + let buffer = unsafe { + ffi::crypto_kdf_keygen(buffer.as_mut_ptr() as *mut u8); + buffer.assume_init() + }; - result + KdfMasterKey { + internal: buffer, + context: *context, + } } +} + +#[derive(Clone)] +pub struct KdfMasterKey { + internal: [u8; ffi::crypto_kdf_KEYBYTES as usize], + context: [u8; ffi::crypto_kdf_CONTEXTBYTES as usize], +} - /// Derives a subkey from a master key and context. +impl KdfMasterKey { + /// Derives a subkey from a master key. /// /// # Panics /// - Panics if the provided `subkey_len` is not in the range (16..=64). - /// - Panics if `master_key.len() != libsodium_sys::crypto_kdf_KEYBYTES`. - /// /// /// # Returns /// A [`Vec`] containing the derived subkey. - pub fn crypto_kdf_derive_from_key( - self, - master_key: &[u8], - context: &str, - subkey_id: u64, - subkey_len: usize, - ) -> Vec { - assert!(subkey_len >= 16 && subkey_len <= 64); - assert!(master_key.len() == ffi::crypto_kdf_KEYBYTES as usize); - - let mut result = Vec::::with_capacity(subkey_len as usize); + pub fn derive_subkey(&self, subkey_id: u64, subkey_len: usize) -> Vec { + assert!((16..=64).contains(&subkey_len)); - let ctx = CString::new(context).unwrap(); + let mut result = Vec::::with_capacity(subkey_len); // SAFETY: See safety for Sodium::crypto_kdf_keygen. unsafe { @@ -272,8 +273,8 @@ impl Sodium { result.as_mut_ptr(), subkey_len, subkey_id, - ctx.as_ptr(), - master_key.as_ptr(), + self.context.as_ptr() as *const i8, + self.internal.as_ptr(), ); result.set_len(subkey_len); } @@ -282,6 +283,12 @@ impl Sodium { } } +impl AsRef<[u8]> for KdfMasterKey { + fn as_ref(&self) -> &[u8] { + &self.internal + } +} + /// An error indicating that a provided decryption header /// was invalid. #[derive(Debug, Clone, Copy)] From 4871785ac10721a4343452869a9e108caa9a7115 Mon Sep 17 00:00:00 2001 From: Jaco Malan Date: Sat, 17 Jun 2023 03:24:49 +0200 Subject: [PATCH 2/2] Derive Copy on KdfMasterKey --- src/sodium.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sodium.rs b/src/sodium.rs index bc9ecc3..f89d988 100644 --- a/src/sodium.rs +++ b/src/sodium.rs @@ -248,7 +248,7 @@ impl Sodium { } } -#[derive(Clone)] +#[derive(Copy, Clone)] pub struct KdfMasterKey { internal: [u8; ffi::crypto_kdf_KEYBYTES as usize], context: [u8; ffi::crypto_kdf_CONTEXTBYTES as usize],