Browse Source

Started wireframing the crypto module.

Matthew Carr 2 years ago
parent
commit
fac63e325c
4 changed files with 65 additions and 17 deletions
  1. 1 1
      README.md
  2. 37 0
      crates/node/src/crypto.rs
  3. 13 6
      crates/node/src/main.rs
  4. 14 10
      crates/node/src/serde_tests.rs

+ 1 - 1
README.md

@@ -3,7 +3,7 @@ In broad strokes, theses are the phases of development.
 
 ## Phase 1: Foundations
 * Definition of the main data types.
-* Definition of the binary format used to serialize all data structures.
+* Definition of the binary format used to serialize all data structures. (Done 2022/04/14)
 * Creation of a cryptographic abstraction layer which will defer to openssl for the time being.
 This module will include type definitions for hashes, keys and signatures. It will define
 functions for:

+ 37 - 0
crates/node/src/crypto.rs

@@ -0,0 +1,37 @@
+/// Functions for performing cryptographic operations on the main data structures.
+
+use super::*;
+
+/// Errors that can occur during cryptographic operations.
+pub(crate) enum Error {
+    NoReadCap
+}
+
+type Result<T> = std::result::Result<T, Error>;
+
+fn decrypt<T>(_ciphertext: &Cryptotext<T>, _key: &Key) -> Result<T> {
+    unimplemented!();
+}
+
+fn decrypt_in_place(_ciphertext: &mut [u8], _key: &Key) -> Result<()> {
+    unimplemented!();
+}
+
+#[allow(dead_code)]
+pub(crate) fn decrypt_block(
+    versioned_block: &mut VersionedBlock, principal: &Principal, key: &Key
+) -> Result<()> {
+    let VersionedBlock::V0(block) = versioned_block;
+    let body = match &mut block.body {
+        Cryptotext::Plain(_) => return Ok(()),
+        Cryptotext::Cipher(body) => body
+    };
+    let read_cap = block.read_caps.get(principal).ok_or(Error::NoReadCap)?;
+    let block_key = decrypt(read_cap, key)?;
+    decrypt_in_place(body, &block_key)?;
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+}

+ 13 - 6
crates/node/src/main.rs

@@ -10,6 +10,8 @@ use serde_big_array::BigArray;
 #[cfg(test)]
 mod serde_tests;
 
+mod crypto;
+
 /// A Block tagged with its version number.
 #[allow(dead_code)]
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -26,13 +28,13 @@ struct Block {
     path: Path,
     /// This field contains a collection of `ReadCap`s indexed by the principal who holds them.
     /// `ReadCap`s are envelopments of the key used to encrypt this block.
-    read_caps: HashMap<Principal, Ciphertext<Key>>,
+    read_caps: HashMap<Principal, Cryptotext<Key>>,
     /// This field is used to verify that the signer of this block had permission to write it.
     /// It contains a certificate chain that must lead back to the root key for the tree this block
     /// is part of.
     write_cap: WriteCap,
     /// The encrypted data contained in this block.
-    body: Ciphertext<Vec<u8>>,
+    body: Cryptotext<Vec<u8>>,
     /// The contents of the block are covered by a digital signature contained in this field.  
     signature: Signature
 }
@@ -44,7 +46,7 @@ struct ReadCap {
     /// The principal this `ReadCap` was issued to.
     issued_to: Principal,
     /// An encipherment of a block key using the public key of the principal.
-    key: Ciphertext<Key>,
+    key: Cryptotext<Key>,
 }
 
 /// Verifies that a principal is authorized to write blocks in a tree.
@@ -102,9 +104,14 @@ struct FragmentRecord {
 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Hashable)]
 struct Principal(Hash);
 
-/// Encrypted data.
+/// Data that may or may not be encrypted.
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
-struct Ciphertext<T>(T);
+enum Cryptotext<T> {
+    /// The inner value of `T` is in plaintext.
+    Plain(T),
+    /// The inner value of `T` is in ciphertext.
+    Cipher(T),
+}
 
 /// An identifier for a block in a tree.
 #[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -159,7 +166,7 @@ fn main() {
 
 impl ReadCap {
     #[allow(dead_code)]
-    fn new(issued_to: Hash, key: Ciphertext<Key>) -> ReadCap {
+    fn new(issued_to: Hash, key: Cryptotext<Key>) -> ReadCap {
         ReadCap { issued_to: Principal(issued_to), key }
     }
 }

+ 14 - 10
crates/node/src/serde_tests.rs

@@ -96,7 +96,7 @@ fn roundtrip_write_cap() -> Result<()> {
 }
 
 fn make_read_cap() -> ReadCap {
-    ReadCap::new(Hash::Sha2_256(PRINCIPAL), Ciphertext(Key::Xsalsa20Poly1305(KEY)))
+    ReadCap::new(Hash::Sha2_256(PRINCIPAL), Cryptotext::Plain(Key::Xsalsa20Poly1305(KEY)))
 }
 
 #[test]
@@ -108,21 +108,25 @@ fn roundtrip_read_cap() -> Result<()> {
     Ok(())
 }
 
-#[test]
-fn roundtrip_versioned_block() -> Result<()> {
+fn make_block() -> Result<Block> {
     let mut read_caps = HashMap::new();
     {
         let read_cap = make_read_cap();
         read_caps.insert(read_cap.issued_to, read_cap.key);
     }
     let write_cap = make_write_cap()?;
-    let expected = VersionedBlock::V0(Block {
-        path: Path::try_from("apps/verse").map_err(|err| Error::Message(err.to_string()))?,
-        read_caps,
-        write_cap,
-        body: Ciphertext(Vec::from(PAYLOAD)),
-        signature: Signature::Ed25519(SIGNATURE)
-    });
+    Ok(Block {
+            path: Path::try_from("apps/verse").map_err(|err| Error::Message(err.to_string()))?,
+            read_caps,
+            write_cap,
+            body: Cryptotext::Plain(Vec::from(PAYLOAD)),
+            signature: Signature::Ed25519(SIGNATURE)
+    })
+}
+
+#[test]
+fn roundtrip_versioned_block() -> Result<()> {
+    let expected = VersionedBlock::V0(make_block()?);
     let ser_result = to_vec(&expected);
     let de_result = from_vec(&ser_result?);
     assert_eq!(expected, de_result?);