Skip to content

Commit

Permalink
implement our own SecretVec which
Browse files Browse the repository at this point in the history
  • Loading branch information
radumarias committed Jun 5, 2024
1 parent de58829 commit 2e081b6
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 26 deletions.
23 changes: 3 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rencrypt"
version = "0.3.0"
version = "0.3.1"
edition = "2021"

[lib]
Expand All @@ -21,7 +21,8 @@ criterion = "0.5.1"
blake3 = "=0.1.3"
hex = "0.4.3"
numpy = "0.21"
secrets = { version = "1.2.0", features = ["use-libsodium-sys"] }
libsodium-sys = "0.2.7"
libc = "0.2.155"

[dev-dependencies]
criterion = { version = "0.5.1", features = ["html_reports"] }
Expand Down
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use rayon::iter::ParallelIterator;
use rayon::prelude::{ParallelSlice, ParallelSliceMut};
use ring::aead::{Aad, AES_256_GCM, BoundKey, CHACHA20_POLY1305, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey};
use ring::error::Unspecified;
use secrets::SecretVec;
use zeroize::Zeroize;
use crate::CipherMeta::Ring;
use crate::secrets::SecretVec;

mod cipher;
mod secrets;

// 256KB seems to be the optimal block size that offers the max MB/s speed for encryption,
// on benchmarks that seem to be the case.
Expand Down Expand Up @@ -521,7 +522,7 @@ fn create_ring_sealing_key(alg: RingAlgorithm, key: &SecretVec<u8>) -> (SealingK
let nonce_sequence = nonce_seq.clone();
let nonce_wrapper = RandomNonceSequenceWrapper::new(nonce_seq.clone());
// Create a new AEAD key without a designated role or nonce sequence
let unbound_key = UnboundKey::new(get_ring_algorithm(alg), &*key.borrow()).unwrap();
let unbound_key = UnboundKey::new(get_ring_algorithm(alg), key.as_ref()).unwrap();

// Create a new AEAD key for encrypting and signing ("sealing"), bound to a nonce sequence
// The SealingKey can be used multiple times, each time a new nonce will be used
Expand All @@ -531,7 +532,7 @@ fn create_ring_sealing_key(alg: RingAlgorithm, key: &SecretVec<u8>) -> (SealingK

fn create_ring_opening_key(alg: RingAlgorithm, key: &SecretVec<u8>) -> (OpeningKey<ExistingNonceSequence>, Arc<Mutex<Vec<u8>>>) {
let last_nonce = Arc::new(Mutex::new(vec![0_u8; get_ring_algorithm(alg).nonce_len()]));
let unbound_key = UnboundKey::new(get_ring_algorithm(alg), &*key.borrow()).unwrap();
let unbound_key = UnboundKey::new(get_ring_algorithm(alg), key.as_ref()).unwrap();
let nonce_sequence = ExistingNonceSequence::new(last_nonce.clone());
let opening_key = OpeningKey::new(unbound_key, nonce_sequence);
(opening_key, last_nonce)
Expand Down Expand Up @@ -684,7 +685,7 @@ mod tests {
fn test_encrypt_decrypt() {
let cipher_meta = Ring { alg: RingAlgorithm::AES256GCM };
let alg = match cipher_meta { Ring { alg } => alg };
let key = SecretVec::<u8>::new(get_ring_algorithm(alg).key_len(), |s| {
let key = SecretVec::new(get_ring_algorithm(alg).key_len(), |s| {
create_rng().fill_bytes(s);
});
let (sealing_key, nonce_sequence) = create_ring_sealing_key(alg, &key);
Expand Down
105 changes: 105 additions & 0 deletions src/secrets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use std::sync::Once;
use libc::{self, size_t};
use libsodium_sys::{
sodium_init
, sodium_mlock
, sodium_munlock,
};
use zeroize::Zeroize;

/// The global [`sync::Once`] that ensures we only perform
/// library initialization one time.
static INIT: Once = Once::new();

/// A flag that returns whether this library has been safely
/// initialized.
static mut INITIALIZED: bool = false;

pub struct SecretVec<T: Zeroize> {
secret: Vec<T>,
}

impl<T: Zeroize + Default + Clone> SecretVec<T> {
pub fn new<F>(len: usize, f: F) -> Self
where F: FnOnce(&mut [T])
{
let v = T::default();
let mut secret: Vec<T> = vec![v; len];
unsafe { mlock(secret.as_mut_ptr(), len); }
f(&mut secret);
SecretVec {
secret,
}
}
}

impl<T: Zeroize> AsRef<[T]> for SecretVec<T> {
fn as_ref(&self) -> &[T] {
&self.secret
}
}

impl<T: Zeroize> AsMut<[T]> for SecretVec<T> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.secret
}
}

impl<T: Zeroize> Drop for SecretVec<T> {
fn drop(&mut self) {
self.secret.zeroize();
unsafe { munlock(self.secret.as_mut_ptr(), self.secret.len()); }
}
}

/// Initialized libsodium. This function *must* be called at least once
/// prior to using any of the other functions in this library, and
/// callers *must* verify that it returns `true`. If it returns `false`,
/// libsodium was unable to be properly set up and this library *must
/// not* be used.
///
/// Calling it multiple times is a no-op.
fn init() -> bool {
unsafe {
INIT.call_once(|| {
// NOTE: Calls to transmute fail to compile if the source
// and destination type have a different size. We (ab)use
// this fact to statically assert the size of types at
// compile-time.
//
// We assume that we can freely cast between rust array
// sizes and [`libc::size_t`]. If that's not true, DO NOT
// COMPILE.
#[allow(clippy::useless_transmute)]
let _ = std::mem::transmute::<usize, size_t>(0);

let mut failure = false;

// sodium_init returns 0 on success, -1 on failure, and 1 if
// the library is already initialized; someone else might
// have already initialized it before us, so we only care
// about failure
failure |= sodium_init() == -1;

INITIALIZED = !failure;
});

INITIALIZED
}
}

/// Calls the platform's underlying `mlock(2)` implementation.
unsafe fn mlock<T>(ptr: *mut T, len: usize) -> bool {
if !init() {
panic!("Failed to initialize libsodium");
}
sodium_mlock(ptr.cast(), len) == 0
}

/// Calls the platform's underlying `munlock(2)` implementation.
unsafe fn munlock<T>(ptr: *mut T, len: usize) -> bool {
if !init() {
panic!("Failed to initialize libsodium");
}
sodium_munlock(ptr.cast(), len) == 0
}

0 comments on commit 2e081b6

Please sign in to comment.