lib3mf_core/crypto/
keys.rs

1use crate::error::{Lib3mfError, Result};
2use rsa::{
3    Oaep,
4    RsaPrivateKey,
5    RsaPublicKey,
6    pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey},
7    pkcs8::DecodePublicKey, // Ensure this is used
8};
9// Removed DecodePrivateKey from pkcs8 usage on PublicKey lines to avoid confusion.
10// Actually RsaPrivateKey needs DecodePrivateKey from pkcs8 too.
11use rand::rngs::OsRng;
12use rsa::pkcs8::DecodePrivateKey;
13use sha1::Sha1;
14use std::fs;
15use std::path::Path;
16
17pub struct KeyManager;
18
19impl KeyManager {
20    /// Loads an RSA private key from a PEM file.
21    pub fn load_private_key<P: AsRef<Path>>(path: P) -> Result<RsaPrivateKey> {
22        let content = fs::read_to_string(path)
23            .map_err(|e| Lib3mfError::Validation(format!("Failed to read key file: {}", e)))?;
24
25        // Try PKCS#1 then PKCS#8
26        RsaPrivateKey::from_pkcs1_pem(&content)
27            .or_else(|_| RsaPrivateKey::from_pkcs8_pem(&content))
28            .map_err(|e| Lib3mfError::Validation(format!("Invalid private key format: {}", e)))
29    }
30
31    /// Loads an RSA public key from a PEM file.
32    pub fn load_public_key<P: AsRef<Path>>(path: P) -> Result<RsaPublicKey> {
33        let content = fs::read_to_string(path)
34            .map_err(|e| Lib3mfError::Validation(format!("Failed to read key file: {}", e)))?;
35
36        RsaPublicKey::from_pkcs1_pem(&content)
37            .or_else(|_| RsaPublicKey::from_public_key_pem(&content))
38            .map_err(|e| Lib3mfError::Validation(format!("Invalid public key format: {}", e)))
39    }
40
41    /// Wraps (encrypts) a CEK using the public key (KEK).
42    /// Uses RSA-OAEP with SHA-1 digest (per 3MF spec).
43    pub fn wrap_key(public_key: &RsaPublicKey, cek: &[u8]) -> Result<Vec<u8>> {
44        let mut rng = OsRng;
45        let padding = Oaep::new::<Sha1>();
46        public_key
47            .encrypt(&mut rng, padding, cek)
48            .map_err(|e| Lib3mfError::EncryptionError(format!("Key wrapping failed: {}", e)))
49    }
50
51    /// Unwraps (decrypts) a CEK using the private key (KEK).
52    /// Uses RSA-OAEP with SHA-1 digest.
53    pub fn unwrap_key(private_key: &RsaPrivateKey, wrapped_key: &[u8]) -> Result<Vec<u8>> {
54        let padding = Oaep::new::<Sha1>();
55        private_key
56            .decrypt(padding, wrapped_key)
57            .map_err(|e| Lib3mfError::EncryptionError(format!("Key unwrapping failed: {}", e)))
58    }
59}