sanstun 0.1.0

A fast, sans-IO implementation of the WireGuard® protocol
Documentation
use std::fmt;

use zeroize::Zeroizing;

/// An X25519 public key.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct PublicKey([u8; 32]);

impl PublicKey {
    pub fn as_bytes(&self) -> &[u8; 32] {
        &self.0
    }

    pub fn to_bytes(&self) -> [u8; 32] {
        self.0
    }

    pub(crate) fn to_dalek(self) -> x25519_dalek::PublicKey {
        x25519_dalek::PublicKey::from(self.0)
    }
}

impl From<[u8; 32]> for PublicKey {
    fn from(bytes: [u8; 32]) -> Self {
        Self(bytes)
    }
}

impl From<&StaticSecret> for PublicKey {
    fn from(secret: &StaticSecret) -> Self {
        Self(x25519_dalek::PublicKey::from(&secret.0).to_bytes())
    }
}

impl fmt::Debug for PublicKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("PublicKey(")?;
        for byte in self.0 {
            write!(f, "{byte:02x}")?;
        }
        f.write_str(")")
    }
}

/// An X25519 static private key, zeroized on drop.
#[derive(Clone)]
pub struct StaticSecret(x25519_dalek::StaticSecret);

impl StaticSecret {
    pub fn as_bytes(&self) -> &[u8; 32] {
        self.0.as_bytes()
    }

    pub(crate) fn as_dalek(&self) -> &x25519_dalek::StaticSecret {
        &self.0
    }
}

impl From<Zeroizing<[u8; 32]>> for StaticSecret {
    fn from(bytes: Zeroizing<[u8; 32]>) -> Self {
        Self(x25519_dalek::StaticSecret::from(*bytes))
    }
}

impl fmt::Debug for StaticSecret {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("StaticSecret(..)")
    }
}

/// A WireGuard preshared key, zeroized on drop.
pub struct PresharedKey(Zeroizing<[u8; 32]>);

impl PresharedKey {
    pub(crate) fn as_bytes(&self) -> &[u8; 32] {
        &self.0
    }
}

impl From<Zeroizing<[u8; 32]>> for PresharedKey {
    fn from(bytes: Zeroizing<[u8; 32]>) -> Self {
        Self(bytes)
    }
}

impl fmt::Debug for PresharedKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("PresharedKey(..)")
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn debug_redacts_only_the_secrets() {
        let secret = StaticSecret::from(Zeroizing::new([0xab; 32]));
        let psk = PresharedKey::from(Zeroizing::new([0xab; 32]));

        assert_eq!(format!("{secret:?}"), "StaticSecret(..)");
        assert_eq!(format!("{psk:?}"), "PresharedKey(..)");
        assert_eq!(
            format!("{:?}", PublicKey::from([0xab; 32])),
            format!("PublicKey({})", "ab".repeat(32))
        );
    }
}