srsa/
lib.rs

1//! A crate that uses the already well established [rsa](https://docs.rs/rsa/0.8.2/rsa/) and
2//! [pkcs8](https://docs.rs/pkcs8/0.10.2/pkcs8/) crates to provide a simple plug
3//! and play experience.
4//!
5//! # Usage
6//!
7//! ## Saving key pairs
8//! ```
9//! use srsa::Keys;
10//! use anyhow::Result as AnyResult;
11//!
12//! fn main() -> AnyResult<()> {
13//!     // The values passed in will be the file names of the private and public keys.
14//!     let keys = Keys::new("priv", "pub");
15//!
16//!     // Saves the key pairs to a folder in the cwd called keys and encrypts the private key with a
17//!     // password
18//!     keys.write_to_disk("password", "keys")?;
19//!
20//!     Ok(())
21//! }
22//! ```
23//!
24//! ## Using an existing key pair
25//! ```rust
26//! use srsa::Keys;
27//! use anyhow::Result as AnyResult;
28//!
29//! fn main() -> AnyResult<()> {
30//!     let keys = Keys::retrieve_keys("keys/test_priv", "1234", "keys/test_pub")?;
31//!     let ciphertext = keys.seal(b"hi")?;
32//!     let plaintext = keys.unseal(&ciphertext)?;
33//!     Ok(())
34//! }
35//! ```
36//!
37//! Encrypting and decrypt things work very similarly.
38//! 1. You retrieve the neccessary keys to do the job.
39//! 2. You run the appropriate function. The encryption function called `seal`, the decryption
40//!    function is called `unseal`.
41
42use std::fs;
43
44pub mod errors;
45mod test;
46
47use anyhow::{Context, Result as AnyResult};
48use errors::KeyError;
49use pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey, LineEnding};
50use rsa::{Pkcs1v15Encrypt, PublicKey, RsaPrivateKey, RsaPublicKey};
51
52/// Contains the key pairs and their names. This struct is to use the key pairs and to retrieve
53/// them. It can also be used to create new key pairs.
54pub struct Keys<'names> {
55    priv_key: Option<RsaPrivateKey>,
56    priv_key_name: &'names str,
57    pub_key: Option<RsaPublicKey>,
58    pub_key_name: &'names str,
59}
60
61impl<'names> Keys<'names> {
62    /// Creates key pairs.
63    /// # Parameters
64    /// - `priv_key_name` & `pub_key_name`: The name of the keys. If the keys are saved to disk
65    /// with `self.write_to_disk` the values for these variables will be the file name.
66    pub fn new(priv_key_name: &'names str, pub_key_name: &'names str) -> Self {
67        let mut rng = rand::thread_rng();
68
69        let bits = 2048;
70        let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
71        let pub_key = RsaPublicKey::from(&priv_key);
72
73        Self {
74            priv_key: Some(priv_key),
75            priv_key_name,
76            pub_key: Some(pub_key),
77            pub_key_name,
78        }
79    }
80
81    /// Will read the PEM encoded public and private keys and return `Self`.
82    /// If you only want a specific key look at their respective function.
83    /// - `retrieve_private_key`
84    /// - `retrieve_public_key`
85    ///
86    /// # Parameters
87    /// - `priv_key`: Path to private key file.
88    /// - `password`: The password used to encrypt the private key.
89    /// - `pub_key`: Path to public key file.
90    pub fn retrieve_keys(
91        priv_key_path: &'names str,
92        password: &str,
93        pub_key_path: &'names str,
94    ) -> AnyResult<Self> {
95        // Get *encrypted* private key first
96        let mut pem = fs::read_to_string(priv_key_path)?;
97
98        // Decrypt encrypted private key
99        let priv_key = RsaPrivateKey::from_pkcs8_encrypted_pem(&pem, password)?;
100        pem.clear();
101
102        // Then get public key
103        pem = fs::read_to_string(pub_key_path)?;
104        let pub_key = RsaPublicKey::from_public_key_pem(&pem)?;
105
106        Ok(Self {
107            priv_key: Some(priv_key),
108            priv_key_name: priv_key_path,
109            pub_key: Some(pub_key),
110            pub_key_name: pub_key_path,
111        })
112    }
113
114    pub fn retrieve_private_key(priv_key_path: &'names str, password: &str) -> AnyResult<Self> {
115        let pem = fs::read_to_string(priv_key_path)?;
116        let private_key = RsaPrivateKey::from_pkcs8_encrypted_pem(&pem, password)?;
117
118        Ok(Self {
119            priv_key: Some(private_key),
120            priv_key_name: priv_key_path,
121            pub_key: None,
122            pub_key_name: "",
123        })
124    }
125}
126
127impl Keys<'_> {
128    /// Will further encrypt the `self.priv_key` before writing it to disk.
129    /// Both keys will be PEM encoded.
130    /// # Parameters
131    /// - `priv_key_pass`: The password used to encrypt the private key.
132    /// - `folder`: The folder to write the keys to. If left empty will default to cwd.
133    pub fn write_to_disk(&self, priv_key_pass: &str, folder: &str) -> AnyResult<()> {
134        let folder = if folder.is_empty() { "." } else { folder };
135
136        let priv_key_pem = &self
137            .priv_key
138            .as_ref()
139            .ok_or(KeyError::UnableToUnpackKey)?
140            .to_pkcs8_encrypted_pem(&mut rand::thread_rng(), priv_key_pass, LineEnding::LF)?;
141
142        let pub_key_pem = &self
143            .pub_key
144            .as_ref()
145            .ok_or(KeyError::UnableToUnpackKey)?
146            .to_public_key_pem(LineEnding::LF)?;
147
148        let priv_key_path = format!("{}/{}", folder, self.priv_key_name);
149        fs::write(priv_key_path, priv_key_pem.as_bytes())?;
150
151        let pub_key_path = format!("{}/{}", folder, self.pub_key_name);
152        fs::write(pub_key_path, pub_key_pem.as_bytes())?;
153
154        Ok(())
155    }
156
157    pub fn seal(&self, plaintext: &[u8]) -> AnyResult<Vec<u8>> {
158        let mut rng = rand::thread_rng();
159        self.pub_key
160            .clone()
161            .ok_or(KeyError::UnableToUnpackKey)?
162            .encrypt(&mut rng, Pkcs1v15Encrypt, plaintext)
163            .context("Unable to encrypt plaintext with public key, you should take a look at it.")
164    }
165
166    pub fn unseal(&self, ciphertext: &[u8]) -> AnyResult<Vec<u8>> {
167        self.priv_key
168            .clone()
169            .ok_or(KeyError::UnableToUnpackKey)?
170            .decrypt(Pkcs1v15Encrypt, ciphertext)
171            .context("Unable to decrypt ciphertext with private key, you should take a look at it.")
172    }
173}