ant_quic/crypto/
raw_keys.rs

1//! Raw Public Key Support
2//!
3//! This module implements support for Ed25519 keys in SubjectPublicKeyInfo format
4//! as specified in RFC 7250. It provides functionality for key generation, encoding,
5//! and verification with a focus on simplicity and performance.
6
7use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
8use rand::rngs::OsRng;
9use thiserror::Error;
10
11/// Errors that can occur during raw public key operations
12#[derive(Debug, Error)]
13pub enum RawKeyError {
14    #[error("Invalid key format: {0}")]
15    InvalidFormat(String),
16
17    #[error("Verification failed")]
18    VerificationFailed,
19
20    #[error("Encoding error: {0}")]
21    EncodingError(String),
22
23    #[error("Decoding error: {0}")]
24    DecodingError(String),
25}
26
27/// Ed25519 key pair for authentication
28#[derive(Clone, Debug)]
29pub struct Ed25519KeyPair {
30    signing_key: SigningKey,
31    verifying_key: VerifyingKey,
32}
33
34impl Ed25519KeyPair {
35    /// Generate a new random Ed25519 key pair
36    pub fn generate() -> Self {
37        let signing_key = SigningKey::generate(&mut OsRng);
38        let verifying_key = VerifyingKey::from(&signing_key);
39
40        Self {
41            signing_key,
42            verifying_key,
43        }
44    }
45
46    /// Create a key pair from an existing signing key
47    pub fn from_signing_key(signing_key: SigningKey) -> Self {
48        let verifying_key = VerifyingKey::from(&signing_key);
49        Self {
50            signing_key,
51            verifying_key,
52        }
53    }
54
55    /// Get the public key in SubjectPublicKeyInfo format
56    pub fn public_key_spki(&self) -> Vec<u8> {
57        create_ed25519_subject_public_key_info(&self.verifying_key)
58    }
59
60    /// Get the raw public key bytes
61    pub fn public_key_bytes(&self) -> [u8; 32] {
62        *self.verifying_key.as_bytes()
63    }
64
65    /// Get a reference to the verifying key
66    pub fn verifying_key(&self) -> &VerifyingKey {
67        &self.verifying_key
68    }
69
70    /// Sign data with the private key
71    pub fn sign(&self, data: &[u8]) -> Signature {
72        self.signing_key.sign(data)
73    }
74
75    /// Verify a signature with the public key
76    pub fn verify(&self, data: &[u8], signature: &Signature) -> Result<(), RawKeyError> {
77        self.verifying_key
78            .verify(data, signature)
79            .map_err(|_| RawKeyError::VerificationFailed)
80    }
81}
82
83/// Create a SubjectPublicKeyInfo DER encoding for an Ed25519 public key
84///
85/// This function creates a minimal DER encoding of the SubjectPublicKeyInfo
86/// structure containing an Ed25519 public key as specified in RFC 5280 and RFC 8410.
87pub fn create_ed25519_subject_public_key_info(public_key: &VerifyingKey) -> Vec<u8> {
88    // Ed25519 SubjectPublicKeyInfo structure:
89    // SEQUENCE {
90    //   SEQUENCE {
91    //     OBJECT IDENTIFIER 1.3.101.112 (Ed25519)
92    //   }
93    //   BIT STRING (32 bytes of public key)
94    // }
95
96    // Pre-allocate the exact size needed (44 bytes)
97    let mut spki = Vec::with_capacity(44);
98
99    // SEQUENCE tag and length (total length will be 44 bytes)
100    spki.extend_from_slice(&[0x30, 0x2a]);
101
102    // Algorithm identifier SEQUENCE
103    spki.extend_from_slice(&[0x30, 0x05]);
104
105    // Ed25519 OID: 1.3.101.112
106    spki.extend_from_slice(&[0x06, 0x03, 0x2b, 0x65, 0x70]);
107
108    // Subject public key BIT STRING
109    spki.extend_from_slice(&[0x03, 0x21, 0x00]); // BIT STRING, 33 bytes (32 + 1 unused bits byte)
110
111    // The actual 32-byte Ed25519 public key
112    spki.extend_from_slice(public_key.as_bytes());
113
114    spki
115}
116
117/// Extract an Ed25519 public key from SubjectPublicKeyInfo format
118///
119/// This function extracts the raw 32-byte Ed25519 public key from a
120/// SubjectPublicKeyInfo structure as specified in RFC 5280 and RFC 8410.
121pub fn extract_ed25519_key_from_spki(spki_der: &[u8]) -> Result<[u8; 32], RawKeyError> {
122    // Simple parsing for Ed25519 SubjectPublicKeyInfo
123    if spki_der.len() != 44 {
124        return Err(RawKeyError::InvalidFormat(format!(
125            "Invalid SPKI length: expected 44 bytes, got {}",
126            spki_der.len()
127        )));
128    }
129
130    // Look for Ed25519 OID pattern in the DER encoding
131    let ed25519_oid = [0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70];
132
133    if !spki_der.starts_with(&ed25519_oid) {
134        return Err(RawKeyError::InvalidFormat(
135            "Invalid SPKI format: Ed25519 OID not found".to_string(),
136        ));
137    }
138
139    // The public key should be at offset 12 and be 32 bytes long
140    let mut public_key = [0u8; 32];
141    public_key.copy_from_slice(&spki_der[12..44]);
142
143    Ok(public_key)
144}
145
146/// Create a VerifyingKey from SubjectPublicKeyInfo format
147pub fn verifying_key_from_spki(spki_der: &[u8]) -> Result<VerifyingKey, RawKeyError> {
148    let key_bytes = extract_ed25519_key_from_spki(spki_der)?;
149    VerifyingKey::from_bytes(&key_bytes)
150        .map_err(|e| RawKeyError::InvalidFormat(format!("Invalid Ed25519 public key: {e}")))
151}
152
153/// Derive a peer ID from a public key
154///
155/// This function creates a deterministic peer ID from an Ed25519 public key
156/// using a secure hash function to ensure uniform distribution and prevent
157/// direct key exposure.
158pub fn derive_peer_id_from_public_key(public_key: &VerifyingKey) -> [u8; 32] {
159    let key_bytes = public_key.as_bytes();
160
161    // Create the input data with domain separator
162    let mut input = Vec::with_capacity(20 + 32); // "AUTONOMI_PEER_ID_V1:" + key_bytes
163    input.extend_from_slice(b"AUTONOMI_PEER_ID_V1:");
164    input.extend_from_slice(key_bytes);
165
166    #[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
167    {
168        // Use SHA-256 to hash the public key with a domain separator
169        use ring::digest::{SHA256, digest};
170
171        // Hash the input
172        let hash = digest(&SHA256, &input);
173        let hash_bytes = hash.as_ref();
174
175        let mut peer_id_bytes = [0u8; 32];
176        peer_id_bytes.copy_from_slice(hash_bytes);
177        peer_id_bytes
178    }
179
180    #[cfg(feature = "aws-lc-rs")]
181    {
182        use aws_lc_rs::digest;
183
184        // Hash the input
185        let hash = digest::digest(&digest::SHA256, &input);
186        let hash_bytes = hash.as_ref();
187
188        let mut peer_id_bytes = [0u8; 32];
189        peer_id_bytes.copy_from_slice(hash_bytes);
190        peer_id_bytes
191    }
192
193    #[cfg(not(any(feature = "ring", feature = "aws-lc-rs")))]
194    {
195        // Use SHA2 crate as fallback
196        use sha2::{Digest, Sha256};
197
198        let mut hasher = Sha256::new();
199        hasher.update(&input);
200        let result = hasher.finalize();
201
202        let mut peer_id_bytes = [0u8; 32];
203        peer_id_bytes.copy_from_slice(&result);
204        peer_id_bytes
205    }
206}
207
208/// Verify that a peer ID was correctly derived from a public key
209pub fn verify_peer_id(peer_id: &[u8; 32], public_key: &VerifyingKey) -> bool {
210    let derived_id = derive_peer_id_from_public_key(public_key);
211    peer_id == &derived_id
212}
213
214/// Generate a new Ed25519 key pair (convenience function)
215pub fn generate_ed25519_keypair() -> Ed25519KeyPair {
216    Ed25519KeyPair::generate()
217}
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222
223    #[test]
224    fn test_keypair_generation() {
225        let keypair = Ed25519KeyPair::generate();
226        let signature = keypair.sign(b"test message");
227        assert!(keypair.verify(b"test message", &signature).is_ok());
228        assert!(keypair.verify(b"wrong message", &signature).is_err());
229    }
230
231    #[test]
232    fn test_spki_encoding_decoding() {
233        let keypair = Ed25519KeyPair::generate();
234        let spki = keypair.public_key_spki();
235
236        // Verify SPKI format
237        assert_eq!(spki.len(), 44);
238        assert_eq!(&spki[0..2], &[0x30, 0x2a]); // SEQUENCE tag and length
239
240        // Extract key from SPKI
241        let extracted_key = extract_ed25519_key_from_spki(&spki).unwrap();
242        assert_eq!(extracted_key, keypair.public_key_bytes());
243
244        // Create VerifyingKey from SPKI
245        let verifying_key = verifying_key_from_spki(&spki).unwrap();
246        assert_eq!(verifying_key.as_bytes(), keypair.verifying_key().as_bytes());
247    }
248
249    #[test]
250    fn test_peer_id_derivation() {
251        let keypair1 = Ed25519KeyPair::generate();
252        let keypair2 = Ed25519KeyPair::generate();
253
254        let peer_id1 = derive_peer_id_from_public_key(keypair1.verifying_key());
255        let peer_id2 = derive_peer_id_from_public_key(keypair1.verifying_key());
256        let peer_id3 = derive_peer_id_from_public_key(keypair2.verifying_key());
257
258        // Same key should produce same peer ID
259        assert_eq!(peer_id1, peer_id2);
260
261        // Different keys should produce different peer IDs
262        assert_ne!(peer_id1, peer_id3);
263
264        // Verify peer ID
265        assert!(verify_peer_id(&peer_id1, keypair1.verifying_key()));
266        assert!(!verify_peer_id(&peer_id1, keypair2.verifying_key()));
267    }
268
269    #[test]
270    fn test_invalid_spki() {
271        // Too short
272        let result = extract_ed25519_key_from_spki(&[0; 43]);
273        assert!(result.is_err());
274
275        // Wrong OID
276        let mut invalid_spki = vec![0; 44];
277        invalid_spki[7] = 0xFF; // Corrupt the OID
278        let result = extract_ed25519_key_from_spki(&invalid_spki);
279        assert!(result.is_err());
280    }
281}