Browse Source

Added support for RSA keys.

Matthew Carr 2 years ago
parent
commit
7b74616079
2 changed files with 115 additions and 34 deletions
  1. 69 22
      crates/node/src/crypto.rs
  2. 46 12
      crates/node/src/test_helpers.rs

+ 69 - 22
crates/node/src/crypto.rs

@@ -6,9 +6,8 @@ use openssl::{
     encrypt::{Encrypter, Decrypter},
     pkey::{PKey, Public, Private},
     symm::{Cipher, encrypt as openssl_encrypt, decrypt as openssl_decrypt},
-    nid::Nid,
-    ec::{EcGroup, EcKey},
     rand::rand_bytes,
+    rsa::{Rsa, Padding as OpensslPadding},
 };
 use serde_block_tree::{self, to_vec, from_vec};
 use serde::de::{DeserializeOwned};
@@ -58,7 +57,7 @@ pub enum Hash {
 #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
 pub enum Signature {
     #[serde(with = "BigArray")]
-    Secp256k1([u8; 64]),
+    Rsa([u8; 64]),
 }
 
 /// Identifies a type of cryptographic key. The variants of this enum match those of `Key`.
@@ -66,7 +65,28 @@ pub enum KeyId {
     // TODO: Write a macro to generate this from `Key`.
     Aes256Cbc,
     Aes256Ctr,
-    Secp256k1,
+    Rsa,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub enum RsaPadding {
+    None,
+    Pkcs1,
+    Pkcs1Oaep,
+    Pkcs1Pss,
+}
+
+impl Copy for RsaPadding {}
+
+impl From<RsaPadding> for OpensslPadding {
+    fn from(padding: RsaPadding) -> OpensslPadding {
+        match padding {
+            RsaPadding::None => OpensslPadding::NONE,
+            RsaPadding::Pkcs1 => OpensslPadding::PKCS1,
+            RsaPadding::Pkcs1Oaep => OpensslPadding::PKCS1_OAEP,
+            RsaPadding::Pkcs1Pss => OpensslPadding::PKCS1_PSS,
+        }
+    }
 }
 
 /// A cryptographic key.
@@ -84,10 +104,10 @@ pub enum Key {
         key: [u8; 32],
         iv: [u8; 16]
     },
-    Secp256k1 {
-        #[serde(with = "BigArray")]
-        public: [u8; 88],
-        private: Option<Vec<u8>>
+    Rsa {
+        public: Vec<u8>,
+        private: Option<Vec<u8>>,
+        padding: RsaPadding,
     },
 }
 
@@ -98,7 +118,7 @@ impl Key {
         match self {
             Key::Aes256Cbc { key, .. } => Some(key),
             Key::Aes256Ctr { key, .. } => Some(key),
-            Key::Secp256k1 { private, .. } => match private {
+            Key::Rsa { private, .. } => match private {
                 Some(key) => Some(key.as_slice()),
                 None => None,
             },
@@ -129,14 +149,11 @@ impl Key {
                 rand_bytes(&mut iv).map_err(Error::from)?;
                 Ok(Key::Aes256Ctr { key, iv })
             },
-            KeyId::Secp256k1 => {
-                let group = EcGroup::from_curve_name(Nid::SECP256K1).map_err(Error::from)?;
-                let key = EcKey::generate(&group).map_err(Error::from)?;
-                let mut public = [0; 88];
-                let public_vec = key.public_key_to_der().map_err(Error::from)?;
-                public.copy_from_slice(&public_vec);
+            KeyId::Rsa => {
+                let key = PKey::from_rsa(Rsa::generate(4096)?)?;
+                let public= key.public_key_to_der().map_err(Error::from)?;
                 let private = Some(key.private_key_to_der().map_err(Error::from)?);
-                Ok(Key::Secp256k1 { public, private })
+                Ok(Key::Rsa { public, private, padding: RsaPadding::Pkcs1 })
             },
         }
     }
@@ -148,7 +165,10 @@ enum EncryptionAlgo<'a> {
         key: &'a [u8],
         iv: Option<&'a [u8]>
     },
-    Asymmetric(PKey<Public>),
+    Asymmetric {
+        key: PKey<Public>,
+        rsa_padding: Option<OpensslPadding>,
+    }
 }
 
 impl<'a> EncryptionAlgo<'a> {
@@ -157,8 +177,11 @@ impl<'a> EncryptionAlgo<'a> {
             EncryptionAlgo::Symmetric { cipher, key, iv } => {
                 openssl_encrypt(*cipher, key, *iv, slice).map_err(Error::from)
             },
-            EncryptionAlgo::Asymmetric(pkey) => {
-                let encrypter = Encrypter::new(pkey).map_err(Error::from)?;
+            EncryptionAlgo::Asymmetric { key, rsa_padding } => {
+                let mut encrypter = Encrypter::new(key).map_err(Error::from)?;
+                if let Some(padding) = rsa_padding {
+                    encrypter.set_rsa_padding(*padding).map_err(Error::from)?;
+                }
                 let buffer_len = encrypter.encrypt_len(slice).map_err(Error::from)?;
                 let mut ciphertext = vec![0; buffer_len];
                 let ciphertext_len = encrypter.encrypt(slice, &mut ciphertext)
@@ -184,10 +207,10 @@ impl<'a> TryFrom<&'a Key> for EncryptionAlgo<'a> {
                 key: key_slice,
                 iv: Some(iv),
             }),
-            Key::Secp256k1 { public, .. } => {
+            Key::Rsa { public, padding, .. } => {
                 let pkey = PKey::public_key_from_der(public.as_slice())
                     .map_err(|err| Error::Message(err.to_string()));
-                Ok(EncryptionAlgo::Asymmetric(pkey?))
+                Ok(EncryptionAlgo::Asymmetric { key: pkey?, rsa_padding: Some((*padding).into()) })
             },
         }
     }
@@ -235,7 +258,7 @@ impl<'a> TryFrom<&'a Key> for DecryptionAlgo<'a> {
                 key: key_slice,
                 iv: Some(iv),
             }),
-            Key::Secp256k1 { private, .. } => {
+            Key::Rsa { private, .. } => {
                 let private = private.as_ref().ok_or(Error::MissingPrivateKey)?;
                 let pkey = PKey::private_key_from_der(private.as_slice()).map_err(Error::from);
                 Ok(DecryptionAlgo::Asymmetric(pkey?))
@@ -358,9 +381,22 @@ mod tests {
         encrypt_decrypt_block_test_case(block, &principal, &key)
     }
 
+    #[test]
+    fn encrypt_decrypt_block_rsa() -> Result<()> {
+        let principal = make_principal();
+        let block_key = Key::Aes256Ctr { key: BLOCK_KEY, iv: BLOCK_IV };
+        let block = make_versioned_block(principal.clone(), block_key)?;
+        let key = Key::generate(KeyId::Rsa)?;
+        encrypt_decrypt_block_test_case(block, &principal, &key)
+    }
+
     /// Tests that validate the dependencies of this module.
     mod dependency_tests {
         use super::*;
+        use openssl::{
+            ec::{EcGroup, EcKey},
+            nid::Nid,
+        };
 
         /// This test validates that data decrypted with the `Crypter` API matches data that was
         /// previously encrypted using it.
@@ -388,5 +424,16 @@ mod tests {
             assert_eq!(88, public_len);
             assert_eq!(118, private_len);
         }
+
+        #[test]
+        fn ed25519_key_lengths() {
+            let key = PKey::generate_x25519().unwrap();
+            let public = key.public_key_to_der().unwrap();
+            let private = key.private_key_to_der().unwrap();
+            let public_len = public.len();
+            let private_len = private.len();
+            assert_eq!(44, public_len);
+            assert_eq!(48, private_len);
+        }
     }
 }

+ 46 - 12
crates/node/src/test_helpers.rs

@@ -1,6 +1,7 @@
 /// Test data and functions to help with testing.
 
 use super::*;
+use crypto::RsaPadding;
 use serde_block_tree::{Error, Result};
 
 pub const PRINCIPAL: [u8; 32] = [
@@ -31,13 +32,42 @@ pub const KEY: [u8; 32] = [
     0xBB, 0xF9, 0xFE, 0xD0, 0xC1, 0xF7, 0x90, 0x34, 0x69, 0xB7, 0xE7, 0xC6, 0x1C, 0x46, 0x85, 0x48,
 ];
 
-const SECP256K1_KEY: [u8; 88] = [
-    0x65, 0x9A, 0xC9, 0xC6, 0xF4, 0x08, 0x95, 0x80, 0x61, 0x5A, 0xFC, 0x46, 0xD7, 0xD8, 0x17, 0x6F,
-    0x84, 0x67, 0xF3, 0xAD, 0x81, 0xBD, 0xAC, 0x85, 0xF4, 0x52, 0x3F, 0xDF, 0x04, 0x42, 0xE4, 0x66,
-    0x0C, 0x8F, 0x56, 0xCF, 0xF5, 0x34, 0x65, 0x3B, 0x95, 0x86, 0x56, 0xC5, 0x25, 0xFD, 0x6F, 0x74,
-    0x98, 0xE5, 0x7D, 0xE0, 0x52, 0xAD, 0x85, 0x48, 0xF1, 0x8A, 0x18, 0x7D, 0xC7, 0x53, 0x8B, 0x79,
-    0xB0, 0x15, 0x7E, 0xBB, 0xA5, 0xA0, 0x41, 0x33, 0x3F, 0x4D, 0x50, 0xCE, 0x06, 0x1F, 0xE2, 0x6A,
-    0x57, 0x5A, 0xB6, 0x85, 0x4B, 0x58, 0xDC, 0x80,
+const RSA_KEY: [u8; 550] = [
+    0xEC, 0xB5, 0x31, 0xFB, 0xF7, 0x1B, 0x81, 0x55, 0x20, 0xF2, 0x4D, 0x09, 0xDC, 0x19, 0x37, 0x07,
+    0x08, 0x41, 0xB5, 0xC2, 0xDE, 0xF8, 0x33, 0xF9, 0x42, 0x79, 0xFF, 0x79, 0x4F, 0x45, 0x4F, 0x99,
+    0x3C, 0x80, 0xE7, 0x91, 0xC1, 0xA1, 0x6C, 0xB4, 0xBF, 0x1B, 0x64, 0xCE, 0xE6, 0xB4, 0x7D, 0xB8,
+    0x8A, 0x2E, 0xE6, 0x01, 0xE5, 0x83, 0xE8, 0xB5, 0x41, 0x21, 0x5B, 0xA6, 0x89, 0xDF, 0x72, 0xBF,
+    0xA8, 0x54, 0x6E, 0x9E, 0x16, 0xDD, 0x19, 0x07, 0x3D, 0xEF, 0xD2, 0x84, 0x05, 0x96, 0xAD, 0x06,
+    0xEC, 0x8C, 0x8F, 0x2B, 0xB5, 0xD9, 0x24, 0x8D, 0xCE, 0x85, 0xC6, 0x72, 0xA5, 0xCC, 0x7A, 0x53,
+    0x5E, 0x86, 0x47, 0x19, 0x15, 0xFC, 0x1F, 0x66, 0xDB, 0x15, 0x24, 0x90, 0x8C, 0x90, 0xBE, 0xA0,
+    0x6A, 0xED, 0x9F, 0x5E, 0x40, 0xD1, 0x08, 0xD0, 0x1B, 0x98, 0x5F, 0xD2, 0x73, 0x1A, 0x5A, 0x85,
+    0x78, 0x5E, 0x57, 0x01, 0xFE, 0x4E, 0xF9, 0xB2, 0x7B, 0x8B, 0x1D, 0xF0, 0xA1, 0xE6, 0xF2, 0xF6,
+    0xB8, 0x27, 0x91, 0xC1, 0xD4, 0x1A, 0xFF, 0xBE, 0x31, 0x05, 0xD7, 0x4D, 0x81, 0xC7, 0xA8, 0x52,
+    0x84, 0xB9, 0x24, 0x5C, 0x4C, 0x98, 0x3A, 0x77, 0xD1, 0x20, 0x9F, 0x3A, 0x72, 0x1D, 0xE2, 0xDB,
+    0xEE, 0x7E, 0xB1, 0x92, 0x91, 0x84, 0xB0, 0xE1, 0x3A, 0x1F, 0xC4, 0x15, 0xB9, 0x9F, 0x1E, 0xBC,
+    0x9D, 0x67, 0xED, 0xD5, 0x39, 0x45, 0x48, 0x7F, 0x15, 0x8D, 0xC5, 0xE0, 0x13, 0x16, 0x32, 0x74,
+    0xB2, 0x5A, 0xF8, 0x10, 0x0D, 0x59, 0xA8, 0xE8, 0xB9, 0xE4, 0xAA, 0xE0, 0x09, 0xDE, 0x4E, 0xA4,
+    0x7E, 0x98, 0x23, 0x65, 0xC1, 0xC9, 0xA2, 0x47, 0x26, 0x59, 0x48, 0xD4, 0x9D, 0x85, 0x75, 0x45,
+    0x7F, 0xFD, 0xCD, 0xE7, 0xC6, 0x81, 0x7F, 0xCC, 0xB5, 0x89, 0xA9, 0x1B, 0x6D, 0x3C, 0xFE, 0x64,
+    0x8B, 0xF4, 0xEE, 0xDD, 0xA2, 0xE0, 0x9A, 0xEF, 0x66, 0x17, 0x6E, 0x6B, 0x7F, 0xB8, 0x7A, 0x54,
+    0x9C, 0x38, 0xA1, 0xC5, 0xAD, 0x0C, 0xA0, 0x8E, 0x13, 0x46, 0x21, 0x07, 0x25, 0x3C, 0x7D, 0xDA,
+    0xD5, 0x62, 0x2E, 0xD4, 0x6E, 0x44, 0x76, 0xA3, 0xF2, 0x32, 0x8A, 0xDE, 0xC1, 0xE6, 0xB7, 0x7A,
+    0xCD, 0xDE, 0x25, 0x3D, 0x59, 0x8C, 0x1F, 0x12, 0xCB, 0x7F, 0xA5, 0x92, 0xC9, 0x65, 0x65, 0xC0,
+    0x3D, 0x09, 0x63, 0xBF, 0x92, 0x97, 0x52, 0xEF, 0xCA, 0x32, 0x9C, 0x51, 0xE8, 0x5F, 0x78, 0x06,
+    0x2F, 0x43, 0x79, 0xD9, 0xE8, 0x1B, 0x2A, 0xB1, 0x52, 0x33, 0xFD, 0x8C, 0x5F, 0x1E, 0x38, 0xC2,
+    0xA4, 0xEB, 0x3C, 0x92, 0x79, 0xAA, 0x6E, 0x95, 0x54, 0xE0, 0x77, 0x47, 0xC4, 0xC5, 0x6F, 0xE6,
+    0x14, 0x77, 0xC5, 0x2C, 0xDF, 0xBF, 0x7E, 0xB2, 0x39, 0x4C, 0x86, 0x1E, 0xD8, 0xAC, 0x03, 0x60,
+    0xB9, 0xA6, 0x44, 0x4F, 0x27, 0xEB, 0xCD, 0xCF, 0x12, 0x93, 0x61, 0x6F, 0xC5, 0x9B, 0xD4, 0x53,
+    0x88, 0x5E, 0x32, 0x21, 0xB2, 0xFA, 0x4E, 0xD1, 0x18, 0x26, 0x97, 0xCB, 0xBC, 0x3D, 0xD1, 0x0C,
+    0x8F, 0xBD, 0x3D, 0x47, 0xA2, 0x91, 0x53, 0x25, 0xCE, 0xB5, 0x3A, 0x72, 0x83, 0xD5, 0x79, 0xD5,
+    0x29, 0x46, 0x44, 0xE0, 0x31, 0xC5, 0x40, 0x04, 0xD6, 0xA5, 0xFB, 0x58, 0xC5, 0xBE, 0x4D, 0x01,
+    0x28, 0xE7, 0x9E, 0xF7, 0x8A, 0xF3, 0x76, 0x52, 0xC4, 0x34, 0x26, 0x25, 0x81, 0xF4, 0xC7, 0xA5,
+    0xE2, 0xA0, 0x3C, 0x68, 0x6F, 0x8B, 0xAF, 0xA2, 0x61, 0x5E, 0x1E, 0x1A, 0xA4, 0x9E, 0x38, 0x77,
+    0x09, 0xFB, 0x8D, 0x23, 0x52, 0x78, 0x9E, 0xAC, 0x1B, 0xEE, 0xAB, 0xBD, 0xF7, 0xE5, 0xA7, 0x03,
+    0xDB, 0x16, 0xB8, 0xE6, 0x63, 0x7C, 0x04, 0x7B, 0xDD, 0x06, 0xDC, 0xD1, 0xF8, 0x1B, 0xCB, 0xA1,
+    0x44, 0x1B, 0x45, 0x33, 0x04, 0x4B, 0xA2, 0x13, 0xA7, 0x27, 0x22, 0x05, 0x09, 0xDA, 0x5E, 0xE5,
+    0xE8, 0x1C, 0x4C, 0x7D, 0xAE, 0x09, 0x88, 0xA4, 0x77, 0x90, 0x15, 0xF0, 0xAA, 0xF7, 0x89, 0xD3,
+    0xD6, 0x50, 0xC0, 0x9A, 0x2F, 0x07,
 ];
 
 pub const BLOCK_KEY: [u8; 32] = [
@@ -70,15 +100,19 @@ pub(crate) fn make_write_cap() -> Result<WriteCap> {
         issued_by: Principal(Hash::Sha2_256(PRINCIPAL)),
         path: Path::try_from("contacts/emergency").map_err(|err| Error::Message(err.to_string()))?,
         expires: Epoch(1649904316),
-        signing_key: Key::Secp256k1 { public: SECP256K1_KEY, private: None },
-        signature: Signature::Secp256k1(SIGNATURE),
+        signing_key: Key::Rsa {
+            public: Vec::from(RSA_KEY), private: None, padding: RsaPadding::Pkcs1
+        },
+        signature: Signature::Rsa(SIGNATURE),
         next: Some(Box::from(WriteCap {
             issued_to: Principal(Hash::Sha2_256(PRINCIPAL)),
             issued_by: Principal(Hash::Sha2_256(PRINCIPAL)),
             path: Path::try_from("contacts").map_err(|err| Error::Message(err.to_string()))?,
             expires: Epoch(1649994316),
-            signing_key: Key::Secp256k1 { public: SECP256K1_KEY, private: None },
-            signature: Signature::Secp256k1(SIGNATURE),
+            signing_key: Key::Rsa {
+                public: Vec::from(RSA_KEY), private: None, padding: RsaPadding::Pkcs1
+            },
+            signature: Signature::Rsa(SIGNATURE),
             next: None,
         }))
     })
@@ -102,6 +136,6 @@ pub(crate) fn make_block() -> Result<Block> {
         read_caps,
         write_cap,
         body: Cryptotext::Plain(Vec::from(PAYLOAD)),
-        signature: Signature::Secp256k1(SIGNATURE)
+        signature: Signature::Rsa(SIGNATURE)
     })
 }