Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge feature/managed kdf masterkey into dev #7

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 20 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
}
77 changes: 42 additions & 35 deletions src/sodium.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -230,50 +228,53 @@ impl Sodium {
///
/// # Returns
/// A [`Vec<u8>`] containing the generated master key.
pub fn crypto_kdf_keygen(self) -> Vec<u8> {
let mut result = Vec::<u8>::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(Copy, 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<u8>`] containing the derived subkey.
pub fn crypto_kdf_derive_from_key(
self,
master_key: &[u8],
context: &str,
subkey_id: u64,
subkey_len: usize,
) -> Vec<u8> {
assert!(subkey_len >= 16 && subkey_len <= 64);
assert!(master_key.len() == ffi::crypto_kdf_KEYBYTES as usize);

let mut result = Vec::<u8>::with_capacity(subkey_len as usize);
pub fn derive_subkey(&self, subkey_id: u64, subkey_len: usize) -> Vec<u8> {
assert!((16..=64).contains(&subkey_len));

let ctx = CString::new(context).unwrap();
let mut result = Vec::<u8>::with_capacity(subkey_len);

// SAFETY: See safety for Sodium::crypto_kdf_keygen.
unsafe {
ffi::crypto_kdf_derive_from_key(
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);
}
Expand All @@ -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)]
Expand Down