libsbxf 0.1.0

Rust library for the Secure Block Exchange Format
Documentation
use rand::prelude::*;

pub struct SBXF<T> {
    handler: T,
}

impl<T: Handler> SBXF<T> {
    pub fn new(handler: T) -> Self {
        SBXF { handler }
    }

    pub fn upload_file(&self, data: Vec<u8>) -> Result<(), ()> {
        let block_size = self.calculate_blocksize(data.len());
        let mut blocks = data.len() / block_size;

        if data.len() % block_size != 0 {
            blocks += 1;
        };

        for i in 0..blocks {
            let block_start = i * block_size;
            let block_end = (block_start + block_size).min(data.len());

            let block = self.size_block(&data[block_start..block_end], block_size);
            let encrypted_block = self.encrypt_block(block);

            self.handler.save_block(encrypted_block)?;
        }

        let _ = self.handler.save_meta(data);
        Ok(())
    }

    fn calculate_blocksize(&self, size: usize) -> usize {
        (size.next_power_of_two() >> 3)
            .max(4 * 1024) // 4 KB minimum block size.
            .min(64 * 1024 * 1024) // 64 MB maximum block size.
    }

    fn size_block(&self, raw_block: &[u8], block_size: usize) -> Vec<u8> {
        let block = if raw_block.len() == block_size {
            raw_block.to_owned()
        } else {
            let mut rng = rand::thread_rng();
            let mut new_block = raw_block.to_owned();
            let padding_len = block_size - new_block.len();

            // Pad the block with random data, to counter cracking the encryption when there is not a lot of entropy in the block.
            for _ in 0..padding_len {
                new_block.push(rng.gen());
            }

            new_block
        };

        block
    }

    fn encrypt_block(&self, block: Vec<u8>) -> Vec<u8> {
        //TODO
        block
    }
}

pub trait Handler {
    fn save_meta(&self, data: Vec<u8>) -> Result<(), ()>;
    fn save_block(&self, data: Vec<u8>) -> Result<(), ()>;
}

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

    struct DummyHandler;

    impl Handler for DummyHandler {
        fn save_meta(&self, _: Vec<u8>) -> Result<(), ()> {
            Ok(())
        }

        fn save_block(&self, _: Vec<u8>) -> Result<(), ()> {
            Ok(())
        }
    }

    #[test]
    fn upload_smoke() {
        let sbxf = SBXF::new(DummyHandler);

        sbxf.upload_file(vec![42, 42, 255])
            .expect("failed to upload");
    }

    #[test]
    fn calculate_blocksize() {
        let sbxf = SBXF::new(DummyHandler);

        assert_eq!(32 * 1024, sbxf.calculate_blocksize(200 * 1024));
        assert_eq!(32 * 1024, sbxf.calculate_blocksize(256 * 1024));
        assert_eq!(64 * 1024, sbxf.calculate_blocksize((256 * 1024) + 1));
    }

    #[test]
    fn calculate_small_blocksize() {
        let sbxf = SBXF::new(DummyHandler);

        assert_eq!(4096, sbxf.calculate_blocksize(0));
        assert_eq!(4096, sbxf.calculate_blocksize(1));
        assert_eq!(4096, sbxf.calculate_blocksize(4242));
        assert_eq!(4096, sbxf.calculate_blocksize(32 * 1024)); // 32 KB
        assert_eq!(8192, sbxf.calculate_blocksize((32 * 1024) + 1)); // 32 KB + 1 B
    }

    #[test]
    fn calculate_large_blocksize() {
        let sbxf = SBXF::new(DummyHandler);

        assert_eq!(
            32 * 1024 * 1024,
            sbxf.calculate_blocksize(256 * 1024 * 1024)
        ); // 0.25 GB
        assert_eq!(
            64 * 1024 * 1024,
            sbxf.calculate_blocksize(256 * 1024 * 1024 + 1)
        ); // 0.25 GB + 1 B
        assert_eq!(
            64 * 1024 * 1024,
            sbxf.calculate_blocksize(1024 * 1024 * 1024)
        ); // 1 GB
        assert_eq!(
            64 * 1024 * 1024,
            sbxf.calculate_blocksize(1024 * 1024 * 1024 * 1024)
        ); // 1 TB
    }

    #[test]
    fn resize_block() {
        let sbxf = SBXF::new(DummyHandler);
        let new_block = sbxf.size_block(&[42, 255, 0], 666);

        assert_eq!(666, new_block.len());
        assert_eq!(42, new_block[0]);
        assert_eq!(255, new_block[1]);
        assert_eq!(0, new_block[2]);
    }
}