Browse Source

Added key generation.

Matthew Carr 2 years ago
parent
commit
72166ca2c9
2 changed files with 77 additions and 13 deletions
  1. 63 8
      crates/node/src/crypto.rs
  2. 14 5
      crates/node/src/test_helpers.rs

+ 63 - 8
crates/node/src/crypto.rs

@@ -6,6 +6,9 @@ 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,
 };
 use serde_block_tree::{self, to_vec, from_vec};
 use serde::de::{DeserializeOwned};
@@ -55,7 +58,15 @@ pub enum Hash {
 #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
 pub enum Signature {
     #[serde(with = "BigArray")]
-    Ed25519([u8; 64]),
+    Secp256k1([u8; 64]),
+}
+
+/// Identifies a type of cryptographic key. The variants of this enum match those of `Key`.
+pub enum KeyId {
+    // TODO: Write a macro to generate this from `Key`.
+    Aes256Cbc,
+    Aes256Ctr,
+    Secp256k1,
 }
 
 /// A cryptographic key.
@@ -73,9 +84,10 @@ pub enum Key {
         key: [u8; 32],
         iv: [u8; 16]
     },
-    Ed25519 {
-        public: [u8; 32],
-        private: Option<[u8; 32]>
+    Secp256k1 {
+        #[serde(with = "BigArray")]
+        public: [u8; 88],
+        private: Option<Vec<u8>>
     },
 }
 
@@ -86,7 +98,7 @@ impl Key {
         match self {
             Key::Aes256Cbc { key, .. } => Some(key),
             Key::Aes256Ctr { key, .. } => Some(key),
-            Key::Ed25519 { private, .. } => match private {
+            Key::Secp256k1 { private, .. } => match private {
                 Some(key) => Some(key.as_slice()),
                 None => None,
             },
@@ -100,6 +112,34 @@ impl Key {
             _ => None,
         }
     }
+
+    fn generate(id: KeyId) -> Result<Key> {
+        match id {
+            KeyId::Aes256Cbc => {
+                let mut key = [0; 32];
+                let mut iv = [0; 16];
+                rand_bytes(&mut key).map_err(Error::from)?;
+                rand_bytes(&mut iv).map_err(Error::from)?;
+                Ok(Key::Aes256Cbc { key, iv })
+            },
+            KeyId::Aes256Ctr => {
+                let mut key = [0; 32];
+                let mut iv = [0; 16];
+                rand_bytes(&mut key).map_err(Error::from)?;
+                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);
+                let private = Some(key.private_key_to_der().map_err(Error::from)?);
+                Ok(Key::Secp256k1 { public, private })
+            },
+        }
+    }
 }
 
 enum EncryptionAlgo<'a> {
@@ -144,7 +184,7 @@ impl<'a> TryFrom<&'a Key> for EncryptionAlgo<'a> {
                 key: key_slice,
                 iv: Some(iv),
             }),
-            Key::Ed25519 { public, .. } => {
+            Key::Secp256k1 { public, .. } => {
                 let pkey = PKey::public_key_from_der(public.as_slice())
                     .map_err(|err| Error::Message(err.to_string()));
                 Ok(EncryptionAlgo::Asymmetric(pkey?))
@@ -195,8 +235,8 @@ impl<'a> TryFrom<&'a Key> for DecryptionAlgo<'a> {
                 key: key_slice,
                 iv: Some(iv),
             }),
-            Key::Ed25519 { private, .. } => {
-                let private = private.ok_or(Error::MissingPrivateKey)?;
+            Key::Secp256k1 { 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?))
             }
@@ -320,6 +360,8 @@ mod tests {
 
     /// Tests that validate the dependencies of this module.
     mod dependency_tests {
+        use super::*;
+
         /// This test validates that data decrypted with the `Crypter` API matches data that was
         /// previously encrypted using it.
         #[test]
@@ -333,5 +375,18 @@ mod tests {
 
             assert_eq!(expected, actual.as_slice());
         }
+
+        /// Tests that the keys for the SECP256K1 curve are the expected sizes.
+        #[test]
+        fn secp256k1_key_lengths() {
+            let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
+            let key = EcKey::generate(&group).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!(88, public_len);
+            assert_eq!(118, private_len);
+        }
     }
 }

+ 14 - 5
crates/node/src/test_helpers.rs

@@ -31,6 +31,15 @@ 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,
+];
+
 pub const BLOCK_KEY: [u8; 32] = [
     0xEE, 0x76, 0xD6, 0xDC, 0x6D, 0x94, 0x1D, 0x95, 0xC2, 0x57, 0x94, 0x46, 0xA2, 0x97, 0x8F, 0x5B,
     0x59, 0xE1, 0x7E, 0xE4, 0x3B, 0xB1, 0x69, 0x88, 0x5D, 0x16, 0x30, 0x5A, 0x50, 0xDB, 0x58, 0x65,
@@ -61,15 +70,15 @@ 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::Ed25519 { public: KEY, private: None },
-        signature: Signature::Ed25519(SIGNATURE),
+        signing_key: Key::Secp256k1 { public: SECP256K1_KEY, private: None },
+        signature: Signature::Secp256k1(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::Ed25519 { public: KEY, private: None },
-            signature: Signature::Ed25519(SIGNATURE),
+            signing_key: Key::Secp256k1 { public: SECP256K1_KEY, private: None },
+            signature: Signature::Secp256k1(SIGNATURE),
             next: None,
         }))
     })
@@ -93,6 +102,6 @@ pub(crate) fn make_block() -> Result<Block> {
         read_caps,
         write_cap,
         body: Cryptotext::Plain(Vec::from(PAYLOAD)),
-        signature: Signature::Ed25519(SIGNATURE)
+        signature: Signature::Secp256k1(SIGNATURE)
     })
 }