Skip to main content

steel_crypto/
key_store.rs

1//! This module contains the `KeyStore` struct, which is used to store the server's encryption keys.
2use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
3
4/// Returned when decryption fails. Carries no reason so callers can't leak one to clients.
5#[derive(Debug, thiserror::Error)]
6#[error("decryption failed")]
7pub struct DecryptError;
8
9/// A struct that stores the server's encryption keys.
10pub struct KeyStore {
11    /// The server's private key.
12    private_key: RsaPrivateKey,
13    /// The server's public key in DER format.
14    pub public_key_der: Vec<u8>,
15}
16
17impl KeyStore {
18    /// Creates a new `KeyStore`.
19    #[must_use]
20    pub fn create() -> Self {
21        log::debug!("Creating encryption keys...");
22        let private_key = Self::generate_private_key();
23
24        let public_key = RsaPublicKey::from(&private_key);
25        let public_key_der =
26            crate::public_key_to_bytes(&public_key).expect("Failed to encode public key");
27
28        Self {
29            private_key,
30            public_key_der,
31        }
32    }
33
34    /// Decrypts a PKCS#1 v1.5 ciphertext. Failures carry no cause on purpose.
35    pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, DecryptError> {
36        self.private_key
37            .decrypt(Pkcs1v15Encrypt, ciphertext)
38            .map_err(|_| DecryptError)
39    }
40
41    fn generate_private_key() -> RsaPrivateKey {
42        // Found out that OsRng is faster than rand::thread_rng here
43        let mut rng = rand::rng();
44
45        RsaPrivateKey::new(&mut rng, 1024).expect("Failed to generate a key")
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn decrypt_reports_no_reason_for_failure() {
55        let ks = KeyStore::create();
56        let public_key = RsaPublicKey::from(&ks.private_key);
57        let secret = b"0123456789abcdef";
58
59        let ciphertext = public_key
60            .encrypt(&mut rand::rng(), Pkcs1v15Encrypt, secret)
61            .unwrap();
62        assert_eq!(ks.decrypt(&ciphertext).unwrap(), secret);
63
64        // Malformed and unpadded ciphertexts must be indistinguishable from each other.
65        assert!(ks.decrypt(&[]).is_err());
66        assert!(ks.decrypt(&[0; 128]).is_err());
67    }
68
69    #[test]
70    fn public_key_der_round_trips() {
71        let ks = KeyStore::create();
72        let decoded = crate::public_key_from_bytes(&ks.public_key_der).unwrap();
73        assert_eq!(decoded, RsaPublicKey::from(&ks.private_key));
74    }
75}