Skip to content

Add a trait to serialize the state of stateful structs #24

@ounsworth

Description

@ounsworth

Algorithms that implement the do_update(), do_final() pattern (hash functions, signatures, ciphers, etc) typically do so because the input could be large and could be received over the network in multiple asynchronous chunks. In some applications, it can be advantageous to be able to serialize the algorithm's internal state to a cache so that it can be resumed (potentially on a different host) when the next chunk of input arrives

This task is to add a trait for serializing an algorithm state to a byte array.

Potentially something similar to:

/// Cryptographic algorithms that implement this trait are providing a way to serialize their internal state so that they can be
/// paused and resumed at a later time, typically as part of a `do_update()`, `do_final()` flow.
trait SerializableState<const STATE_LEN: usize> {
     /// Serialize the algorithm state to a byte array; typically used to pause an algorithm in the middle of
     /// a `do_update()`, `do_final()` flow.
     ///
     /// Note that this is not intended as a mechanism for cloning stateful operations.
     /// As such, this function moves `self` so that the struct is no longer usable after its state has been serialized
     /// as an attempt to help prevent bugs and vulnerabilities related to accidental state reuse.
     /// If you are intending to clone the operational state, `.clone()` should be available for this purpose.
     ///
     /// Notes to implementers: 
     ///   * The serialized state MUST include the version of the library that produced it.
    ///    * The serialized state MUST NOT include any private key material
    ///
    /// Security Consideration:
    ///    While the serialized state does not contain the private key material, it must still be treated as sensitive
    ///    since its leakage can still lead to any number of security issues.
   fn serialize_state(self) -> [u8; STATE_LEN];


    /// Create a new instance of an algorithm struct from a serialized state; typically used to pause an algorithm in the middle of
    /// a `do_update()`, `do_final()` flow.
    ///
    /// Note that this is not intended as a mechanism for cloning stateful operations.
    /// As such, this function moves the serialized state array in order to help prevent bugs and vulnerabilities related
    /// to accidental state reuse.
    ///
    /// Notes to implementers: 
    ///    * If ever the serialization format for a given algorithm needs to be changed, this function MUST check the embedded
    ///       library version and throw [SerializationError::IncompatibleVersion] if the serialized state was produced by a version
    ///       of the library before the breaking change. The oldest version accepted MUST be documented in the corresponding docstring.
    ///       
   fn from_serialized_state(state: [u8; STATE_LEN]) -> Result<Self, SerializedStateError>;
}

enum SerializedStateError {
    CorruptState,
    IncompatibleVersion,
}

Some extra thoughts to whomever picks up this ticket:

  • As part of addressing this ticket, think through whether the proposed trait above makes sense, add it to bouncycastle-core, and impl it for all stateful algorithms.
  • The requirement to not serialize the private key might force us to redesign some of the algorithm APIs, or maybe add a from_serialized_state_with_key(state: [u8; STATE_LEN], key: &[u8; KEY_LEN]) or something.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedCould be picked up by anyone in the community
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions