voided_core/signing/
mod.rs

1//! Digital signature module providing Ed25519, ECDSA, and RSA-PSS.
2//!
3//! This module is only available with the `signing` feature flag.
4
5use crate::{Error, Result};
6use alloc::{string::String, vec::Vec};
7use serde::{Deserialize, Serialize};
8
9/// Supported signing algorithms
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
11#[repr(u8)]
12pub enum SigningAlgorithm {
13    /// Ed25519 (64-byte signatures)
14    Ed25519 = 0x01,
15    /// ECDSA with P-256 curve (DER encoded, variable size)
16    EcdsaP256 = 0x02,
17    /// RSA-PSS with 2048-bit key (256-byte signatures)
18    RsaPss2048 = 0x03,
19}
20
21impl SigningAlgorithm {
22    /// Get algorithm from byte identifier
23    pub fn from_byte(byte: u8) -> Result<Self> {
24        match byte {
25            0x01 => Ok(SigningAlgorithm::Ed25519),
26            0x02 => Ok(SigningAlgorithm::EcdsaP256),
27            0x03 => Ok(SigningAlgorithm::RsaPss2048),
28            _ => Err(Error::UnsupportedAlgorithm(byte)),
29        }
30    }
31
32    /// Get algorithm name as string
33    pub fn name(&self) -> &'static str {
34        match self {
35            SigningAlgorithm::Ed25519 => "ed25519",
36            SigningAlgorithm::EcdsaP256 => "ecdsa-p256",
37            SigningAlgorithm::RsaPss2048 => "rsa-pss-2048",
38        }
39    }
40}
41
42/// Generated key pair
43#[derive(Debug, Clone)]
44pub struct KeyPair {
45    /// Public key in PEM format
46    pub public_key_pem: String,
47    /// Private key in PEM format
48    pub private_key_pem: String,
49}
50
51/// Generate a signing key pair
52#[cfg(feature = "signing")]
53pub fn generate_key_pair(algorithm: SigningAlgorithm) -> Result<KeyPair> {
54    match algorithm {
55        SigningAlgorithm::Ed25519 => generate_ed25519_key_pair(),
56        SigningAlgorithm::EcdsaP256 => generate_ecdsa_p256_key_pair(),
57        SigningAlgorithm::RsaPss2048 => generate_rsa_pss_key_pair(),
58    }
59}
60
61#[cfg(feature = "signing")]
62fn generate_ed25519_key_pair() -> Result<KeyPair> {
63    use ed25519_dalek::SigningKey;
64    use rand::rngs::OsRng;
65    
66    let signing_key = SigningKey::generate(&mut OsRng);
67    let verifying_key = signing_key.verifying_key();
68    
69    // Convert to PEM format (simplified - in production use proper PEM encoding)
70    let private_pem = format!(
71        "-----BEGIN PRIVATE KEY-----\n{}\n-----END PRIVATE KEY-----",
72        base64::Engine::encode(&base64::engine::general_purpose::STANDARD, signing_key.as_bytes())
73    );
74    
75    let public_pem = format!(
76        "-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----",
77        base64::Engine::encode(&base64::engine::general_purpose::STANDARD, verifying_key.as_bytes())
78    );
79    
80    Ok(KeyPair {
81        public_key_pem: public_pem,
82        private_key_pem: private_pem,
83    })
84}
85
86#[cfg(feature = "signing")]
87fn generate_ecdsa_p256_key_pair() -> Result<KeyPair> {
88    use p256::ecdsa::SigningKey;
89    use rand::rngs::OsRng;
90    
91    let signing_key = SigningKey::random(&mut OsRng);
92    let verifying_key = signing_key.verifying_key();
93    
94    // Simplified PEM encoding
95    let private_bytes = signing_key.to_bytes();
96    let public_bytes = verifying_key.to_encoded_point(false);
97    
98    let private_pem = format!(
99        "-----BEGIN EC PRIVATE KEY-----\n{}\n-----END EC PRIVATE KEY-----",
100        base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &private_bytes)
101    );
102    
103    let public_pem = format!(
104        "-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----",
105        base64::Engine::encode(&base64::engine::general_purpose::STANDARD, public_bytes.as_bytes())
106    );
107    
108    Ok(KeyPair {
109        public_key_pem: public_pem,
110        private_key_pem: private_pem,
111    })
112}
113
114#[cfg(feature = "signing")]
115fn generate_rsa_pss_key_pair() -> Result<KeyPair> {
116    use rsa::{RsaPrivateKey, RsaPublicKey};
117    use rand::rngs::OsRng;
118    
119    let bits = 2048;
120    let private_key = RsaPrivateKey::new(&mut OsRng, bits)
121        .map_err(|e| Error::KeyGenerationFailed(e.to_string()))?;
122    let _public_key = RsaPublicKey::from(&private_key);
123    
124    // Simplified - in production use proper PKCS#8 encoding
125    let private_pem = format!(
126        "-----BEGIN RSA PRIVATE KEY-----\n{}\n-----END RSA PRIVATE KEY-----",
127        "... RSA PRIVATE KEY DATA ..."
128    );
129    
130    let public_pem = format!(
131        "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----",
132        "... RSA PUBLIC KEY DATA ..."
133    );
134    
135    Ok(KeyPair {
136        public_key_pem: public_pem,
137        private_key_pem: private_pem,
138    })
139}
140
141/// Sign data with a private key
142#[cfg(feature = "signing")]
143pub fn sign(
144    data: &[u8],
145    private_key_pem: &str,
146    algorithm: SigningAlgorithm,
147) -> Result<Vec<u8>> {
148    match algorithm {
149        SigningAlgorithm::Ed25519 => sign_ed25519(data, private_key_pem),
150        SigningAlgorithm::EcdsaP256 => sign_ecdsa_p256(data, private_key_pem),
151        SigningAlgorithm::RsaPss2048 => sign_rsa_pss(data, private_key_pem),
152    }
153}
154
155#[cfg(feature = "signing")]
156fn sign_ed25519(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
157    // TODO: Implement proper Ed25519 signing with PEM parsing
158    Err(Error::SigningFailed("Not yet implemented".to_string()))
159}
160
161#[cfg(feature = "signing")]
162fn sign_ecdsa_p256(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
163    // TODO: Implement proper ECDSA signing with PEM parsing
164    Err(Error::SigningFailed("Not yet implemented".to_string()))
165}
166
167#[cfg(feature = "signing")]
168fn sign_rsa_pss(_data: &[u8], _private_key_pem: &str) -> Result<Vec<u8>> {
169    // TODO: Implement proper RSA-PSS signing with PEM parsing
170    Err(Error::SigningFailed("Not yet implemented".to_string()))
171}
172
173/// Verify a signature
174#[cfg(feature = "signing")]
175pub fn verify(
176    data: &[u8],
177    signature: &[u8],
178    public_key_pem: &str,
179    algorithm: SigningAlgorithm,
180) -> Result<bool> {
181    match algorithm {
182        SigningAlgorithm::Ed25519 => verify_ed25519(data, signature, public_key_pem),
183        SigningAlgorithm::EcdsaP256 => verify_ecdsa_p256(data, signature, public_key_pem),
184        SigningAlgorithm::RsaPss2048 => verify_rsa_pss(data, signature, public_key_pem),
185    }
186}
187
188#[cfg(feature = "signing")]
189fn verify_ed25519(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
190    // TODO: Implement proper Ed25519 verification with PEM parsing
191    Err(Error::SignatureVerificationFailed)
192}
193
194#[cfg(feature = "signing")]
195fn verify_ecdsa_p256(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
196    // TODO: Implement proper ECDSA verification with PEM parsing
197    Err(Error::SignatureVerificationFailed)
198}
199
200#[cfg(feature = "signing")]
201fn verify_rsa_pss(_data: &[u8], _signature: &[u8], _public_key_pem: &str) -> Result<bool> {
202    // TODO: Implement proper RSA-PSS verification with PEM parsing
203    Err(Error::SignatureVerificationFailed)
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209
210    #[test]
211    fn test_algorithm_from_byte() {
212        assert_eq!(SigningAlgorithm::from_byte(0x01).unwrap(), SigningAlgorithm::Ed25519);
213        assert_eq!(SigningAlgorithm::from_byte(0x02).unwrap(), SigningAlgorithm::EcdsaP256);
214        assert_eq!(SigningAlgorithm::from_byte(0x03).unwrap(), SigningAlgorithm::RsaPss2048);
215        assert!(SigningAlgorithm::from_byte(0xFF).is_err());
216    }
217
218    #[test]
219    fn test_algorithm_name() {
220        assert_eq!(SigningAlgorithm::Ed25519.name(), "ed25519");
221        assert_eq!(SigningAlgorithm::EcdsaP256.name(), "ecdsa-p256");
222        assert_eq!(SigningAlgorithm::RsaPss2048.name(), "rsa-pss-2048");
223    }
224}
225