Skip to content

Commit

Permalink
Reduce code duplication & remove AesKey struct
Browse files Browse the repository at this point in the history
  • Loading branch information
matheus23 committed Jul 7, 2023
1 parent e3fbf24 commit e4ba8f9
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 152 deletions.
2 changes: 1 addition & 1 deletion wnfs/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub enum ShareError {
AccessKeyNotFound,
}

/// AES-GCM errors.
/// Symmetric encryption errors.
#[derive(Debug, Error)]
pub enum CryptError {
#[error("Unable to encrypt data: {0}")]
Expand Down
2 changes: 1 addition & 1 deletion wnfs/src/private/encrypted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
/// Any data wrapped like this **must not have low entropy**.
///
/// For anything that could potentially have low entropy,
/// please use AES-GCM instead via `SnapshotKey`.
/// please use XChaCha20-Poly1305 instead via `SnapshotKey`.
///
/// When serialized or deserialized this will only
/// ever emit or consume ciphertexts.
Expand Down
5 changes: 2 additions & 3 deletions wnfs/src/private/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,15 +582,14 @@ impl PrivateFile {
}

fn create_revision_name(file_block_name: &Name, key: &SnapshotKey) -> Name {
let revision_segment =
NameSegment::from_digest(Sha3_256::new().chain_update(key.0.as_bytes()));
let revision_segment = NameSegment::from_digest(Sha3_256::new().chain_update(key.0));
file_block_name.with_segments_added(Some(revision_segment))
}

/// Creates the label for a block of a file.
fn create_block_label(key: &SnapshotKey, index: usize, file_revision_name: &Name) -> Name {
let key_hash = Sha3_256::new()
.chain_update(key.0.as_bytes())
.chain_update(key.0)
.chain_update(index.to_le_bytes());
let elem = NameSegment::from_digest(key_hash);

Expand Down
84 changes: 0 additions & 84 deletions wnfs/src/private/keys/aes.rs

This file was deleted.

2 changes: 0 additions & 2 deletions wnfs/src/private/keys/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
mod access;
mod aes;
mod exchange;
mod privateref;

pub use self::exchange::*;
pub use access::*;
pub use aes::*;
pub(crate) use privateref::*;
33 changes: 12 additions & 21 deletions wnfs/src/private/keys/privateref.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use super::KEY_BYTE_SIZE;
use crate::{
error::{CryptError, FsError},
private::{PrivateRefSerializable, TemporalKey},
error::FsError,
private::{PrivateRefSerializable, TemporalKey, KEY_BYTE_SIZE},
};
use aes_kw::KekAes256;
use anyhow::{anyhow, Result};
use anyhow::Result;
use libipld_core::cid::Cid;
use serde::{de::Error as DeError, ser::Error as SerError, Deserialize, Serialize};
use std::fmt::Debug;
Expand Down Expand Up @@ -62,11 +60,9 @@ impl PrivateRef {
parent_temporal_key: &TemporalKey,
) -> Result<PrivateRefSerializable> {
let snapshot_key = self.temporal_key.derive_snapshot_key();
// encrypt ratchet key
let temporal_key_as_kek = KekAes256::from(parent_temporal_key.0.clone().bytes());
let temporal_key_wrapped = temporal_key_as_kek
.wrap_with_padding_vec(self.temporal_key.0.as_bytes())
.map_err(|e| CryptError::UnableToEncrypt(anyhow!(e)))?;

// encrypt temporal key
let temporal_key_wrapped = parent_temporal_key.key_wrap_encrypt(&self.temporal_key.0)?;

Ok(PrivateRefSerializable {
revision_name_hash: self.revision_name_hash,
Expand All @@ -80,25 +76,20 @@ impl PrivateRef {
private_ref: PrivateRefSerializable,
parent_temporal_key: &TemporalKey,
) -> Result<Self> {
// TODO: Move key wrapping & unwrapping logic to impl TemporalKey
let temporal_key_as_kek = KekAes256::from(parent_temporal_key.0.clone().bytes());

let temporal_key_raw: [u8; KEY_BYTE_SIZE] = temporal_key_as_kek
.unwrap_with_padding_vec(&private_ref.temporal_key)
.map_err(|e| CryptError::UnableToDecrypt(anyhow!(e)))?
.try_into()
.map_err(|e: Vec<u8>| {
let temporal_key_decrypted =
parent_temporal_key.key_wrap_decrypt(&private_ref.temporal_key)?;

let temporal_key_raw: [u8; KEY_BYTE_SIZE] =
temporal_key_decrypted.try_into().map_err(|e: Vec<u8>| {
FsError::InvalidDeserialization(format!(
"Expected 32 bytes for ratchet key, but got {}",
e.len()
))
})?;

let temporal_key = temporal_key_raw.into();

Ok(Self {
revision_name_hash: private_ref.revision_name_hash,
temporal_key,
temporal_key: temporal_key_raw.into(),
content_cid: private_ref.content_cid,
})
}
Expand Down
2 changes: 1 addition & 1 deletion wnfs/src/private/node/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl PrivateNodeHeader {
/// ```
/// use std::rc::Rc;
/// use wnfs::private::{
/// PrivateFile, AesKey,
/// PrivateFile,
/// forest::{hamt::HamtForest, traits::PrivateForest},
/// };
/// use chrono::Utc;
Expand Down
71 changes: 32 additions & 39 deletions wnfs/src/private/node/keys.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
error::CryptError,
private::{AesKey, KEY_BYTE_SIZE, NONCE_SIZE},
};
use crate::error::CryptError;
use aes_kw::KekAes256;
use anyhow::{anyhow, Result};
use chacha20poly1305::{
Expand All @@ -15,17 +12,33 @@ use skip_ratchet::Ratchet;
use std::fmt::Debug;
use wnfs_hamt::Hasher;

//--------------------------------------------------------------------------------------------------
// Constants
//--------------------------------------------------------------------------------------------------

pub(crate) const NONCE_SIZE: usize = 24;
pub(crate) const AUTHENTICATION_TAG_SIZE: usize = 16;
pub const KEY_BYTE_SIZE: usize = 32;

//--------------------------------------------------------------------------------------------------
// Type Definitions
//--------------------------------------------------------------------------------------------------

/// The key used to encrypt the content of a node.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct SnapshotKey(pub AesKey);
pub struct SnapshotKey(
#[serde(serialize_with = "crate::utils::serialize_byte_slice32")]
#[serde(deserialize_with = "crate::utils::deserialize_byte_slice32")]
pub [u8; KEY_BYTE_SIZE],
);

/// The key used to encrypt the header section of a node.
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct TemporalKey(pub AesKey);
pub struct TemporalKey(
#[serde(serialize_with = "crate::utils::serialize_byte_slice32")]
#[serde(deserialize_with = "crate::utils::deserialize_byte_slice32")]
pub [u8; KEY_BYTE_SIZE],
);

//--------------------------------------------------------------------------------------------------
// Constants
Expand All @@ -48,8 +61,7 @@ impl TemporalKey {
/// Turn this TemporalKey, which gives read access to the current revision and any future
/// revisions into a SnapshotKey, which only gives read access to the current revision.
pub fn derive_snapshot_key(&self) -> SnapshotKey {
let TemporalKey(key) = self;
SnapshotKey::from(Sha3_256::hash(&key.as_bytes()))
SnapshotKey::from(Sha3_256::hash(&self.0))
}

/// Encrypt a cleartext with this temporal key.
Expand All @@ -59,7 +71,7 @@ impl TemporalKey {
/// The resulting ciphertext is 8 bytes longer than the next multiple of 8 bytes of the
/// cleartext input length.
pub fn key_wrap_encrypt(&self, cleartext: &[u8]) -> Result<Vec<u8>> {
Ok(KekAes256::from(self.0.clone().bytes())
Ok(KekAes256::from(self.0)
.wrap_with_padding_vec(cleartext)
.map_err(|e| CryptError::UnableToEncrypt(anyhow!(e)))?)
}
Expand All @@ -71,7 +83,7 @@ impl TemporalKey {
/// The input ciphertext is 8 bytes longer than the next multiple of 8 bytes of the
/// resulting cleartext length.
pub fn key_wrap_decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
Ok(KekAes256::from(self.0.clone().bytes())
Ok(KekAes256::from(self.0)
.unwrap_with_padding_vec(ciphertext)
.map_err(|e| CryptError::UnableToEncrypt(anyhow!(e)))?)
}
Expand All @@ -83,7 +95,7 @@ impl SnapshotKey {
/// # Examples
///
/// ```
/// use wnfs::private::{AesKey, SnapshotKey};
/// use wnfs::private::SnapshotKey;
/// use wnfs::common::utils;
/// use rand::thread_rng;
///
Expand All @@ -99,7 +111,7 @@ impl SnapshotKey {
pub fn encrypt(&self, data: &[u8], rng: &mut impl CryptoRngCore) -> Result<Vec<u8>> {
let nonce = Self::generate_nonce(rng);

let key = self.0.clone().bytes().into();
let key = self.0.into();
let cipher_text = XChaCha20Poly1305::new(&key)
.encrypt(&nonce, data)
.map_err(|e| CryptError::UnableToEncrypt(anyhow!(e)))?;
Expand All @@ -118,7 +130,7 @@ impl SnapshotKey {
///
/// The authentication tag is required for decryption and usually appended to the ciphertext.
pub(crate) fn encrypt_in_place(&self, nonce: &XNonce, buffer: &mut [u8]) -> Result<Tag> {
let key = self.0.clone().bytes().into();
let key = self.0.into();
let tag = XChaCha20Poly1305::new(&key)
.encrypt_in_place_detached(nonce, &[], buffer)
.map_err(|e| CryptError::UnableToEncrypt(anyhow!(e)))?;
Expand All @@ -130,7 +142,7 @@ impl SnapshotKey {
/// # Examples
///
/// ```
/// use wnfs::private::{AesKey, SnapshotKey};
/// use wnfs::private::SnapshotKey;
/// use wnfs::common::utils;
/// use rand::thread_rng;
///
Expand All @@ -145,7 +157,7 @@ impl SnapshotKey {
/// ```
pub fn decrypt(&self, cipher_text: &[u8]) -> Result<Vec<u8>> {
let (nonce_bytes, data) = cipher_text.split_at(NONCE_SIZE);
let key = self.0.clone().bytes().into();
let key = self.0.into();
let nonce = XNonce::from_slice(nonce_bytes);

Ok(XChaCha20Poly1305::new(&key)
Expand All @@ -164,49 +176,30 @@ impl SnapshotKey {
tag: &Tag,
buffer: &mut [u8],
) -> Result<()> {
let key = self.0.clone().bytes().into();
let key = self.0.into();
XChaCha20Poly1305::new(&key)
.decrypt_in_place_detached(nonce, &[], buffer, tag)
.map_err(|e| CryptError::UnableToDecrypt(anyhow!(e)))?;
Ok(())
}
}

impl From<AesKey> for TemporalKey {
fn from(key: AesKey) -> Self {
Self(key)
}
}

impl From<[u8; KEY_BYTE_SIZE]> for TemporalKey {
fn from(key: [u8; KEY_BYTE_SIZE]) -> Self {
Self(AesKey::new(key))
Self(key)
}
}

impl From<&Ratchet> for TemporalKey {
fn from(ratchet: &Ratchet) -> Self {
Self::from(AesKey::new(
ratchet.derive_key(TEMPORAL_KEY_DSS).finalize().into(),
))
}
}

impl From<AesKey> for SnapshotKey {
fn from(key: AesKey) -> Self {
Self(key)
let key: [u8; KEY_BYTE_SIZE] = ratchet.derive_key(TEMPORAL_KEY_DSS).finalize().into();
Self::from(key)
}
}

impl From<[u8; KEY_BYTE_SIZE]> for SnapshotKey {
fn from(key: [u8; KEY_BYTE_SIZE]) -> Self {
Self(AesKey::new(key))
}
}

impl From<SnapshotKey> for AesKey {
fn from(key: SnapshotKey) -> Self {
key.0
Self(key)
}
}

Expand Down

0 comments on commit e4ba8f9

Please sign in to comment.