@@ -7,7 +7,7 @@ use log::{debug, error, info};
77use p256:: elliptic_curve:: PrimeField ;
88use p256:: { NonZeroScalar , ProjectivePoint , Scalar , SecretKey } ;
99use pem_rfc7468:: LineEnding ;
10- use rand_chacha :: { rand_core:: SeedableRng , ChaCha20Rng } ;
10+ use rand_core:: { impls , CryptoRng , Error as RngError , RngCore } ;
1111use static_assertions as sa;
1212use std:: collections:: HashSet ;
1313use std:: {
@@ -37,7 +37,6 @@ const CAPS: Capability = Capability::all();
3737const DELEGATED_CAPS : Capability = Capability :: all ( ) ;
3838const DOMAIN : Domain = Domain :: all ( ) ;
3939const ID : Id = 0x1 ;
40- const SEED_LEN : usize = 32 ;
4140const KEY_LEN : usize = 32 ;
4241const SHARE_LEN : usize = KEY_LEN + 1 ;
4342const LABEL : & str = "backup" ;
@@ -208,24 +207,18 @@ impl Hsm {
208207 /// then put the key into the YubiHSM. The shares and the verifier are then
209208 /// returned to the caller. Generally they will then be distributed
210209 /// 'off-platform' somehow.
211- pub fn new_split_wrap ( & self ) -> Result < ( Zeroizing < SharesMax > , Verifier ) > {
210+ pub fn new_split_wrap (
211+ & mut self ,
212+ ) -> Result < ( Zeroizing < SharesMax > , Verifier ) > {
212213 info ! (
213214 "Generating wrap / backup key from HSM PRNG with label: \" {}\" " ,
214215 LABEL . to_string( )
215216 ) ;
216217 // get 32 bytes from YubiHSM PRNG
217218 // TODO: zeroize
218- let wrap_key = self . client . get_pseudo_random ( KEY_LEN ) ?;
219- let rng_seed = self . client . get_pseudo_random ( SEED_LEN ) ?;
220- let rng_seed: [ u8 ; SEED_LEN ] =
221- rng_seed. try_into ( ) . map_err ( |v : Vec < u8 > | {
222- anyhow:: anyhow!(
223- "Expected vec with {} elements, got {}" ,
224- SEED_LEN ,
225- v. len( )
226- )
227- } ) ?;
228- let mut rng = ChaCha20Rng :: from_seed ( rng_seed) ;
219+ let mut wrap_key = [ 0u8 ; KEY_LEN ] ;
220+ self . try_fill_bytes ( & mut wrap_key) ?;
221+ let wrap_key = wrap_key;
229222
230223 info ! ( "Splitting wrap key into {} shares." , LIMIT ) ;
231224 let wrap_key = SecretKey :: from_be_bytes ( & wrap_key) ?;
@@ -237,9 +230,9 @@ impl Hsm {
237230 let ( shares, verifier) = Feldman :: < THRESHOLD , LIMIT > :: split_secret :: <
238231 Scalar ,
239232 ProjectivePoint ,
240- ChaCha20Rng ,
233+ Self ,
241234 SHARE_LEN ,
242- > ( * nzs. as_ref ( ) , None , & mut rng )
235+ > ( * nzs. as_ref ( ) , None , & mut * self )
243236 . map_err ( |e| HsmError :: SplitKeyFailed { e } ) ?;
244237
245238 // put 32 random bytes into the YubiHSM as an Aes256Ccm wrap key
@@ -466,6 +459,33 @@ impl Hsm {
466459 }
467460}
468461
462+ impl RngCore for Hsm {
463+ fn next_u32 ( & mut self ) -> u32 {
464+ impls:: next_u32_via_fill ( self )
465+ }
466+ fn next_u64 ( & mut self ) -> u64 {
467+ impls:: next_u64_via_fill ( self )
468+ }
469+ fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
470+ self . try_fill_bytes ( dest)
471+ . expect ( "RNG failed to fill the provided buffer." )
472+ }
473+ fn try_fill_bytes ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , RngError > {
474+ // The yubihsm.rs client allocates memory for the bytes that we
475+ // request here. Then we copy them to the slice provided by the
476+ // caller. API impedence mismatch.
477+ let bytes = match self . client . get_pseudo_random ( dest. len ( ) ) {
478+ Ok ( b) => Ok ( b) ,
479+ Err ( e) => Err ( RngError :: new ( e) ) ,
480+ } ?;
481+ dest. copy_from_slice ( & bytes) ;
482+ Ok ( ( ) )
483+ }
484+ }
485+
486+ // This is required for Feldman::split_secret to use `Hms` as an RNG.
487+ impl CryptoRng for Hsm { }
488+
469489/// Provided a key ID and a object type this function will find the object
470490/// in the HSM and generate the appropriate KeySpec for it.
471491pub fn backup_object < P : AsRef < Path > > (
0 commit comments