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}