devolutions-crypto 0.3.0

An abstraction layer for the cryptography used by Devolutions
Documentation
use super::DcHeader;
use super::DevoCryptoError;
use super::Result;

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

const PRIVATE: u16 = 1;
const PUBLIC: u16 = 2;

pub enum DcKeyV1 {
    Private(StaticSecret),
    Public(PublicKey),
}

impl From<DcKeyV1> for Vec<u8> {
    fn from(key: DcKeyV1) -> Vec<u8> {
        match key {
            DcKeyV1::Private(x) => x.to_bytes().to_vec(),
            DcKeyV1::Public(x) => x.as_bytes().to_vec(),
        }
    }
}

impl DcKeyV1 {
    pub fn try_from_header(data: &[u8], header: &DcHeader) -> Result<DcKeyV1> {
        if data.len() != 32 {
            return Err(DevoCryptoError::InvalidLength);
        };

        let mut key_bytes = [0u8; 32];

        key_bytes.copy_from_slice(&data[0..32]);

        let key = match header.data_subtype {
            PRIVATE => DcKeyV1::Private(StaticSecret::from(key_bytes)),
            PUBLIC => DcKeyV1::Public(PublicKey::from(key_bytes)),
            _ => return Err(DevoCryptoError::UnknownSubtype),
        };
        Ok(key)
    }

    pub fn generate_key_exchange(
        private_header: &mut DcHeader,
        public_header: &mut DcHeader,
    ) -> Result<(DcKeyV1, DcKeyV1)> {
        private_header.data_subtype = PRIVATE;
        public_header.data_subtype = PUBLIC;

        let private = StaticSecret::new(&mut OsRng);
        let public = PublicKey::from(&private);

        Ok((DcKeyV1::Private(private), DcKeyV1::Public(public)))
    }

    pub fn mix_key_exchange(self, public: DcKeyV1) -> Result<Vec<u8>> {
        match (self, public) {
            (DcKeyV1::Private(private), DcKeyV1::Public(public)) => {
                Ok(private.diffie_hellman(&public).as_bytes().to_vec())
            }
            _ => Err(DevoCryptoError::InvalidDataType),
        }
    }
}