Skip to content

Commit

Permalink
fix: deserialization issue
Browse files Browse the repository at this point in the history
  • Loading branch information
mikesposito committed Dec 1, 2023
1 parent 6e3ca14 commit a430b36
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 36 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ fn main() {
// Key generation (32bytes for the key, 16 bytes for salt)
let key = Key::<32, 16>::new(b"my password", 900_000); // 900K rounds

// Using Enclave for data encapsulation
// Using Enclave for data encapsulation (&str metadata, 8-byte nonce)
let enclave =
Enclave::from_plain_bytes("Some metadata", key.pubk, b"Some bytes to encrypt".to_vec())
Enclave::<&str, 8>::from_plain_bytes("Some metadata", key.pubk, b"Some bytes to encrypt".to_vec())
.unwrap();

// Get encrypted bytes (ciphertext)
Expand Down
6 changes: 3 additions & 3 deletions benches/src/chacha20.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use secured_cipher::chacha20::ChaChaStream;
use secured_cipher::chacha20::{ChaChaStream, KEY_SIZE, NONCE_SIZE};

const KB: usize = 1024;

fn bench(c: &mut Criterion) {
let mut group = c.benchmark_group("ChaChaStream");

for size in &[KB, 2 * KB, 4 * KB, 8 * KB, 16 * KB] {
let key = [0u8; 32];
let iv = [1u8; 8];
let key = [0u8; KEY_SIZE];
let iv = [1u8; NONCE_SIZE];

group.throughput(Throughput::Bytes(*size as u64));

Expand Down
5 changes: 3 additions & 2 deletions benches/src/enclave.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use secured_cipher::chacha20::{KEY_SIZE, NONCE_SIZE};
use secured_enclave::Enclave;

const KB: usize = 1024;
Expand All @@ -7,13 +8,13 @@ fn bench(c: &mut Criterion) {
let mut group = c.benchmark_group("enclave");

for size in &[KB, 2 * KB, 4 * KB, 8 * KB, 16 * KB] {
let key = [0u8; 32];
let key = [0u8; KEY_SIZE];

group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::new("encrypt", size), size, |b, &_size| {
b.iter(|| {
let buf = vec![0u8; *size];
Enclave::from_plain_bytes("Metadata", key, buf)
Enclave::<&str, NONCE_SIZE>::from_plain_bytes("Metadata", key, buf)
});
});
}
Expand Down
8 changes: 8 additions & 0 deletions cipher/src/chacha20/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ pub const STATE_WORDS: usize = 16;
/// The standard number of rounds is 20.
pub const ROUNDS: usize = 20;

/// Size of the nonce in bytes.
/// The nonce is a 64-bit (8 bytes) value used to make each block unique.
pub const NONCE_SIZE: usize = 8;

/// Size of the key in bytes.
/// The key is a 256-bit (32 bytes) value used for encryption and decryption.
pub const KEY_SIZE: usize = 32;

/// Performs the quarter round operation on the state.
///
/// This operation modifies four words in the state as per the ChaCha20 algorithm's quarter round rules.
Expand Down
17 changes: 14 additions & 3 deletions cipher/src/chacha20/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod stream;

use crate::{Bytes, Cipher, Slice};
pub use stream::ChaChaStream;
pub use self::core::{NONCE_SIZE, KEY_SIZE};

/// Represents the ChaCha20 encryption/decryption cipher.
///
Expand All @@ -29,7 +30,17 @@ impl ChaCha20 {
///
/// # Returns
/// A new instance of `ChaCha20`.
pub fn new(key: [u8; 32], iv: [u8; 8]) -> Self {
pub fn new(key: &[u8], iv: &[u8]) -> Self {
let key: [u8; 32] = match key.len() {
KEY_SIZE => key.try_into().unwrap(),
_ => panic!("Invalid key length"),
};

let iv: [u8; 8] = match iv.len() {
NONCE_SIZE => iv.try_into().unwrap(),
_ => panic!("Invalid IV length"),
};

Self {
stream: ChaChaStream::new(key, iv),
}
Expand Down Expand Up @@ -82,7 +93,7 @@ mod tests {

#[test]
fn it_should_encrypt_data() {
let mut cipher = ChaCha20::new(KEY, IV);
let mut cipher = ChaCha20::new(&KEY, &IV);
let encrypted_data = cipher.encrypt(&PLAINTEXT);

assert_eq!(encrypted_data.len(), 64);
Expand All @@ -91,7 +102,7 @@ mod tests {

#[test]
fn it_should_decrypt_data() {
let mut cipher = ChaCha20::new(KEY, IV);
let mut cipher = ChaCha20::new(&KEY, &IV);
let decrypted_data = cipher.decrypt(&CIPHERTEXT);

assert_eq!(decrypted_data.len(), 64);
Expand Down
7 changes: 4 additions & 3 deletions cipher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! let nonce: [u8; 8] = [0; 8]; // Replace with your nonce
//! let data: &[u8] = b"Your data here"; // Data to be encrypted
//!
//! let mut cipher = ChaCha20::new(key, nonce);
//! let mut cipher = ChaCha20::new(&key, &nonce);
//! let encrypted_data = cipher.encrypt(data);
//! println!("Encrypted data: {:?}", encrypted_data);
//! ```
Expand All @@ -40,7 +40,7 @@
//! let nonce: [u8; 8] = [0; 8]; // Replace with your nonce
//! let encrypted_data: &[u8] = &[0x1, 0x2, 0x3, 0x4]; // Replace with your encrypted data
//!
//! let mut cipher = ChaCha20::new(key, nonce);
//! let mut cipher = ChaCha20::new(&key, &nonce);
//! let decrypted_data = cipher.decrypt(encrypted_data);
//! println!("Decrypted data: {:?}", decrypted_data);
//! ```
Expand All @@ -54,8 +54,9 @@
//! suitable for various cryptographic needs. Whether you need high-level interfaces with `ChaCha20`
//! or low-level control with `ChaChaStream`, `secured-cipher` is equipped to meet your cryptographic requirements.
pub use secured_cipher_key::{random_bytes, Key};
pub mod chacha20;
pub use secured_cipher_key::{random_bytes, Key};
// pub use chacha20;

/// A type alias for representing a slice of bytes.
/// This is commonly used for raw data input/output in cryptographic operations.
Expand Down
48 changes: 30 additions & 18 deletions enclave/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub mod errors;

pub use errors::EnclaveError;
use secured_cipher::{chacha20::ChaCha20, random_bytes, Cipher};
use secured_cipher::{chacha20::{ChaCha20, core::KEY_SIZE}, random_bytes, Cipher};

/// `Enclave` acts as a container for encrypted data, including metadata and the encrypted content itself.
///
Expand All @@ -11,18 +11,18 @@ use secured_cipher::{chacha20::ChaCha20, random_bytes, Cipher};
/// # Type Parameters
/// * `T`: The type of metadata associated with the encrypted data.
#[derive(Debug, Clone)]
pub struct Enclave<T> {
pub struct Enclave<T, const NONCE_SIZE: usize> {
/// Metadata associated with the encrypted data.
pub metadata: T,

/// The encrypted data.
encrypted_bytes: Box<[u8]>,

/// The nonce used in the encryption process, 8 bytes long (ChaCha20).
nonce: [u8; 8],
nonce: [u8; NONCE_SIZE],
}

impl<T> Enclave<T> {
impl<T, const NONCE_SIZE: usize> Enclave<T, NONCE_SIZE> {
/// Creates a new `Enclave` instance from unencrypted data.
///
/// # Arguments
Expand All @@ -34,11 +34,11 @@ impl<T> Enclave<T> {
/// A `Result` containing the newly created `Enclave` instance, or an error string if encryption fails.
pub fn from_plain_bytes(
metadata: T,
key: [u8; 32],
key: [u8; KEY_SIZE],
plain_bytes: Vec<u8>,
) -> Result<Self, String> {
let nonce = random_bytes::<8>();
let mut cipher = ChaCha20::new(key, nonce);
let nonce = random_bytes::<NONCE_SIZE>();
let mut cipher = ChaCha20::new(&key, &nonce);

let encrypted_bytes = cipher.encrypt(&plain_bytes);

Expand All @@ -56,14 +56,14 @@ impl<T> Enclave<T> {
///
/// # Returns
/// A `Result` containing the decrypted data as a vector of bytes, or an error string if decryption fails.
pub fn decrypt(&self, key: [u8; 32]) -> Result<Vec<u8>, String> {
let mut cipher = ChaCha20::new(key, self.nonce);
pub fn decrypt(&self, key: [u8; KEY_SIZE]) -> Result<Vec<u8>, String> {
let mut cipher = ChaCha20::new(&key, &self.nonce);

Ok(cipher.decrypt(&self.encrypted_bytes))
}
}

impl<T> From<Enclave<T>> for Vec<u8>
impl<T, const NONCE_SIZE: usize> From<Enclave<T, NONCE_SIZE>> for Vec<u8>
where
T: TryFrom<Vec<u8>> + Into<Vec<u8>>,
{
Expand All @@ -74,7 +74,7 @@ where
///
/// # Returns
/// A `Vec<u8>` representing the serialized enclave.
fn from(enclave: Enclave<T>) -> Vec<u8> {
fn from(enclave: Enclave<T, NONCE_SIZE>) -> Vec<u8> {
let mut bytes: Vec<u8> = vec![];
let metadata_bytes = enclave.metadata.into();

Expand All @@ -87,7 +87,7 @@ where
}
}

impl<T> TryFrom<Vec<u8>> for Enclave<T>
impl<T, const NONCE_SIZE: usize> TryFrom<Vec<u8>> for Enclave<T, NONCE_SIZE>
where
T: TryFrom<Vec<u8>> + Into<Vec<u8>>,
{
Expand All @@ -105,8 +105,8 @@ where
let metadata = T::try_from(bytes[1..metadata_len as usize + 1].to_vec()).or(Err(
EnclaveError::Deserialization("error deserializing metadata".to_string()),
))?;
let encrypted_bytes = bytes[metadata_len as usize + 1..bytes.len() - 24].to_vec();
let nonce = bytes[bytes.len() - 24..bytes.len()].to_vec();
let encrypted_bytes = bytes[metadata_len as usize + 1..bytes.len() - NONCE_SIZE].to_vec();
let nonce = bytes[bytes.len() - NONCE_SIZE..bytes.len()].to_vec();

Ok(Enclave {
metadata,
Expand All @@ -118,7 +118,7 @@ where
}
}

impl<T> PartialEq for Enclave<T>
impl<T, const NONCE_SIZE: usize> PartialEq for Enclave<T, NONCE_SIZE>
where
T: PartialEq + TryFrom<Vec<u8>> + Into<Vec<u8>>,
{
Expand Down Expand Up @@ -149,7 +149,7 @@ mod tests {
let key: Key<32, 16> = Key::new(b"my password", 10_000);
let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();

let safe = Enclave::from_plain_bytes("metadata", key.pubk, bytes);
let safe = Enclave::<&str, 8>::from_plain_bytes("metadata", key.pubk, bytes);

assert!(safe.is_ok());
assert_eq!(safe.unwrap().metadata, "metadata");
Expand All @@ -163,7 +163,7 @@ mod tests {
fn it_should_decrypt_enclave() {
let key: Key<32, 16> = Key::new(b"my password", 10_000);
let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
let safe = Enclave::from_plain_bytes("metadata", key.pubk, bytes.clone()).unwrap();
let safe = Enclave::<&str, 8>::from_plain_bytes("metadata", key.pubk, bytes.clone()).unwrap();

let decrypted_bytes = safe.decrypt(key.pubk);

Expand All @@ -175,12 +175,24 @@ mod tests {
fn it_should_fail_with_wrong_key() {
let key: Key<32, 16> = Key::new(b"my password", 10_000);
let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
let safe = Enclave::from_plain_bytes("metadata", key.pubk, bytes.clone()).unwrap();
let safe = Enclave::<&str, 8>::from_plain_bytes("metadata", key.pubk, bytes.clone()).unwrap();
let wrong_key: Key<32, 16> = Key::new(b"my wrong password", 10_000);

let decrypted_bytes = safe.decrypt(wrong_key.pubk).unwrap();

assert_ne!(decrypted_bytes, bytes);
}

#[test]
fn it_should_serialize_and_deserialize_to_bytes() {
let key: Key<32, 16> = Key::new(b"my password", 10_000);
let bytes = [0u8, 1u8, 2u8, 3u8, 4u8].to_vec();
let enclave = Enclave::<[u8; 2], 8>::from_plain_bytes([0_u8, 1_u8], key.pubk, bytes.clone()).unwrap();

let serialized: Vec<u8> = enclave.clone().into();
let deserialized = Enclave::try_from(serialized).unwrap();

assert_eq!(enclave, deserialized);
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub use cipher;
/// let key: Key<32, 16> = Key::new(b"my password", 1_000);
///
/// // Encrypt data: Utilize the Enclave to securely encrypt data along with metadata.
/// let enclave = Enclave::from_plain_bytes("some metadata", key.pubk, b"some bytes to encrypt".to_vec()).unwrap();
/// let enclave = Enclave::<&str, 8>::from_plain_bytes("some metadata", key.pubk, b"some bytes to encrypt".to_vec()).unwrap();
///
/// // Decrypt data: Recover the original bytes from the encrypted enclave.
/// let recovered_bytes = enclave.decrypt(key.pubk);
Expand Down
7 changes: 3 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use std::fs::{metadata, File};
use std::io::{Read, Write};

use enclave::Enclave;

use cipher::Key;
use cipher::{Key, chacha20::NONCE_SIZE};

/// Defines command line subcommands for the application.
#[derive(Debug, Subcommand)]
Expand Down Expand Up @@ -58,7 +57,7 @@ fn main() {
/// * `filename` - The name of the file to be encrypted.
fn encrypt_file(password: &String, filename: &String) {
let encryption_key: Key<32, 16> = Key::new(password.as_bytes(), 900_000);
let enclave = Enclave::from_plain_bytes(
let enclave = Enclave::<[u8; 16], NONCE_SIZE>::from_plain_bytes(
encryption_key.salt,
encryption_key.pubk,
get_file_as_byte_vec(filename),
Expand All @@ -81,7 +80,7 @@ fn encrypt_file(password: &String, filename: &String) {
/// * `filename` - The name of the file to be decrypted.
fn decrypt_file(password: &String, filename: &String) {
let encrypted_bytes = get_file_as_byte_vec(filename);
let enclave = Enclave::try_from(encrypted_bytes).expect("Unable to deserialize enclave");
let enclave = Enclave::<[u8; 16], NONCE_SIZE>::try_from(encrypted_bytes).expect("Unable to deserialize enclave");
let encryption_key: Key<32, 16> = Key::with_salt(password.as_bytes(), enclave.metadata, 900_000);
let recovered_bytes = enclave
.decrypt(encryption_key.pubk)
Expand Down

0 comments on commit a430b36

Please sign in to comment.