//! Read and Write PEM files from RSA types //! //! This library will be useless after the next release of the RSA crate, which should have this //! functionality baked in. //! //! ### Examples //! ```rust //! use rsa_pem::KeyExt; //! use rsa::RSAPrivateKey; //! # //! # let mut rng = rand::thread_rng(); //! # let private_key = RSAPrivateKey::new(&mut rng, 2048).unwrap(); //! //! let pkcs8_string = private_key.to_pem_pkcs8().unwrap(); //! let private_key = RSAPrivateKey::from_pem_pkcs8(&pkcs8_string).unwrap(); //! ``` use num_bigint_dig::{BigInt, BigUint, Sign}; use thiserror::Error; mod private; mod public; const RSA_OID: [u64; 7] = [1, 2, 840, 113_549, 1, 1, 1]; /// Extensions to keys for formatting and reading PKCS1 and PKCS8 PEM strings pub trait KeyExt { /// Write a PKCS8 pem string fn to_pem_pkcs8(&self) -> Result; /// Read a PKCS8 pem string fn from_pem_pkcs8(pem: &str) -> Result where Self: Sized; /// Write a PKCS1 pem string fn to_pem_pkcs1(&self) -> Result; /// Read a PKCS1 pem string fn from_pem_pkcs1(pem: &str) -> Result where Self: Sized; } /// Errors produced when serializing or deserializing keys #[derive(Debug, Error)] pub enum KeyError { /// The PEM wrapper has the wrong name #[error("Invalid key kind supplied")] Kind, /// The file isn't PEM encoded #[error("Key not PEM-formatted")] Pem, /// Parsing the DER bytes failed #[error("Error parsing key, {}", .0)] Parse(rsa::errors::Error), /// The private key's fields don't make sense #[error("Constructed key is invalid")] Validate, /// Failed to serialize to DER bytes #[error("Could not serialize key")] Serialize, } fn from_dig(biguint: &BigUint) -> num_bigint::BigUint { num_bigint::BigUint::from_bytes_be(&biguint.to_bytes_be()) } fn int_from_dig(bigint: &BigInt) -> num_bigint::BigInt { let (sign, bytes) = bigint.to_bytes_be(); num_bigint::BigInt::from_bytes_be(sign_from_dig(sign), &bytes) } fn sign_from_dig(sign: Sign) -> num_bigint::Sign { match sign { Sign::Minus => num_bigint::Sign::Minus, Sign::NoSign => num_bigint::Sign::NoSign, Sign::Plus => num_bigint::Sign::Plus, } } #[cfg(test)] mod tests { use crate::KeyExt; use rsa::{hash::Hash, padding::PaddingScheme, PublicKey, RSAPrivateKey, RSAPublicKey}; use sha2::{Digest, Sha256}; static SIGNING_STRING: &[u8] = b"Hewwo, Mr Obama"; fn padding() -> PaddingScheme { PaddingScheme::PKCS1v15Sign { hash: Some(Hash::SHA2_256), } } #[test] fn priv_can_complete_cycle_pkcs1() { let mut rng = rand::thread_rng(); let rsa = RSAPrivateKey::new(&mut rng, 2048).unwrap(); let hashed = Sha256::digest(SIGNING_STRING); let sig = rsa.sign(padding(), &hashed).unwrap(); let string = rsa.to_pem_pkcs1().unwrap(); let res = RSAPrivateKey::from_pem_pkcs1(&string); let pubkey = res.unwrap().to_public_key(); pubkey.verify(padding(), &hashed, &sig).unwrap(); } #[test] fn pub_can_complete_cycle_pkcs1() { let mut rng = rand::thread_rng(); let rsa = RSAPrivateKey::new(&mut rng, 2048).unwrap(); let hashed = Sha256::digest(SIGNING_STRING); let sig = rsa.sign(padding(), &hashed).unwrap(); let rsa = rsa.to_public_key(); let string = rsa.to_pem_pkcs1().unwrap(); let res = RSAPublicKey::from_pem_pkcs1(&string); let pubkey = res.unwrap(); pubkey.verify(padding(), &hashed, &sig).unwrap(); } #[test] fn priv_can_complete_cycle_pkcs8() { let mut rng = rand::thread_rng(); let rsa = RSAPrivateKey::new(&mut rng, 2048).unwrap(); let hashed = Sha256::digest(SIGNING_STRING); let sig = rsa.sign(padding(), &hashed).unwrap(); let string = rsa.to_pem_pkcs8().unwrap(); let res = RSAPrivateKey::from_pem_pkcs8(&string); let pubkey = res.unwrap().to_public_key(); pubkey.verify(padding(), &hashed, &sig).unwrap(); } #[test] fn pub_can_complete_cycle_pkcs8() { let mut rng = rand::thread_rng(); let rsa = RSAPrivateKey::new(&mut rng, 2048).unwrap(); let hashed = Sha256::digest(SIGNING_STRING); let sig = rsa.sign(padding(), &hashed).unwrap(); let rsa = rsa.to_public_key(); let string = rsa.to_pem_pkcs8().unwrap(); let res = RSAPublicKey::from_pem_pkcs8(&string); let pubkey = res.unwrap(); pubkey.verify(padding(), &hashed, &sig).unwrap(); } }