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.
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 arrivesThis task is to add a trait for serializing an algorithm state to a byte array.
Potentially something similar to:
Some extra thoughts to whomever picks up this ticket:
from_serialized_state_with_key(state: [u8; STATE_LEN], key: &[u8; KEY_LEN])or something.