steel_crypto/
rsa_utils.rs1use rsa::{RsaPrivateKey, RsaPublicKey};
6use thiserror::Error;
7
8#[derive(Debug, Error)]
10pub enum CryptError {
11 #[error("RSA error: {0}")]
12 RsaError(#[from] rsa::Error),
13
14 #[error("PKCS8 error: {0}")]
15 Pkcs8Error(#[from] rsa::pkcs8::Error),
16
17 #[error("SPKI error: {0}")]
18 SpkiError(#[from] rsa::pkcs8::spki::Error),
19
20 #[error("Invalid key format")]
21 InvalidKeyFormat,
22
23 #[error("Cryptographic operation failed: {0}")]
24 OperationFailed(String),
25}
26
27pub fn generate_key_pair() -> Result<(RsaPrivateKey, RsaPublicKey), CryptError> {
31 let mut rng = rand::rng();
32 let private_key = RsaPrivateKey::new(&mut rng, crate::RSA_KEY_BITS)?;
33 let public_key = RsaPublicKey::from(&private_key);
34 Ok((private_key, public_key))
35}
36
37pub fn public_key_to_bytes(key: &RsaPublicKey) -> Result<Vec<u8>, CryptError> {
41 use rsa::pkcs8::EncodePublicKey;
42 key.to_public_key_der()
43 .map(|der| der.to_vec())
44 .map_err(CryptError::from)
45}
46
47pub fn public_key_from_bytes(bytes: &[u8]) -> Result<RsaPublicKey, CryptError> {
51 use rsa::pkcs8::DecodePublicKey;
52 RsaPublicKey::from_public_key_der(bytes).map_err(CryptError::from)
53}
54
55pub fn public_key_to_pem(key: &RsaPublicKey) -> Result<String, CryptError> {
59 use rsa::pkcs8::EncodePublicKey;
60 key.to_public_key_pem(rsa::pkcs8::LineEnding::LF)
61 .map_err(CryptError::from)
62}
63
64pub fn public_key_from_pem(pem: &str) -> Result<RsaPublicKey, CryptError> {
68 use rsa::pkcs8::DecodePublicKey;
69 RsaPublicKey::from_public_key_pem(pem).map_err(CryptError::from)
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_generate_key_pair() {
78 let result = generate_key_pair();
79 assert!(result.is_ok());
80 }
81
82 #[test]
83 fn test_public_key_round_trip() {
84 let (_, public_key) = generate_key_pair().unwrap();
85 let bytes = public_key_to_bytes(&public_key).unwrap();
86 let decoded = public_key_from_bytes(&bytes).unwrap();
87
88 let encoded_again = public_key_to_bytes(&decoded).unwrap();
89 assert_eq!(bytes, encoded_again);
90 }
91
92 #[test]
93 fn test_pem_round_trip() {
94 let (_, public_key) = generate_key_pair().unwrap();
95 let pem = public_key_to_pem(&public_key).unwrap();
96 let decoded = public_key_from_pem(&pem).unwrap();
97
98 let pem_again = public_key_to_pem(&decoded).unwrap();
99 assert_eq!(pem, pem_again);
100 }
101}