@@ -26,7 +26,7 @@ use openprot_hal_blocking::{
2626/// Hubris IPC error codes for inter-task communication.
2727#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
2828pub enum HubrisCryptoError {
29- /// Invalid key length for the requested operation333
29+ /// Invalid key length for the requested operation
3030 InvalidKeyLength ,
3131 /// Hardware crypto accelerator failure
3232 HardwareFailure ,
@@ -36,6 +36,129 @@ pub enum HubrisCryptoError {
3636 ResourceBusy ,
3737 /// Operation not supported by hardware
3838 NotSupported ,
39+ /// Session state error (context or device missing)
40+ SessionStateError ,
41+ }
42+
43+ /// RAII-style crypto session management
44+ ///
45+ /// This type provides RAII-style resource management for crypto devices used in
46+ /// session-based operations. It ensures that crypto hardware devices are properly
47+ /// recovered and can be reused after operations complete.
48+ ///
49+ /// The CryptoSession handles the fundamental constraint that hardware controllers
50+ /// cannot be cloned, providing a mechanism for device recovery that works with
51+ /// both software implementations (which can create new instances) and hardware
52+ /// controllers (which require different recovery strategies).
53+ ///
54+ /// ## Design Rationale
55+ ///
56+ /// Session-based crypto operations consume the device when creating contexts,
57+ /// but we need to recover the device for reuse. This type solves that by:
58+ /// 1. Storing both the crypto context and a recovery device
59+ /// 2. Providing update/finalize methods that manage the context lifecycle
60+ /// 3. Returning the recovered device when the session completes
61+ ///
62+ /// ## Usage Pattern
63+ ///
64+ /// ```rust,ignore
65+ /// let session = device.init_digest_session_sha256()?;
66+ /// let session = session.update(b"data")?;
67+ /// let (result, recovered_device) = session.finalize()?;
68+ /// // recovered_device can now be used for new operations
69+ /// ```
70+ pub struct CryptoSession < Context , Device > {
71+ context : Option < Context > ,
72+ device : Option < Device > ,
73+ }
74+
75+ impl < Context , Device > CryptoSession < Context , Device > {
76+ /// Create a new crypto session with the given context and recovery device
77+ pub fn new ( context : Context , device : Device ) -> Self {
78+ Self {
79+ context : Some ( context) ,
80+ device : Some ( device) ,
81+ }
82+ }
83+
84+ /// Take the context out of the session (for move operations)
85+ fn take_context ( & mut self ) -> Result < Context , HubrisCryptoError > {
86+ self . context
87+ . take ( )
88+ . ok_or ( HubrisCryptoError :: SessionStateError )
89+ }
90+
91+ /// Put a context back into the session (after move operations)
92+ fn put_context ( & mut self , context : Context ) {
93+ self . context = Some ( context) ;
94+ }
95+
96+ /// Update the session with new data
97+ ///
98+ /// This method uses move semantics to update the context while maintaining
99+ /// the device for recovery.
100+ pub fn update ( mut self , data : & [ u8 ] ) -> Result < Self , HubrisCryptoError >
101+ where
102+ Context : DigestOp < Controller = Device > ,
103+ {
104+ let context = self . take_context ( ) ?;
105+ let updated_context = context
106+ . update ( data)
107+ . map_err ( |_| HubrisCryptoError :: HardwareFailure ) ?;
108+ self . put_context ( updated_context) ;
109+ Ok ( self )
110+ }
111+
112+ /// Finalize the digest session and recover the device
113+ ///
114+ /// Returns the computed result and the device for reuse.
115+ pub fn finalize ( mut self ) -> Result < ( Context :: Output , Device ) , HubrisCryptoError >
116+ where
117+ Context : DigestOp < Controller = Device > ,
118+ {
119+ let context = self . take_context ( ) ?;
120+ let ( output, _controller) = context
121+ . finalize ( )
122+ . map_err ( |_| HubrisCryptoError :: HardwareFailure ) ?;
123+
124+ // Recover our device from the session
125+ let device = self
126+ . device
127+ . take ( )
128+ . ok_or ( HubrisCryptoError :: SessionStateError ) ?;
129+ Ok ( ( output, device) )
130+ }
131+
132+ /// Update the MAC session with new data
133+ pub fn update_mac ( mut self , data : & [ u8 ] ) -> Result < Self , HubrisCryptoError >
134+ where
135+ Context : MacOp < Controller = Device > ,
136+ {
137+ let context = self . take_context ( ) ?;
138+ let updated_context = context
139+ . update ( data)
140+ . map_err ( |_| HubrisCryptoError :: HardwareFailure ) ?;
141+ self . put_context ( updated_context) ;
142+ Ok ( self )
143+ }
144+
145+ /// Finalize the MAC session and recover the device
146+ pub fn finalize_mac ( mut self ) -> Result < ( Context :: Output , Device ) , HubrisCryptoError >
147+ where
148+ Context : MacOp < Controller = Device > ,
149+ {
150+ let context = self . take_context ( ) ?;
151+ let ( output, _controller) = context
152+ . finalize ( )
153+ . map_err ( |_| HubrisCryptoError :: HardwareFailure ) ?;
154+
155+ // Recover our device from the session
156+ let device = self
157+ . device
158+ . take ( )
159+ . ok_or ( HubrisCryptoError :: SessionStateError ) ?;
160+ Ok ( ( output, device) )
161+ }
39162}
40163
41164/// Hubrus-specific digest device trait
@@ -108,11 +231,57 @@ pub trait HubrisDigestDevice {
108231 /// - Validates key size against device limits
109232 /// - Ensures compatibility with task memory constraints
110233 fn create_hmac_key ( data : & [ u8 ] ) -> Result < Self :: HmacKey , HubrisCryptoError > {
111- if data. len ( ) > Self :: MAX_KEY_SIZE {
112- return Err ( HubrisCryptoError :: InvalidKeyLength ) ;
113- }
114234 Self :: HmacKey :: try_from ( data) . map_err ( |_| HubrisCryptoError :: InvalidKeyLength )
115235 }
236+
237+ // Session methods for digest operations
238+
239+ /// Initialize SHA-256 digest session with device recovery
240+ fn init_digest_session_sha256 (
241+ self ,
242+ ) -> Result < CryptoSession < Self :: DigestContext256 , Self > , HubrisCryptoError >
243+ where
244+ Self : Sized ;
245+
246+ /// Initialize SHA-384 digest session with device recovery
247+ fn init_digest_session_sha384 (
248+ self ,
249+ ) -> Result < CryptoSession < Self :: DigestContext384 , Self > , HubrisCryptoError >
250+ where
251+ Self : Sized ;
252+
253+ /// Initialize SHA-512 digest session with device recovery
254+ fn init_digest_session_sha512 (
255+ self ,
256+ ) -> Result < CryptoSession < Self :: DigestContext512 , Self > , HubrisCryptoError >
257+ where
258+ Self : Sized ;
259+
260+ // Session methods for HMAC operations
261+
262+ /// Initialize HMAC-SHA256 session with device recovery
263+ fn init_hmac_session_sha256 (
264+ self ,
265+ key : Self :: HmacKey ,
266+ ) -> Result < CryptoSession < Self :: HmacContext256 , Self > , HubrisCryptoError >
267+ where
268+ Self : Sized ;
269+
270+ /// Initialize HMAC-SHA384 session with device recovery
271+ fn init_hmac_session_sha384 (
272+ self ,
273+ key : Self :: HmacKey ,
274+ ) -> Result < CryptoSession < Self :: HmacContext384 , Self > , HubrisCryptoError >
275+ where
276+ Self : Sized ;
277+
278+ /// Initialize HMAC-SHA512 session with device recovery
279+ fn init_hmac_session_sha512 (
280+ self ,
281+ key : Self :: HmacKey ,
282+ ) -> Result < CryptoSession < Self :: HmacContext512 , Self > , HubrisCryptoError >
283+ where
284+ Self : Sized ;
116285}
117286
118287/// Extension trait for one-shot operations in Hubris
0 commit comments