devolutions-crypto 0.5.1

An abstraction layer for the cryptography used by Devolutions
Documentation
use super::Argon2Parameters;

use super::Error;
use super::Result;

use rand::rngs::OsRng;
use x25519_dalek::{PublicKey, StaticSecret};
use zeroize::Zeroize;

use std::convert::TryFrom;

#[derive(Clone)]
pub struct KeyV1Pair {
    pub private_key: KeyV1Private,
    pub public_key: KeyV1Public,
}

#[derive(Clone)]
pub struct KeyV1Private {
    key: StaticSecret,
}

impl core::fmt::Debug for KeyV1Private {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> std::result::Result<(), core::fmt::Error> {
        write!(f, "Private Key")
    }
}

#[cfg(feature = "fuzz")]
impl arbitrary::Arbitrary for KeyV1Private {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        let private_key: [u8; 32] = arbitrary::Arbitrary::arbitrary(u)?;
        Ok(Self {
            key: x25519_dalek::StaticSecret::from(private_key),
        })
    }
}

#[derive(Clone, Debug)]
pub struct KeyV1Public {
    key: PublicKey,
}

#[cfg(feature = "fuzz")]
impl arbitrary::Arbitrary for KeyV1Public {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        let public_key: [u8; 32] = arbitrary::Arbitrary::arbitrary(u)?;
        Ok(Self {
            key: x25519_dalek::PublicKey::from(public_key),
        })
    }
}

impl From<KeyV1Private> for Vec<u8> {
    fn from(key: KeyV1Private) -> Self {
        key.key.to_bytes().to_vec()
    }
}

impl From<KeyV1Public> for Vec<u8> {
    fn from(key: KeyV1Public) -> Self {
        key.key.as_bytes().to_vec()
    }
}

impl TryFrom<&[u8]> for KeyV1Private {
    type Error = Error;

    fn try_from(key: &[u8]) -> Result<Self> {
        if key.len() != 32 {
            return Err(Error::InvalidLength);
        }

        let mut key_bytes = [0u8; 32];
        key_bytes.copy_from_slice(&key[0..32]);
        Ok(Self {
            key: StaticSecret::from(key_bytes),
        })
    }
}

impl TryFrom<&[u8]> for KeyV1Public {
    type Error = Error;

    fn try_from(key: &[u8]) -> Result<Self> {
        if key.len() != 32 {
            return Err(Error::InvalidLength);
        }

        let mut key_bytes = [0u8; 32];
        key_bytes.copy_from_slice(&key[0..32]);
        Ok(Self {
            key: PublicKey::from(key_bytes),
        })
    }
}

pub fn generate_keypair() -> KeyV1Pair {
    let private = StaticSecret::new(&mut OsRng);
    let public = PublicKey::from(&private);

    KeyV1Pair {
        private_key: KeyV1Private { key: private },
        public_key: KeyV1Public { key: public },
    }
}

pub fn derive_keypair(password: &[u8], parameters: &Argon2Parameters) -> Result<KeyV1Pair> {
    if parameters.length != 32 {
        return Err(Error::InvalidLength);
    }
    let mut derived_pass = parameters.compute(password)?;

    let mut key_bytes = [0u8; 32];
    key_bytes.copy_from_slice(&derived_pass[0..32]);

    derived_pass.zeroize();

    let private = StaticSecret::from(key_bytes);
    let public = PublicKey::from(&private);

    Ok(KeyV1Pair {
        private_key: KeyV1Private { key: private },
        public_key: KeyV1Public { key: public },
    })
}

pub fn mix_key_exchange(private: &KeyV1Private, public: &KeyV1Public) -> Vec<u8> {
    private.key.diffie_hellman(&public.key).as_bytes().to_vec()
}

impl From<&KeyV1Public> for x25519_dalek::PublicKey {
    fn from(data: &KeyV1Public) -> Self {
        data.key
    }
}

impl From<&KeyV1Private> for x25519_dalek::StaticSecret {
    fn from(data: &KeyV1Private) -> Self {
        data.key.clone()
    }
}