devolutions-crypto 0.10.0

An abstraction layer for the cryptography used by Devolutions
Documentation
use std::convert::TryFrom;
use std::io::{Cursor, Read, Write};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use crate::ciphertext::Ciphertext;
use crate::key_derivation::DerivationParameters;
use crate::{Error, Result};

#[cfg(feature = "fuzz")]
use arbitrary::Arbitrary;

#[derive(Clone, Debug)]
#[cfg_attr(feature = "fuzz", derive(Arbitrary))]
pub struct KdfEncryptedDataV1 {
    pub derivation_parameters: DerivationParameters,
    pub ciphertext: Ciphertext,
}

impl From<KdfEncryptedDataV1> for Vec<u8> {
    fn from(data: KdfEncryptedDataV1) -> Self {
        let derivation_parameters: Vec<u8> = data.derivation_parameters.into();
        let ciphertext: Vec<u8> = data.ciphertext.into();

        let mut serialized = Vec::with_capacity(8 + derivation_parameters.len() + ciphertext.len());

        serialized
            .write_u32::<LittleEndian>(derivation_parameters.len() as u32)
            .unwrap();
        serialized
            .write_u32::<LittleEndian>(ciphertext.len() as u32)
            .unwrap();
        serialized.write_all(&derivation_parameters).unwrap();
        serialized.write_all(&ciphertext).unwrap();

        serialized
    }
}

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

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

        let mut cursor = Cursor::new(data);

        let derivation_parameters_length = cursor.read_u32::<LittleEndian>()? as usize;
        let ciphertext_length = cursor.read_u32::<LittleEndian>()? as usize;

        let total_expected = 8usize
            .checked_add(derivation_parameters_length)
            .and_then(|x| x.checked_add(ciphertext_length))
            .ok_or(Error::InvalidLength)?;

        if data.len() != total_expected {
            return Err(Error::InvalidLength);
        }

        let mut derivation_parameters_raw = vec![0u8; derivation_parameters_length];
        cursor.read_exact(&mut derivation_parameters_raw)?;

        let mut ciphertext_raw = vec![0u8; ciphertext_length];
        cursor.read_exact(&mut ciphertext_raw)?;

        Ok(Self {
            derivation_parameters: DerivationParameters::try_from(
                derivation_parameters_raw.as_slice(),
            )?,
            ciphertext: Ciphertext::try_from(ciphertext_raw.as_slice())?,
        })
    }
}