@@ -7,6 +7,7 @@ use crate::{
77 Errno , HostInterface , arch:: ioport:: serial_print_string,
88 host:: per_cpu_variables:: with_per_cpu_variables,
99} ;
10+ use digest:: Digest ;
1011use rand_core:: { RngCore , SeedableRng } ;
1112use zeroize:: Zeroizing ;
1213
@@ -104,13 +105,67 @@ unsafe impl litebox::platform::ThreadLocalStorageProvider for LvbsLinuxKernel {
104105
105106impl litebox:: platform:: CrngProvider for LvbsLinuxKernel {
106107 fn fill_bytes_crng ( & self , buf : & mut [ u8 ] ) {
107- static RANDOM : spin:: mutex:: SpinMutex < Option < rand_chacha:: ChaCha20Rng > > =
108- spin:: mutex:: SpinMutex :: new ( None ) ;
108+ static RANDOM : spin:: mutex:: SpinMutex < Option < LvbsCrng > > = spin:: mutex:: SpinMutex :: new ( None ) ;
109109
110110 let mut random = RANDOM . lock ( ) ;
111111 random
112- . get_or_insert_with ( || rand_chacha:: ChaCha20Rng :: from_seed ( rdrand_seed ( ) ) )
113- . fill_bytes ( buf) ;
112+ . get_or_insert_with ( || LvbsCrng :: new ( PRK_ONCE . wait ( ) , rdrand_seed ( ) ) )
113+ . fill_bytes ( buf, rdrand_seed) ;
114+ }
115+ }
116+
117+ const CRNG_RESEED_INTERVAL_BYTES : usize = 1024 * 1024 ;
118+ const CRNG_RESEED_STATE_BYTES : usize = 32 ;
119+
120+ struct LvbsCrng {
121+ random : rand_chacha:: ChaCha20Rng ,
122+ bytes_until_reseed : usize ,
123+ reseed_counter : usize ,
124+ }
125+
126+ impl LvbsCrng {
127+ fn new (
128+ prk : & [ u8 ; PRK_LEN ] ,
129+ rdrand_seed : <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed ,
130+ ) -> Self {
131+ Self {
132+ random : rand_chacha:: ChaCha20Rng :: from_seed ( crng_seed_from_prk_and_rdrand (
133+ prk,
134+ rdrand_seed,
135+ ) ) ,
136+ bytes_until_reseed : CRNG_RESEED_INTERVAL_BYTES ,
137+ reseed_counter : 0 ,
138+ }
139+ }
140+
141+ fn fill_bytes (
142+ & mut self ,
143+ mut buf : & mut [ u8 ] ,
144+ rdrand_seed : impl Fn ( ) -> <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed ,
145+ ) {
146+ while !buf. is_empty ( ) {
147+ let len = buf. len ( ) . min ( self . bytes_until_reseed ) ;
148+ let ( chunk, rest) = buf. split_at_mut ( len) ;
149+ self . random . fill_bytes ( chunk) ;
150+ buf = rest;
151+ self . bytes_until_reseed -= len;
152+
153+ if self . bytes_until_reseed == 0 {
154+ self . reseed ( rdrand_seed ( ) ) ;
155+ }
156+ }
157+ }
158+
159+ fn reseed ( & mut self , rdrand_seed : <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed ) {
160+ self . reseed_counter += 1 ;
161+ let mut current_state = Zeroizing :: new ( [ 0u8 ; CRNG_RESEED_STATE_BYTES ] ) ;
162+ self . random . fill_bytes ( & mut * current_state) ;
163+ self . random = rand_chacha:: ChaCha20Rng :: from_seed ( crng_reseed_from_rdrand_and_state (
164+ rdrand_seed,
165+ self . reseed_counter ,
166+ & current_state,
167+ ) ) ;
168+ self . bytes_until_reseed = CRNG_RESEED_INTERVAL_BYTES ;
114169 }
115170}
116171
@@ -152,6 +207,30 @@ fn rdrand_seed() -> <rand_chacha::ChaCha20Rng as SeedableRng>::Seed {
152207 seed
153208}
154209
210+ fn crng_seed_from_prk_and_rdrand (
211+ prk : & [ u8 ; PRK_LEN ] ,
212+ rdrand_seed : <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed ,
213+ ) -> <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed {
214+ let mut hasher = sha2:: Sha256 :: new ( ) ;
215+ hasher. update ( b"litebox-lvbs-crng-seed-v1" ) ;
216+ hasher. update ( prk) ;
217+ hasher. update ( rdrand_seed) ;
218+ hasher. finalize ( ) . into ( )
219+ }
220+
221+ fn crng_reseed_from_rdrand_and_state (
222+ rdrand_seed : <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed ,
223+ reseed_counter : usize ,
224+ current_state : & [ u8 ; CRNG_RESEED_STATE_BYTES ] ,
225+ ) -> <rand_chacha:: ChaCha20Rng as SeedableRng >:: Seed {
226+ let mut hasher = sha2:: Sha256 :: new ( ) ;
227+ hasher. update ( b"litebox-lvbs-crng-reseed-v1" ) ;
228+ hasher. update ( rdrand_seed) ;
229+ hasher. update ( reseed_counter. to_le_bytes ( ) ) ;
230+ hasher. update ( current_state) ;
231+ hasher. finalize ( ) . into ( )
232+ }
233+
155234pub struct HostLvbsInterface ;
156235
157236impl HostLvbsInterface { }
0 commit comments