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

Securely erasing memory #2

Open
nstilt1 opened this issue Mar 9, 2024 · 2 comments
Open

Securely erasing memory #2

nstilt1 opened this issue Mar 9, 2024 · 2 comments
Labels
question Further information is requested

Comments

@nstilt1
Copy link
Owner

nstilt1 commented Mar 9, 2024

Currently, there are a few aspects of this crate that can't be easily erased from memory:

  1. temporary values and other stack-based values containing key material when creating private keys may be copied at will by the compiler
  2. hkdf might use some temporary values as well

This library doesn't perform some of the more large operations to be able to sufficiently implement "stack bleaching", such as signing data with private keys. This library merely generates the key, so a library that uses this library might be more suited for stack bleaching.

My question is: is it even worth it to eliminate all temporary variables, or should people try to use stack bleaching until there is a new development with Rust and/or the LLVM that allows for the developer to indicate that the compiler should not make certain stack data persist longer than required?

@nstilt1 nstilt1 added the question Further information is requested label Mar 9, 2024
@nstilt1
Copy link
Owner Author

nstilt1 commented Apr 27, 2024

There is more trouble in this regard in the initialization methods for the key_generator. It is also leaving some memory behind, but besides stack bleaching, I could add some members on the key_generator that contain the MAC key and the HKDF key and RNG seed, but I would also want to add something for the symmetric resource encryption key, which would mean that I would need to add the ResourceEncryptor as a generic parameter for the key_manager

@nstilt1
Copy link
Owner Author

nstilt1 commented Apr 27, 2024

It seems like the only way to do this without stack bleaching would involve having several members of the structs as Option<T>, and perhaps making a separate struct to simplify any sort of .unwrap() and .is_some() shenanigans. I wouldn't mind (much) doing this, but there are still some underlying crates that do not buffer their intermediate outputs... likely for a good reason, because it seems pretty tedious and imperfect. There's a lot of meticulous aspects of this, such as initialization. Calling Box::new(SomeStruct::new(...)) seems to only allocate the struct to the heap once the struct is returned from the new method. So to take that into account, the code might look something like this (kind of nasty):

#[cfg(feature = "boxed")]
type Boxed<T> = Box<T>;
#[cfg(not(feature = "boxed"))]
type Boxed<T> = T;

pub fn new(arr: &[u8]) -> Boxed<Self> {
    let mut s: Boxed<Self> = Boxed::new(Self {
        hkdf: Hkdf::from_prk(arr).expect("should be long enough"),
        hkdf_2: None,
        kdf_key: Default::default(),
    });
    s.hkdf.expand(b"level 2 kdf", &mut s.kdf_key);
    s.hkdf_2 = Some(Hkdf::from_prk(&s.kdf_key).expect("long enough"));
    s
}

Keep in mind that there would likely need to be a trait called Boxed that has a new method, or maybe a macro. Not entirely sure, but this seems like it would be nasty enough to consider stack bleaching instead. I tried to store intermediate values in a previous, unreleased version of this crate, and it got extremely hectic, especially once I had to start dealing with the Option<T> types. I believe I resorted to a helper function that called Option<T>::as_mut_slice()[0], which would fail on a None value, but should return a mutable reference if it was Some<T>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant