1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use alloc::boxed::Box;
use sha2::Digest;
use sha2::{digest::DynDigest, Sha256, Sha512};

use crate::{
    measurement::MeasurementError,
    rmi::{HASH_ALGO_SHA256, HASH_ALGO_SHA512},
};

pub struct HashWrapper {
    pub hash_func: Box<dyn DynDigest>,
}

impl HashWrapper {
    pub fn hash(&mut self, data: impl AsRef<[u8]>) {
        self.hash_func.update(data.as_ref());
    }

    pub fn hash_u8(&mut self, data: u8) {
        self.hash_func.update(data.to_le_bytes().as_slice());
    }

    pub fn hash_u16(&mut self, data: u16) {
        self.hash_func.update(data.to_le_bytes().as_slice());
    }

    pub fn hash_u32(&mut self, data: u32) {
        self.hash_func.update(data.to_le_bytes().as_slice());
    }

    pub fn hash_u64(&mut self, data: u64) {
        self.hash_func.update(data.to_le_bytes().as_slice());
    }

    pub fn hash_usize(&mut self, data: usize) {
        self.hash_func.update(data.to_le_bytes().as_slice());
    }

    pub fn hash_u64_array(&mut self, array: &[u64]) {
        for el in array.iter() {
            self.hash_func.update(el.to_le_bytes().as_slice());
        }
    }

    fn finish(&mut self, mut out: impl AsMut<[u8]>) -> Result<(), MeasurementError> {
        self.hash_func
            .finalize_into_reset(&mut out.as_mut()[0..self.hash_func.output_size()])
            .map_err(|_| MeasurementError::OutputBufferTooSmall)
    }
}

pub struct Hasher {
    factory: Box<dyn Fn() -> Box<dyn DynDigest>>,
    block_size: usize,
}

impl Hasher {
    pub fn from_hash_algo(hash_algo: u8) -> Result<Self, MeasurementError> {
        let factory: Box<dyn Fn() -> Box<dyn DynDigest>> = match hash_algo {
            HASH_ALGO_SHA256 => Box::new(|| Box::new(Sha256::new())),
            HASH_ALGO_SHA512 => Box::new(|| Box::new(Sha512::new())),
            _ => return Err(MeasurementError::InvalidHashAlgorithmValue(hash_algo)),
        };

        let block_size = match hash_algo {
            HASH_ALGO_SHA256 => <Sha256 as Digest>::output_size(),
            HASH_ALGO_SHA512 => <Sha512 as Digest>::output_size(),
            _ => return Err(MeasurementError::InvalidHashAlgorithmValue(hash_algo)),
        };

        Ok(Self {
            factory,
            block_size,
        })
    }

    pub fn hash_fields_into(
        &self,
        out: impl AsMut<[u8]>,
        f: impl Fn(&mut HashWrapper),
    ) -> Result<(), MeasurementError> {
        let mut wrapper = HashWrapper {
            hash_func: (self.factory)(),
        };
        f(&mut wrapper);
        wrapper.finish(out)
    }

    pub fn hash_object_into(
        &self,
        obj: &dyn Hashable,
        mut out: impl AsMut<[u8]>,
    ) -> Result<(), MeasurementError> {
        obj.hash(self, out.as_mut())
    }

    pub fn output_size(&self) -> usize {
        self.block_size
    }
}

pub trait Hashable {
    fn hash(&self, hasher: &Hasher, out: &mut [u8]) -> Result<(), MeasurementError>;
}