diff --git a/src/crypto/keys.rs b/src/crypto/keys.rs index 9e7aea5..3a12a7b 100644 --- a/src/crypto/keys.rs +++ b/src/crypto/keys.rs @@ -174,6 +174,62 @@ pub struct PublicKey { impl PublicKey { + /// Creates an RSA Public Key based on the supplied exponent and modulus. + /// + /// See: + /// [RFC 4055]: https://tools.ietf.org/html/rfc4055 + /// + /// An RSA Public Key uses the following DER encoded structure inside its + /// BitString component: + /// + /// ```txt + /// RSAPublicKey ::= SEQUENCE { + /// modulus INTEGER, -- n + /// publicExponent INTEGER } -- e + /// ``` + pub fn rsa_from_components( + modulus: &[u8], // n + exponent: &[u8] // e + ) -> Result { + let modulus = bcder::Unsigned::from_slice(modulus)?; + let exponent = bcder::Unsigned::from_slice(exponent)?; + + let pub_key_sequence = bcder::encode::sequence(( + modulus.encode(), + exponent.encode() + )); + + Ok(PublicKey { + algorithm: PublicKeyFormat::Rsa, + bits: BitString::new( + 0, + pub_key_sequence.to_captured(bcder::Mode::Der).into_bytes() + ), + }) + } + + /// Creates an RSA public key from the key’s bits. + /// + /// Note that this is _not_ the DER-encoded public key written by, for + /// instance, the OpenSSL command line tools. These files contain the + /// complete public key including the algorithm and need to be read + /// with [`PublicKey::decode`]. + pub fn rsa_from_bits_bytes( + bytes: Bytes + ) -> Result { + Mode::Der.decode(bytes.clone(), |cons| { + cons.take_sequence(|cons| { + let _ = bcder::Unsigned::take_from(cons)?; + let _ = bcder::Unsigned::take_from(cons)?; + Ok(()) + }) + })?; + Ok(PublicKey { + algorithm: PublicKeyFormat::Rsa, + bits: BitString::new(0, bytes) + }) + } + /// Returns the algorithm of this public key. pub fn algorithm(&self) -> PublicKeyFormat { self.algorithm @@ -394,4 +450,16 @@ mod test { assert_eq!(pub_key, &de); } -} \ No newline at end of file + + #[test] + fn rsa_from_public_key_bytes() { + let key = PublicKey::decode( + include_bytes!("../../test-data/rsa-key.public.der").as_ref(), + ).unwrap(); + assert!( + PublicKey::rsa_from_bits_bytes( + key.bits_bytes() + ).is_ok() + ); + } +} diff --git a/test-data/rsa-key.private.der b/test-data/rsa-key.private.der new file mode 100644 index 0000000..c8738fa Binary files /dev/null and b/test-data/rsa-key.private.der differ diff --git a/test-data/rsa-key.public.der b/test-data/rsa-key.public.der new file mode 100644 index 0000000..7dc2f73 Binary files /dev/null and b/test-data/rsa-key.public.der differ