use secp256k1::key::{SecretKey, ONE_KEY};
use sodiumoxide::utils::{mlock, munlock};
use std::convert::TryFrom;
use std::fmt;
use std::ops::Deref;
use std::pin::Pin;
use std::slice;
use zeroize::{DefaultIsZeroes, Zeroize};
pub struct SafeSecretKey {
safe: Pin<Box<ZeroizedSecretKey>>,
}
impl fmt::Debug for SafeSecretKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SecretKey").finish()
}
}
#[derive(Copy, Clone)]
struct ZeroizedSecretKey(SecretKey);
impl DefaultIsZeroes for ZeroizedSecretKey {}
impl Default for ZeroizedSecretKey {
fn default() -> Self {
Self(ONE_KEY)
}
}
impl ZeroizedSecretKey {
fn as_mut_bytes(&mut self) -> &mut [u8] {
unsafe {
let ptr = self.0.as_mut_ptr();
slice::from_raw_parts_mut(ptr, self.0.len())
}
}
}
impl SafeSecretKey {
fn new(secret: &SecretKey) -> Result<Self, ()> {
let mut safe = Pin::new(Box::<ZeroizedSecretKey>::default());
let mem = safe.as_mut_bytes();
mlock(mem)?;
safe.0 = *secret;
Ok(Self { safe })
}
}
impl<'a> TryFrom<&'a SecretKey> for SafeSecretKey {
type Error = ();
fn try_from(secret: &'a SecretKey) -> Result<Self, ()> {
Self::new(secret)
}
}
impl Drop for SafeSecretKey {
fn drop(&mut self) {
self.safe.zeroize();
let mem = self.safe.as_mut_bytes();
let _ignore = munlock(mem);
}
}
impl Deref for SafeSecretKey {
type Target = SecretKey;
fn deref(&self) -> &Self::Target {
&self.safe.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use secp256k1::key::ONE_KEY;
#[test]
pub fn no_panic() {
let key = ONE_KEY;
let safe = SafeSecretKey::new(&key).unwrap();
drop(safe);
}
}