| // Licensed under the Apache-2.0 license |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| //! # ECDSA Digital Signature Operations |
| //! |
| //! This module provides a comprehensive, type-safe abstraction for Elliptic Curve Digital |
| //! Signature Algorithm (ECDSA) operations. The design follows security best practices and |
| //! provides a generic interface that can work with any elliptic curve. |
| //! |
| //! ## Features |
| //! |
| //! - **Type Safety**: Generic over curve types to prevent cross-curve contamination |
| //! - **Security First**: Mandatory cryptographic RNG, proper key validation, secure memory clearing |
| //! - **No-std Compatible**: Works in embedded environments without standard library |
| //! - **Comprehensive Error Handling**: Detailed error types for proper debugging and security |
| //! - **Optional Serialization**: Flexible serialization support for software keys, with hardware key compatibility |
| //! |
| //! ## Architecture |
| //! |
| //! The module follows a trait-based design with the following key components: |
| //! |
| //! ```text |
| //! Curve (Abstract EC Parameters) |
| //! ├── DigestType: DigestAlgorithm |
| //! └── Scalar: IntoBytes + FromBytes |
| //! |
| //! Key Management |
| //! ├── PrivateKey<C>: Zeroize + Validation |
| //! ├── SerializablePrivateKey<C>: PrivateKey<C> + Serialization (optional) |
| //! ├── PublicKey<C>: Coordinate Access + Validation |
| //! └── SerializablePublicKey<C>: PublicKey<C> + Serialization (optional) |
| //! |
| //! Signatures |
| //! ├── Signature<C>: Component Access + Validation |
| //! └── SerializableSignature<C>: Signature<C> + Serialization (optional) |
| //! |
| //! Operations |
| //! ├── EcdsaKeyGen<C>: Key pair generation |
| //! ├── EcdsaSign<C>: Digital signing with RNG |
| //! └── EcdsaVerify<C>: Signature verification |
| //! |
| //! Error Handling |
| //! ├── Error: Debug → ErrorKind mapping |
| //! ├── ErrorType: Associated error types |
| //! └── ErrorKind: Common error classifications |
| //! |
| //! Key Storage Patterns |
| //! ├── Software Keys: Implement SerializablePrivateKey for persistence |
| //! ├── Hardware Keys: Implement only PrivateKey for HSM/secure enclave |
| //! └── Hybrid Systems: Mix both patterns as needed |
| //! ``` |
| //! |
| //! ## Usage Example |
| //! |
| //! ```rust,no_run |
| //! # use openprot_hal_blocking::ecdsa::*; |
| //! # use rand_core::{RngCore, CryptoRng}; |
| //! # |
| //! # fn example() -> Result<(), Box<dyn std::error::Error>> { |
| //! // This example shows both software and hardware key patterns |
| //! |
| //! // SOFTWARE KEYS (with optional serialization): |
| //! // let mut key_generator = SoftwareKeyGen::new(); |
| //! // let mut rng = YourCryptoRng::new(); |
| //! // let (private_key, public_key) = key_generator.generate_keypair(&mut rng)?; |
| //! |
| //! // Software keys can be serialized: |
| //! // let private_bytes = private_key.as_bytes(); // SerializablePrivateKey |
| //! // let public_bytes = public_key.as_bytes(); // SerializablePublicKey |
| //! |
| //! // HARDWARE KEYS (no serialization): |
| //! // let mut hsm_generator = HsmKeyGen::new(); |
| //! // let (hsm_private, hsm_public) = hsm_generator.generate_keypair(&mut rng)?; |
| //! |
| //! // Hardware keys cannot be serialized (no IntoBytes/FromBytes bounds) |
| //! // but can still be used for cryptographic operations: |
| //! // hsm_private.validate()?; // PrivateKey trait method |
| //! |
| //! // Both key types work the same for crypto operations: |
| //! // let mut signer = YourSignerImpl::new(); |
| //! // let message_digest = your_hash_function(message); |
| //! // let signature = signer.sign(&private_key, &message_digest, &mut rng)?; |
| //! // let signature_hsm = signer.sign(&hsm_private, &message_digest, &mut rng)?; |
| //! |
| //! # Ok(()) |
| //! # } |
| //! ``` |
| //! |
| //! ## Security Considerations |
| //! |
| //! - **Always validate inputs**: Use the `validate()` methods on keys and signatures |
| //! - **Use cryptographic RNG**: Only `CryptoRng + RngCore` is accepted for signing |
| //! - **Clear sensitive data**: Private keys implement `Zeroize` for secure memory clearing |
| //! - **Hardware key support**: Private keys can be non-serializable for HSM/secure enclave use |
| //! - **Constant-time operations**: Implementers should use constant-time algorithms where possible |
| //! - **Side-channel protection**: Be aware of timing attacks in verification operations |
| |
| use crate::digest::DigestAlgorithm; |
| use core::fmt::Debug; |
| use zerocopy::Immutable; |
| use zerocopy::{FromBytes, IntoBytes}; |
| use zeroize::Zeroize; |
| /// Trait for converting implementation-specific ECDSA errors into generic error kinds. |
| /// |
| /// This trait allows HAL implementations to define their own detailed error types |
| /// while still providing a common interface for generic code to handle errors. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// # use openprot_hal_blocking::ecdsa::{Error, ErrorKind}; |
| /// #[derive(Debug)] |
| /// enum MyEcdsaError { |
| /// HardwareFault, |
| /// InvalidParameters, |
| /// Timeout, |
| /// } |
| /// |
| /// impl Error for MyEcdsaError { |
| /// fn kind(&self) -> ErrorKind { |
| /// match self { |
| /// MyEcdsaError::HardwareFault => ErrorKind::Other, |
| /// MyEcdsaError::InvalidParameters => ErrorKind::InvalidKeyFormat, |
| /// MyEcdsaError::Timeout => ErrorKind::Busy, |
| /// } |
| /// } |
| /// } |
| /// ``` |
| pub trait Error: core::fmt::Debug { |
| /// Convert error to a generic error kind |
| /// |
| /// By using this method, errors freely defined by HAL implementations |
| /// can be converted to a set of generic errors upon which generic |
| /// code can act. |
| fn kind(&self) -> ErrorKind; |
| } |
| |
| impl Error for core::convert::Infallible { |
| fn kind(&self) -> ErrorKind { |
| match *self {} |
| } |
| } |
| |
| /// Trait for associating a type with an ECDSA error type. |
| /// |
| /// This trait is used throughout the ECDSA module to associate operations |
| /// with their specific error types while maintaining type safety. |
| /// |
| /// # Example |
| /// |
| /// ```rust |
| /// # use openprot_hal_blocking::ecdsa::{ErrorType, Error, ErrorKind}; |
| /// # #[derive(Debug)] |
| /// # enum MyError { Failed } |
| /// # impl Error for MyError { |
| /// # fn kind(&self) -> ErrorKind { ErrorKind::Other } |
| /// # } |
| /// struct MyEcdsaDevice; |
| /// |
| /// impl ErrorType for MyEcdsaDevice { |
| /// type Error = MyError; |
| /// } |
| /// ``` |
| pub trait ErrorType { |
| /// Error type. |
| type Error: Error; |
| } |
| |
| /// Error kind for ECDSA operations. |
| /// |
| /// This represents a common set of ECDSA operation errors that can occur across |
| /// different implementations. The enum is `#[non_exhaustive]` to allow for future |
| /// additions without breaking API compatibility. |
| /// |
| /// Implementations are free to define more specific or additional error types. |
| /// However, by providing a mapping to these common errors through the [`Error::kind`] |
| /// method, generic code can still react to them appropriately. |
| /// |
| /// # Security Note |
| /// |
| /// Error types should not leak sensitive information. For example, avoid |
| /// distinguishing between "key not found" and "wrong key" errors, as this |
| /// could provide timing attack vectors. |
| /// |
| /// # Examples |
| /// |
| /// ```rust |
| /// # use openprot_hal_blocking::ecdsa::ErrorKind; |
| /// # let error_kind = ErrorKind::Busy; |
| /// match error_kind { |
| /// ErrorKind::InvalidSignature => { |
| /// // Handle signature verification failure |
| /// eprintln!("Signature verification failed"); |
| /// } |
| /// ErrorKind::WeakKey => { |
| /// // Handle weak key detection |
| /// eprintln!("Weak key detected - regenerate keypair"); |
| /// } |
| /// ErrorKind::Busy => { |
| /// // Handle resource busy - retry later |
| /// eprintln!("ECDSA hardware is busy, retry later"); |
| /// } |
| /// _ => { |
| /// // Handle other errors |
| /// eprintln!("ECDSA operation failed: {:?}", error_kind); |
| /// } |
| /// } |
| /// ``` |
| #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] |
| #[non_exhaustive] |
| pub enum ErrorKind { |
| /// The operation is busy and cannot be completed |
| /// |
| /// This indicates that the hardware or implementation is currently |
| /// busy with another operation. The caller should retry later. |
| Busy, |
| |
| /// The signature is invalid |
| /// |
| /// Returned when signature verification fails. This could indicate: |
| /// - The signature was corrupted during transmission |
| /// - The signature was created with a different key |
| /// - The message was modified after signing |
| /// - The signature components (r, s) are invalid |
| InvalidSignature, |
| |
| /// Key generation failed |
| /// |
| /// Indicates that the key generation process could not complete successfully. |
| /// This might be due to insufficient entropy, hardware failures, or other |
| /// random number generation issues. |
| KeyGenError, |
| |
| /// Signing operation failed |
| /// |
| /// The signing process encountered an error. This is distinct from key |
| /// generation errors and typically indicates issues during the actual |
| /// signing computation. |
| SigningError, |
| |
| /// Invalid key format or encoding |
| /// |
| /// The provided key data could not be parsed or is in an unsupported format. |
| /// This includes issues with: |
| /// - Incorrect key length |
| /// - Invalid encoding (DER, PEM, etc.) |
| /// - Malformed key structure |
| InvalidKeyFormat, |
| |
| /// Point is not on the curve |
| /// |
| /// The provided coordinates do not represent a valid point on the specified |
| /// elliptic curve. This is a critical security check that prevents attacks |
| /// using invalid curve points. |
| InvalidPoint, |
| |
| /// Unsupported curve or algorithm |
| /// |
| /// The requested elliptic curve or algorithm parameters are not supported |
| /// by this implementation. Common reasons include: |
| /// - Curve not implemented in hardware |
| /// - Disabled curve due to security concerns |
| /// - Incompatible curve parameters |
| UnsupportedCurve, |
| |
| /// Weak key detected (e.g., zero key, key equal to curve order) |
| /// |
| /// The key fails cryptographic strength requirements. This includes: |
| /// - Zero private keys |
| /// - Private keys equal to the curve order |
| /// - Public keys at the identity point |
| /// - Other mathematically weak keys |
| WeakKey, |
| |
| /// Other unspecified error |
| /// |
| /// A catch-all for errors that don't fit into the specific categories above. |
| /// Implementations should prefer specific error types when possible. |
| Other, |
| } |
| |
| /// Trait for ECC private keys associated with a specific curve. |
| /// |
| /// Private keys must implement secure memory clearing through the [`Zeroize`] trait |
| /// to ensure cryptographic material is properly destroyed when no longer needed. |
| /// |
| /// # Security Requirements |
| /// |
| /// Implementations must: |
| /// - Validate keys are within the valid scalar range (1 < key < curve_order) |
| /// - Implement constant-time operations where possible |
| /// - Clear sensitive data from memory using [`Zeroize`] |
| /// - Hardware keys may store only handles/references, not actual key material |
| /// |
| /// # Hardware Key Considerations |
| /// |
| /// For hardware-based keys (HSMs, TPMs, secure enclaves): |
| /// - The `Zeroize` implementation may clear key handles/references |
| /// - Actual key material remains securely stored in hardware |
| /// - Consider calling hardware APIs to invalidate keys during zeroization |
| /// - Some implementations may use no-op zeroization if hardware manages lifecycle |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{PrivateKey, SerializablePrivateKey, Curve, ErrorKind}; |
| /// use zeroize::Zeroize; |
| /// use zerocopy::{IntoBytes, FromBytes}; |
| /// |
| /// // Software private key (can be serialized) |
| /// #[derive(IntoBytes, FromBytes)] |
| /// struct SoftwarePrivateKey([u8; 32]); |
| /// |
| /// impl<C: Curve> PrivateKey<C> for SoftwarePrivateKey { |
| /// fn validate(&self) -> Result<(), ErrorKind> { |
| /// // Check if key is zero or equal to curve order |
| /// if self.0.iter().all(|&b| b == 0) { |
| /// return Err(ErrorKind::WeakKey); |
| /// } |
| /// Ok(()) |
| /// } |
| /// } |
| /// |
| /// // Implement optional serialization |
| /// impl<C: Curve> SerializablePrivateKey<C> for SoftwarePrivateKey {} |
| /// |
| /// // Hardware private key (cannot be serialized) |
| /// struct HardwarePrivateKey { |
| /// key_handle: u32, // Handle to key in HSM |
| /// } |
| /// |
| /// impl<C: Curve> PrivateKey<C> for HardwarePrivateKey { |
| /// fn validate(&self) -> Result<(), ErrorKind> { |
| /// // Validate key exists in hardware |
| /// // (implementation would call into HSM API) |
| /// Ok(()) |
| /// } |
| /// } |
| /// |
| /// // No SerializablePrivateKey implementation for hardware keys |
| /// ``` |
| pub trait PrivateKey<C: Curve>: Zeroize { |
| /// Validate that this private key is valid for the curve. |
| /// |
| /// This method should verify that the private key is within the valid |
| /// range for the curve (typically 1 < key < curve_order). |
| /// |
| /// # Returns |
| /// - `Ok(())`: The private key is valid |
| /// - `Err(ErrorKind::WeakKey)`: The key is zero, equal to curve order, or otherwise weak |
| /// - `Err(ErrorKind::InvalidKeyFormat)`: The key format is invalid |
| fn validate(&self, curve: &C) -> Result<(), ErrorKind>; |
| } |
| |
| /// A trait representing an abstract elliptic curve with associated types for cryptographic operations. |
| /// |
| /// This trait defines the fundamental components required for elliptic curve cryptography, |
| /// including the digest algorithm for hashing operations and the scalar field element type |
| /// for curve arithmetic. |
| /// |
| /// # Associated Types |
| /// |
| /// - [`DigestType`]: The hash function used for message digests in signing operations |
| /// - [`Scalar`]: The field element type representing curve coordinates and private keys |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{Curve, DigestAlgorithm}; |
| /// use openprot_hal_blocking::digest::Sha256; |
| /// |
| /// struct P256; |
| /// |
| /// impl Curve for P256 { |
| /// type DigestType = Sha256; |
| /// type Scalar = [u8; 32]; |
| /// } |
| /// ``` |
| /// |
| /// [`DigestType`]: Curve::DigestType |
| /// [`Scalar`]: Curve::Scalar |
| pub trait Curve { |
| /// The digest algorithm used by this elliptic curve for cryptographic operations. |
| type DigestType: DigestAlgorithm; |
| /// The scalar field element type used in elliptic curve operations. |
| type Scalar: IntoBytes + FromBytes; |
| } |
| |
| /// Trait for ECDSA signatures associated with a specific curve. |
| /// |
| /// This trait provides access to signature components and validation methods |
| /// for ECDSA signatures over elliptic curves. |
| /// |
| /// # Security Considerations |
| /// |
| /// - Signature components (r, s) must be in the range [1, curve_order) |
| /// - Zero values for r or s make the signature invalid |
| /// - Implementations should validate signatures before use |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{Signature, Curve, ErrorKind}; |
| /// |
| /// struct MySignature { |
| /// r: [u8; 32], |
| /// s: [u8; 32], |
| /// } |
| /// |
| /// impl<C: Curve> Signature<C> for MySignature { |
| /// fn from_coordinates(r: C::Scalar, s: C::Scalar) -> Result<Self, ErrorKind> { |
| /// // Validate that r and s are in valid range [1, curve_order) |
| /// if r.iter().all(|&b| b == 0) || s.iter().all(|&b| b == 0) { |
| /// return Err(ErrorKind::InvalidSignature); |
| /// } |
| /// Ok(Self { r, s }) |
| /// } |
| /// |
| /// fn coordinates(&self, r_out: &mut C::Scalar, s_out: &mut C::Scalar) { |
| /// // Zero-allocation coordinate access for embedded environments |
| /// *r_out = self.r; |
| /// *s_out = self.s; |
| /// } |
| /// } |
| /// ``` |
| pub trait Signature<C: Curve> { |
| /// Create a new signature from r and s components with validation. |
| /// |
| /// This method validates that both r and s are within the valid range |
| /// for the curve (typically 1 ≤ r,s < curve_order). |
| /// |
| /// # Parameters |
| /// - `r`: The r component of the signature |
| /// - `s`: The s component of the signature |
| /// |
| /// # Returns |
| /// - `Ok(Self)`: Valid signature |
| /// - `Err(ErrorKind::InvalidSignature)`: If r or s are invalid (zero or ≥ curve order) |
| fn from_coordinates(r: C::Scalar, s: C::Scalar) -> Result<Self, ErrorKind> |
| where |
| Self: Sized; |
| |
| /// Write coordinates to output buffers (zero-allocation for embedded). |
| /// |
| /// This method provides zero-allocation coordinate access for embedded |
| /// environments. Implementations can extract coordinates directly into |
| /// the provided buffers without temporary allocation. |
| fn coordinates(&self, x_out: &mut C::Scalar, y_out: &mut C::Scalar); |
| } |
| |
| /// A trait representing a public key associated with a specific elliptic curve. |
| /// Trait for ECC public keys associated with a specific curve. |
| /// |
| /// Public keys represent points on elliptic curves and are used for signature verification. |
| /// This trait provides coordinate access and validation methods to ensure keys represent |
| /// valid curve points. |
| /// |
| /// # Security Considerations |
| /// |
| /// - Points must lie on the specified elliptic curve |
| /// - The identity element (point at infinity) is typically invalid for cryptographic use |
| /// - Always validate public keys before using them for verification |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{PublicKey, Curve, ErrorKind}; |
| /// |
| /// struct MyPublicKey { |
| /// x: [u8; 32], |
| /// y: [u8; 32], |
| /// } |
| /// |
| /// impl<C: Curve> PublicKey<C> for MyPublicKey { |
| /// fn coordinates(&self, x_out: &mut C::Scalar, y_out: &mut C::Scalar) { |
| /// // Zero-allocation coordinate access |
| /// *x_out = self.x; |
| /// *y_out = self.y; |
| /// } |
| /// |
| /// fn from_coordinates(x: C::Scalar, y: C::Scalar) -> Result<Self, ErrorKind> { |
| /// // Validate point is on curve during construction |
| /// // (validation logic would go here) |
| /// Ok(Self { x, y }) |
| /// } |
| /// } |
| /// ``` |
| pub trait PublicKey<C: Curve> { |
| /// Write coordinates to output buffers (zero-allocation for embedded). |
| /// |
| /// This method provides zero-allocation coordinate access for embedded |
| /// environments. Implementations can extract coordinates directly into |
| /// the provided buffers without temporary allocation. |
| fn coordinates(&self, x_out: &mut C::Scalar, y_out: &mut C::Scalar); |
| |
| /// Create a new public key from x and y coordinates with validation. |
| /// |
| /// This method validates that the point (x, y) lies on the specified curve |
| /// and is cryptographically valid. Validation is performed during construction |
| /// to ensure all created public keys are valid. |
| /// |
| /// # Parameters |
| /// - `x`: The x coordinate of the point |
| /// - `y`: The y coordinate of the point |
| /// |
| /// # Returns |
| /// - `Ok(Self)`: Valid public key if the point is on the curve |
| /// - `Err(ErrorKind::InvalidPoint)`: If the point is not on the curve |
| /// - `Err(ErrorKind::WeakKey)`: If the point is the identity element |
| fn from_coordinates(x: C::Scalar, y: C::Scalar) -> Result<Self, ErrorKind> |
| where |
| Self: Sized; |
| } |
| |
| /// Optional serialization support for private keys. |
| /// |
| /// This trait provides serialization capabilities for private keys that support it, |
| /// such as software-based keys. Hardware-based keys (HSMs, secure enclaves, etc.) |
| /// do not need to implement this trait. |
| /// |
| /// # Security Note |
| /// |
| /// Implementing this trait exposes private key material as bytes. Only implement |
| /// this for software keys where serialization is appropriate and secure. |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{PrivateKey, SerializablePrivateKey, Curve}; |
| /// use zerocopy::{IntoBytes, FromBytes}; |
| /// |
| /// #[derive(IntoBytes, FromBytes)] |
| /// struct SoftwarePrivateKey([u8; 32]); |
| /// |
| /// impl<C: Curve> PrivateKey<C> for SoftwarePrivateKey { /* ... */ } |
| /// impl<C: Curve> SerializablePrivateKey<C> for SoftwarePrivateKey {} |
| /// ``` |
| pub trait SerializablePrivateKey<C: Curve>: PrivateKey<C> + IntoBytes + FromBytes {} |
| |
| /// Optional serialization support for public keys. |
| /// |
| /// This trait provides serialization capabilities for public keys that support it. |
| /// Most public key implementations should implement this since public keys are |
| /// not sensitive and often need to be transmitted or stored. |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{PublicKey, SerializablePublicKey, Curve}; |
| /// use zerocopy::{IntoBytes, FromBytes}; |
| /// |
| /// #[derive(IntoBytes, FromBytes)] |
| /// struct MyPublicKey { /* ... */ } |
| /// |
| /// impl<C: Curve> PublicKey<C> for MyPublicKey { /* ... */ } |
| /// impl<C: Curve> SerializablePublicKey<C> for MyPublicKey {} |
| /// ``` |
| pub trait SerializablePublicKey<C: Curve>: PublicKey<C> + IntoBytes + FromBytes {} |
| |
| /// Optional serialization support for signatures. |
| /// |
| /// This trait provides serialization capabilities for signatures that support it. |
| /// Most signature implementations should implement this since signatures need |
| /// to be transmitted and verified. |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{Signature, SerializableSignature, Curve}; |
| /// use zerocopy::{IntoBytes, FromBytes}; |
| /// |
| /// #[derive(IntoBytes, FromBytes)] |
| /// struct MySignature { /* ... */ } |
| /// |
| /// impl<C: Curve> Signature<C> for MySignature { /* ... */ } |
| /// impl<C: Curve> SerializableSignature<C> for MySignature {} |
| /// ``` |
| pub trait SerializableSignature<C: Curve>: Signature<C> + IntoBytes + FromBytes {} |
| |
| /// Trait for ECDSA key generation over a specific elliptic curve. |
| /// |
| /// This trait enables generation of cryptographically secure ECDSA key pairs |
| /// using a cryptographic random number generator. Keys can be generated either |
| /// as standalone objects or stored directly in a key vault for enhanced security. |
| /// |
| /// # Security Requirements |
| /// |
| /// - Must use a cryptographically secure random number generator |
| /// - Generated keys must be uniformly distributed over the valid scalar range |
| /// - Private keys must be properly zeroized after use |
| /// - Key vault storage should be preferred for hardware-backed security |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{EcdsaKeyGen, Curve, generate_and_store_keypair}; |
| /// use openprot_hal_blocking::key_vault::{KeyLifecycle, KeyStore}; |
| /// use rand_core::{RngCore, CryptoRng}; |
| /// |
| /// struct MyKeyGenerator; |
| /// |
| /// impl<C: Curve> EcdsaKeyGen<C> for MyKeyGenerator { |
| /// type PrivateKey = MyPrivateKey; |
| /// type PublicKey = MyPublicKey; |
| /// |
| /// fn generate_keypair<R>(&mut self, rng: &mut R) |
| /// -> Result<(Self::PrivateKey, Self::PublicKey), Self::Error> |
| /// where |
| /// R: RngCore + CryptoRng, |
| /// { |
| /// // Generate cryptographically secure key pair |
| /// unimplemented!() |
| /// } |
| /// } |
| /// |
| /// // Usage example with standalone function: |
| /// let mut key_gen = MyKeyGenerator; |
| /// let mut vault = MyKeyVault::new(); |
| /// let mut rng = MyRng::new(); |
| /// |
| /// let public_key = generate_and_store_keypair( |
| /// &mut key_gen, |
| /// &mut vault, |
| /// KeyId::new(42), |
| /// KeyUsage::SIGNING, |
| /// KeyMetadata::default(), |
| /// &mut rng |
| /// )?; |
| /// ``` |
| pub trait EcdsaKeyGen<C: Curve>: ErrorType { |
| /// The type representing the private key for the curve. |
| type PrivateKey: PrivateKey<C>; |
| /// The type representing the public key for the curve. |
| type PublicKey: PublicKey<C>; |
| |
| /// Generates an ECDSA key pair. |
| /// |
| /// # Parameters |
| /// - `rng`: A cryptographically secure random number generator. |
| /// |
| /// # Returns |
| /// A tuple containing the generated private key and public key. |
| fn generate_keypair<R>( |
| &mut self, |
| rng: &mut R, |
| ) -> Result<(Self::PrivateKey, Self::PublicKey), Self::Error> |
| where |
| R: rand_core::RngCore + rand_core::CryptoRng; |
| } |
| |
| /// Generates an ECDSA key pair and stores the private key in a key vault. |
| /// |
| /// This function provides integrated key generation and secure storage, ensuring |
| /// that private keys are immediately stored in a secure vault rather than |
| /// being exposed in memory. Only the public key is returned to the caller. |
| /// |
| /// # Parameters |
| /// - `key_gen`: The key generator implementation |
| /// - `vault`: The key vault for secure private key storage |
| /// - `key_id`: Unique identifier for the key in the vault |
| /// - `usage`: Usage permissions for the stored key |
| /// - `metadata`: Additional metadata to store with the key |
| /// - `rng`: A cryptographically secure random number generator |
| /// |
| /// # Returns |
| /// The generated public key (private key is securely stored in vault) |
| /// |
| /// # Security Benefits |
| /// - Private key is never exposed to caller |
| /// - Immediate secure storage reduces attack surface |
| /// - Usage permissions are set atomically with storage |
| /// - Vault locking mechanisms can be applied immediately |
| /// |
| /// # Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{generate_and_store_keypair, P256}; |
| /// use openprot_hal_blocking::key_vault::{KeyLifecycle, KeyStore}; |
| /// |
| /// let mut key_gen = MyKeyGenerator::new(); |
| /// let mut vault = MyKeyVault::new(); |
| /// let mut rng = MyRng::new(); |
| /// |
| /// let public_key = generate_and_store_keypair::<P256, _, _, _>( |
| /// &mut key_gen, |
| /// &mut vault, |
| /// KeyId::new(42), |
| /// KeyUsage::SIGNING, |
| /// KeyMetadata::default(), |
| /// &mut rng |
| /// )?; |
| /// ``` |
| pub fn generate_and_store_keypair<C, G, V, R>( |
| key_gen: &mut G, |
| vault: &mut V, |
| key_id: <V as crate::key_vault::KeyStore>::KeyId, |
| usage: <V as crate::key_vault::KeyStore>::KeyUsage, |
| metadata: <V as crate::key_vault::KeyLifecycle>::KeyMetadata, |
| rng: &mut R, |
| ) -> Result<G::PublicKey, G::Error> |
| where |
| C: Curve, |
| G: EcdsaKeyGen<C>, |
| R: rand_core::RngCore + rand_core::CryptoRng, |
| V: crate::key_vault::KeyLifecycle<KeyData = G::PrivateKey> + crate::key_vault::KeyStore, |
| <V as crate::key_vault::KeyLifecycle>::KeyId: From<<V as crate::key_vault::KeyStore>::KeyId>, |
| G::Error: From<V::Error>, |
| { |
| // Generate key pair |
| let (private_key, public_key) = key_gen.generate_keypair(rng)?; |
| |
| // Store private key in vault with metadata |
| let lifecycle_key_id = <V as crate::key_vault::KeyLifecycle>::KeyId::from(key_id); |
| vault |
| .store_key(lifecycle_key_id, private_key, metadata) |
| .map_err(G::Error::from)?; |
| vault.set_key_usage(key_id, usage).map_err(G::Error::from)?; |
| |
| Ok(public_key) |
| } |
| |
| /// Trait for ECDSA signing using a digest algorithm. |
| /// |
| /// This trait provides ECDSA signature generation from message digests. |
| /// The digest should be produced by a cryptographically secure hash function |
| /// that matches the curve's security level. |
| /// |
| /// # Security Considerations |
| /// |
| /// - Use cryptographically secure random number generators for nonce generation |
| /// - Ensure digest length matches the curve's security level |
| /// - Private keys must be validated before use |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{EcdsaSign, Curve, PrivateKey}; |
| /// use rand_core::{RngCore, CryptoRng}; |
| /// |
| /// struct MySigner; |
| /// |
| /// impl<C: Curve> EcdsaSign<C> for MySigner { |
| /// type PrivateKey = MyPrivateKey; |
| /// type Signature = MySignature; |
| /// |
| /// fn sign<R>(&mut self, key: &Self::PrivateKey, digest: &[u8], rng: &mut R) |
| /// -> Result<Self::Signature, Self::Error> |
| /// where |
| /// R: RngCore + CryptoRng, |
| /// { |
| /// // Generate ECDSA signature |
| /// unimplemented!() |
| /// } |
| /// } |
| /// ``` |
| pub trait EcdsaSign<C: Curve>: ErrorType { |
| /// The type representing the private key for the curve. |
| type PrivateKey: PrivateKey<C>; |
| /// The type representing the signature for the curve. |
| type Signature: Signature<C>; |
| |
| /// Signs a digest produced by a compatible hash function. |
| /// |
| /// # Parameters |
| /// - `private_key`: The private key used for signing. |
| /// - `digest`: The digest output from a hash function. |
| /// - `rng`: A cryptographically secure random number generator. |
| fn sign<R>( |
| &mut self, |
| private_key: &Self::PrivateKey, |
| digest: <<C as Curve>::DigestType as DigestAlgorithm>::Digest, |
| rng: &mut R, |
| ) -> Result<Self::Signature, Self::Error> |
| where |
| R: rand_core::RngCore + rand_core::CryptoRng; |
| } |
| |
| /// Trait for ECDSA signature verification using a digest algorithm. |
| /// |
| /// This trait provides ECDSA signature verification against message digests |
| /// using public keys. Verification should be performed in constant time |
| /// where possible to prevent timing attacks. |
| /// |
| /// # Security Considerations |
| /// |
| /// - Always validate public keys before verification |
| /// - Validate signature components are within valid ranges |
| /// - Use constant-time comparison operations when possible |
| /// |
| /// # Example |
| /// |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::{EcdsaVerify, Curve, PublicKey}; |
| /// |
| /// struct MyVerifier; |
| /// |
| /// impl<C: Curve> EcdsaVerify<C> for MyVerifier { |
| /// type PublicKey = MyPublicKey; |
| /// type Signature = MySignature; |
| /// |
| /// fn verify(&mut self, key: &Self::PublicKey, digest: &[u8], signature: &Self::Signature) |
| /// -> Result<(), Self::Error> |
| /// { |
| /// // Verify ECDSA signature |
| /// unimplemented!() |
| /// } |
| /// } |
| /// ``` |
| pub trait EcdsaVerify<C: Curve>: ErrorType { |
| /// The type representing the public key for the curve. |
| type PublicKey: PublicKey<C>; |
| /// The type representing the signature for the curve. |
| type Signature: Signature<C>; |
| |
| /// Verifies a signature against a digest. |
| /// |
| /// # Parameters |
| /// - `public_key`: The public key used for verification. |
| /// - `digest`: The digest output from a hash function. |
| /// - `signature`: The signature to verify. |
| fn verify( |
| &mut self, |
| public_key: &Self::PublicKey, |
| digest: <<C as Curve>::DigestType as DigestAlgorithm>::Digest, |
| signature: &Self::Signature, |
| ) -> Result<(), Self::Error>; |
| } |
| |
| /// secp256k1 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the secp256k1 elliptic curve, widely used in |
| /// Bitcoin and other cryptocurrencies. It provides ~128-bit security level. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 256 bits |
| /// - **Security Level**: ~128 bits |
| /// - **Standard**: SEC 2 |
| /// - **Common Uses**: Bitcoin, Ethereum, cryptocurrency applications |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::Secp256k1; |
| /// |
| /// // Type-safe key generation for secp256k1 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(Secp256k1)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct Secp256k1; |
| |
| impl Curve for Secp256k1 { |
| type DigestType = crate::digest::Sha2_256; |
| type Scalar = [u8; 32]; |
| } |
| |
| /// NIST P-256 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the NIST P-256 elliptic curve (secp256r1). |
| /// This is the most widely used elliptic curve for ECDSA, providing ~128-bit security. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 256 bits |
| /// - **Security Level**: ~128 bits |
| /// - **Standard**: FIPS 186-4, RFC 5480 |
| /// - **Common Uses**: TLS certificates, JWT signing, general-purpose cryptography |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::P256; |
| /// |
| /// // Type-safe key generation for P-256 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(P256)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct P256; |
| |
| impl Curve for P256 { |
| type DigestType = crate::digest::Sha2_256; |
| type Scalar = [u8; 32]; |
| } |
| |
| /// NIST P-384 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the NIST P-384 elliptic curve (secp384r1). |
| /// Provides higher security level than P-256 with ~192-bit security. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 384 bits |
| /// - **Security Level**: ~192 bits |
| /// - **Standard**: FIPS 186-4, RFC 5480 |
| /// - **Common Uses**: High-security applications, government systems |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::P384; |
| /// |
| /// // Type-safe key generation for P-384 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(P384)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct P384; |
| |
| impl Curve for P384 { |
| type DigestType = crate::digest::Sha2_384; |
| type Scalar = [u8; 48]; |
| } |
| |
| /// A serializable public key for the P384 elliptic curve. |
| /// |
| /// This implementation provides both coordinate access and serialization |
| /// capabilities for P384 public keys, supporting the standard 96-byte |
| /// uncompressed format (48 bytes each for x and y coordinates). |
| #[derive(Clone, Debug, IntoBytes, FromBytes, Immutable)] |
| #[repr(C)] |
| pub struct P384PublicKey { |
| /// X coordinate (48 bytes for P384) |
| x: [u8; 48], |
| /// Y coordinate (48 bytes for P384) |
| y: [u8; 48], |
| } |
| |
| impl P384PublicKey { |
| /// Create a new P384 public key from raw coordinates |
| pub fn new(x: [u8; 48], y: [u8; 48]) -> Self { |
| Self { x, y } |
| } |
| } |
| |
| impl PublicKey<P384> for P384PublicKey { |
| fn coordinates( |
| &self, |
| x_out: &mut <P384 as Curve>::Scalar, |
| y_out: &mut <P384 as Curve>::Scalar, |
| ) { |
| // P384::Scalar is [u8; 48], so we can copy directly |
| *x_out = self.x; |
| *y_out = self.y; |
| } |
| |
| fn from_coordinates( |
| x: <P384 as Curve>::Scalar, |
| y: <P384 as Curve>::Scalar, |
| ) -> Result<Self, ErrorKind> { |
| Ok(Self::new(x, y)) |
| } |
| } |
| |
| impl SerializablePublicKey<P384> for P384PublicKey {} |
| |
| /// A serializable signature for the P384 elliptic curve. |
| /// |
| /// This implementation provides both signature validation and serialization |
| /// capabilities for P384 ECDSA signatures, supporting the standard 96-byte |
| /// format (48 bytes each for r and s components). |
| #[derive(Clone, Debug, IntoBytes, FromBytes, Immutable)] |
| #[repr(C)] |
| pub struct P384Signature { |
| /// R component (48 bytes for P384) |
| r: [u8; 48], |
| /// S component (48 bytes for P384) |
| s: [u8; 48], |
| } |
| |
| impl P384Signature { |
| /// Create a new P384 signature from r and s components |
| pub fn new(r: [u8; 48], s: [u8; 48]) -> Self { |
| Self { r, s } |
| } |
| } |
| |
| impl Signature<P384> for P384Signature { |
| fn from_coordinates( |
| r: <P384 as Curve>::Scalar, |
| s: <P384 as Curve>::Scalar, |
| ) -> Result<Self, ErrorKind> { |
| // TODO: Add proper signature validation here |
| // For now, we accept any r,s values but in a real implementation |
| // we should validate that 1 ≤ r,s < curve_order |
| Ok(Self::new(r, s)) |
| } |
| |
| fn coordinates( |
| &self, |
| r_out: &mut <P384 as Curve>::Scalar, |
| s_out: &mut <P384 as Curve>::Scalar, |
| ) { |
| // P384::Scalar is [u8; 48], so we can copy directly |
| *r_out = self.r; |
| *s_out = self.s; |
| } |
| } |
| |
| impl SerializableSignature<P384> for P384Signature {} |
| |
| /// NIST P-521 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the NIST P-521 elliptic curve (secp521r1). |
| /// Provides maximum security among NIST curves with ~256-bit security. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 521 bits |
| /// - **Security Level**: ~256 bits |
| /// - **Standard**: FIPS 186-4, RFC 5480 |
| /// - **Common Uses**: Maximum security applications, long-term archival |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::P521; |
| /// |
| /// // Type-safe key generation for P-521 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(P521)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct P521; |
| |
| impl Curve for P521 { |
| type DigestType = crate::digest::Sha2_512; |
| type Scalar = [u8; 66]; |
| } |
| |
| /// Brainpool P256r1 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the Brainpool P256r1 elliptic curve. |
| /// Brainpool curves are alternative curves to NIST curves with potentially better properties. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 256 bits |
| /// - **Security Level**: ~128 bits |
| /// - **Standard**: RFC 5639 |
| /// - **Common Uses**: Alternative to NIST curves, European standards |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::BrainpoolP256r1; |
| /// |
| /// // Type-safe key generation for Brainpool P256r1 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(BrainpoolP256r1)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct BrainpoolP256r1; |
| |
| impl Curve for BrainpoolP256r1 { |
| type DigestType = crate::digest::Sha2_256; |
| type Scalar = [u8; 32]; |
| } |
| |
| /// Brainpool P384r1 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the Brainpool P384r1 elliptic curve. |
| /// Provides higher security level than P256r1 with 192-bit security. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 384 bits |
| /// - **Security Level**: ~192 bits |
| /// - **Standard**: RFC 5639 |
| /// - **Common Uses**: High-security applications, European standards |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::BrainpoolP384r1; |
| /// |
| /// // Type-safe key generation for Brainpool P384r1 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(BrainpoolP384r1)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct BrainpoolP384r1; |
| |
| impl Curve for BrainpoolP384r1 { |
| type DigestType = crate::digest::Sha2_384; |
| type Scalar = [u8; 48]; |
| } |
| |
| /// Brainpool P512r1 elliptic curve marker type. |
| /// |
| /// This zero-sized type represents the Brainpool P512r1 elliptic curve. |
| /// Provides maximum security among Brainpool curves with ~256-bit security. |
| /// |
| /// ## Parameters |
| /// - **Field Size**: 512 bits |
| /// - **Security Level**: ~256 bits |
| /// - **Standard**: RFC 5639 |
| /// - **Common Uses**: Maximum security applications, European standards |
| /// |
| /// ## Example |
| /// ```rust,ignore |
| /// use openprot_hal_blocking::ecdsa::BrainpoolP512r1; |
| /// |
| /// // Type-safe key generation for Brainpool P512r1 |
| /// let key_gen = MyKeyGenerator; |
| /// let (private_key, public_key) = key_gen.generate_keypair(BrainpoolP512r1)?; |
| /// ``` |
| #[derive(Clone, Copy, Debug)] |
| pub struct BrainpoolP512r1; |
| |
| impl Curve for BrainpoolP512r1 { |
| type DigestType = crate::digest::Sha2_512; |
| type Scalar = [u8; 64]; |
| } |