Skip to main content

tpm2_rand/
lib.rs

1use rand_core::{CryptoRng, RngCore};
2use tss_esapi::Context;
3
4pub struct TpmRand {
5    tpm_context: Context,
6}
7
8impl TpmRand {
9    pub fn new(ctx: Context) -> Self {
10        Self { tpm_context: ctx }
11    }
12}
13
14impl RngCore for TpmRand {
15    fn next_u32(&mut self) -> u32 {
16        let random_bytes = self
17            .tpm_context
18            .get_random(4)
19            .expect("Failed to get random bytes from TPM");
20        let buf: [u8; 4] = random_bytes
21            .value()
22            .try_into()
23            .expect("Expected 4 bytes from TPM");
24        u32::from_le_bytes(buf)
25    }
26
27    fn next_u64(&mut self) -> u64 {
28        let random_bytes = self
29            .tpm_context
30            .get_random(8)
31            .expect("Failed to get random bytes from TPM");
32        let buf: [u8; 8] = random_bytes
33            .value()
34            .try_into()
35            .expect("Expected 8 bytes from TPM");
36        u64::from_le_bytes(buf)
37    }
38
39    fn fill_bytes(&mut self, dest: &mut [u8]) {
40        const MAX_TPM_RANDOM_BUF: usize = 48;
41        let mut offset = 0;
42        while offset < dest.len() {
43            let chunk_size = core::cmp::min(MAX_TPM_RANDOM_BUF, dest.len() - offset);
44            let random_bytes = self
45                .tpm_context
46                .get_random(chunk_size)
47                .expect("Failed to get random bytes from TPM");
48            let bytes = random_bytes.value();
49            dest[offset..offset + chunk_size].copy_from_slice(&bytes[..chunk_size]);
50            offset += chunk_size;
51        }
52    }
53
54    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
55        self.fill_bytes(dest);
56        Ok(())
57    }
58}
59
60impl CryptoRng for TpmRand {}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use tss_esapi::{TctiNameConf, tcti_ldr::TabrmdConfig};
66
67    #[test]
68    fn test_tpm_rand() {
69        let tcti = TctiNameConf::Tabrmd(TabrmdConfig::default());
70        let ctx = Context::new(tcti).unwrap();
71        let mut rng = TpmRand::new(ctx);
72
73        let mut buf = [0u8; 128];
74        rng.fill_bytes(&mut buf);
75        assert!(!buf.is_empty(), "Buffer should not be empty");
76
77        println!("Random bytes: {:?}", buf);
78    }
79}