From 96e069d81b355d490b6623d0eed31cf4ab5252b3 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Wed, 18 Sep 2024 11:57:12 +0100 Subject: [PATCH 01/10] Implement ChaCha20Poly1305 encryption for keystore files. --- crates/keystore/Cargo.toml | 2 ++ crates/keystore/src/lib.rs | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index cb5fe10a..73be3360 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -10,3 +10,5 @@ chrono.workspace = true serde_json.workspace = true thiserror.workspace = true nix.workspace = true +chacha20poly1305 = "0.10.1" + diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index cc68778d..e399490b 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -1,11 +1,17 @@ pub mod filesystem; +use chacha20poly1305::{aead::generic_array::GenericArray, KeyInit}; + use chrono::Utc; use did_utils::{ crypto::{Ed25519KeyPair, Generate, ToPublic, X25519KeyPair}, jwk::Jwk, }; -use std::error::Error; +use std::{ + error::Error, + fs::File, + io::{Read, Write}, +}; use crate::filesystem::FileSystem; @@ -33,7 +39,35 @@ pub struct KeyStore<'a> { filename: String, keys: Vec, } + //Import Chacha20Poly1303 encryption algorith +use chacha20poly1305::{ + aead::{Aead, AeadCore, OsRng}, + ChaCha20Poly1305, +}; +struct FileSystemkeystore { + key:Vec, + nonce: Vec, +} + +impl FileSystemkeystore{ + fn encrypts(mut self, secret: KeyStore) { + let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); + + let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); + let path = secret.path(); + let mut keystorefile = File::open(path).unwrap(); + let mut buffer = Vec::new(); + keystorefile.read_to_end(&mut buffer).unwrap(); + + let encrypted_key = cipher + .encrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) + .unwrap(); + // overwritting file with encrypted keys + keystorefile.write_all(&encrypted_key).unwrap(); + self.nonce = nonce.to_vec(); + } +} impl<'a> KeyStore<'a> { /// Constructs file-based key-value store. pub fn new(fs: &'a mut dyn FileSystem, storage_dirpath: &str) -> Self { From b78ba296c1f1c879414025cdc5c320b2562de818 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Wed, 18 Sep 2024 15:18:28 +0100 Subject: [PATCH 02/10] Implemented ChaCha20Poly1305 decryption for keystore files. --- crates/keystore/src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index e399490b..dd86be94 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -39,7 +39,6 @@ pub struct KeyStore<'a> { filename: String, keys: Vec, } - //Import Chacha20Poly1303 encryption algorith use chacha20poly1305::{ aead::{Aead, AeadCore, OsRng}, ChaCha20Poly1305, @@ -51,7 +50,7 @@ struct FileSystemkeystore { } impl FileSystemkeystore{ - fn encrypts(mut self, secret: KeyStore) { + fn encrypt(mut self, secret: KeyStore) { let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); @@ -67,7 +66,20 @@ impl FileSystemkeystore{ keystorefile.write_all(&encrypted_key).unwrap(); self.nonce = nonce.to_vec(); } + + fn decrypt( self, secret: KeyStore) -> Result, chacha20poly1305::aead::Error> { + let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); + let path = secret.path(); + let mut keystorefile = File::open(path).unwrap(); + let mut buffer = Vec::new(); + keystorefile.read_to_end(&mut buffer).unwrap(); + + let decrypted_key = cipher.decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice())?; + Ok(decrypted_key) + + } } + impl<'a> KeyStore<'a> { /// Constructs file-based key-value store. pub fn new(fs: &'a mut dyn FileSystem, storage_dirpath: &str) -> Self { From 3ca8d7e241d373a43bdf497342926e6ea6363317 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Thu, 19 Sep 2024 10:15:33 +0100 Subject: [PATCH 03/10] Implemented/added memmory management by clearing and forgetting the temporary buffer used for reading the keystore file. --- crates/keystore/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index dd86be94..0c9f3bb1 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -7,6 +7,7 @@ use did_utils::{ crypto::{Ed25519KeyPair, Generate, ToPublic, X25519KeyPair}, jwk::Jwk, }; +use nix::libc::mremap; use std::{ error::Error, fs::File, @@ -65,6 +66,10 @@ impl FileSystemkeystore{ // overwritting file with encrypted keys keystorefile.write_all(&encrypted_key).unwrap(); self.nonce = nonce.to_vec(); + + // Overwrite the buffer with zeros to prevent data leakage + buffer.clear(); + std::mem::forget(buffer); } fn decrypt( self, secret: KeyStore) -> Result, chacha20poly1305::aead::Error> { @@ -75,6 +80,11 @@ impl FileSystemkeystore{ keystorefile.read_to_end(&mut buffer).unwrap(); let decrypted_key = cipher.decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice())?; + + + buffer.clear(); + std::mem::forget(buffer); + Ok(decrypted_key) } From 0a3aa61c56525ff51b5faee578eeb41dab71ee0c Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Fri, 20 Sep 2024 15:49:06 +0100 Subject: [PATCH 04/10] Added logging, redaction, and path handling improvements. --- crates/keystore/Cargo.toml | 1 + crates/keystore/src/lib.rs | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index 73be3360..aa357fd9 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -11,4 +11,5 @@ serde_json.workspace = true thiserror.workspace = true nix.workspace = true chacha20poly1305 = "0.10.1" +log = "0.4.22" diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index 0c9f3bb1..2307c219 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -7,7 +7,6 @@ use did_utils::{ crypto::{Ed25519KeyPair, Generate, ToPublic, X25519KeyPair}, jwk::Jwk, }; -use nix::libc::mremap; use std::{ error::Error, fs::File, @@ -44,52 +43,59 @@ use chacha20poly1305::{ aead::{Aead, AeadCore, OsRng}, ChaCha20Poly1305, }; +use log::{debug, info, error}; // Import logging macros struct FileSystemkeystore { - key:Vec, + key: Vec, nonce: Vec, } -impl FileSystemkeystore{ +impl FileSystemkeystore { fn encrypt(mut self, secret: KeyStore) { let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); let path = secret.path(); - let mut keystorefile = File::open(path).unwrap(); + let mut keystorefile = File::open(path.clone()).unwrap(); let mut buffer = Vec::new(); keystorefile.read_to_end(&mut buffer).unwrap(); let encrypted_key = cipher .encrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) .unwrap(); - // overwritting file with encrypted keys + // Overwrite the file with encrypted keys keystorefile.write_all(&encrypted_key).unwrap(); self.nonce = nonce.to_vec(); // Overwrite the buffer with zeros to prevent data leakage buffer.clear(); std::mem::forget(buffer); + + // Conditional logging + debug!("Encryption successful for keystore file: {}", path); } - fn decrypt( self, secret: KeyStore) -> Result, chacha20poly1305::aead::Error> { + fn decrypt(self, secret: KeyStore) -> Result, chacha20poly1305::aead::Error> { let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); let path = secret.path(); - let mut keystorefile = File::open(path).unwrap(); + let mut keystorefile = File::open(path.clone()).unwrap(); let mut buffer = Vec::new(); keystorefile.read_to_end(&mut buffer).unwrap(); let decrypted_key = cipher.decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice())?; + // Enhanced redaction: Replace all sensitive characters with asterisks + let redacted_key = decrypted_key.iter().map(|b| if b.is_ascii_graphic() && !b.is_ascii_whitespace() { '*' as u8 } else { *b }).collect::>(); + + // Conditional logging with redacted key + info!("Decryption successful for keystore file: {}, redacted key: {:?}", &path, redacted_key); buffer.clear(); std::mem::forget(buffer); Ok(decrypted_key) - } } - impl<'a> KeyStore<'a> { /// Constructs file-based key-value store. pub fn new(fs: &'a mut dyn FileSystem, storage_dirpath: &str) -> Self { @@ -203,6 +209,7 @@ impl<'a> KeyStore<'a> { } } + #[cfg(test)] mod tests { use super::*; From acd5d64cf339bfd743439bf239d4d5eb9da60d40 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Tue, 24 Sep 2024 14:46:49 +0100 Subject: [PATCH 05/10] Improved keystore security and error handling with custom error types, secure key storage, and robust file operations. --- crates/keystore/Cargo.toml | 4 +++ crates/keystore/src/lib.rs | 57 +++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index aa357fd9..9e5d5bc0 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -12,4 +12,8 @@ thiserror.workspace = true nix.workspace = true chacha20poly1305 = "0.10.1" log = "0.4.22" +openssl = "0.10.66" +jsonwebtoken = "9.3.0" +zeroize.workspace = true +secrecy = "0.10.2" diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index 2307c219..39349f5c 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -43,46 +43,70 @@ use chacha20poly1305::{ aead::{Aead, AeadCore, OsRng}, ChaCha20Poly1305, }; + use log::{debug, info, error}; // Import logging macros +use secrecy::{ExposeSecret, SecretString}; +use zeroize::Zeroize; -struct FileSystemkeystore { - key: Vec, +// Define a custom error type for keystore operations +#[derive(Debug, thiserror::Error)] +pub enum KeystoreError { + #[error("File error: {0}")] + FileError(std::io::Error), + #[error("Encryption error: {0}")] + EncryptionError(chacha20poly1305::Error), + #[error("Decryption error: {0}")] + DecryptionError(chacha20poly1305::Error), +} + + +struct FileSystemKeystore { + key: SecretString, // Store key securely using secrecy crate nonce: Vec, } -impl FileSystemkeystore { - fn encrypt(mut self, secret: KeyStore) { - let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); +impl FileSystemKeystore { + fn encrypt(mut self, secret: KeyStore) -> Result<(), Box> { + let key = self.key.expose_secret(); // Access key securely + let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key.as_bytes())); let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng); let path = secret.path(); - let mut keystorefile = File::open(path.clone()).unwrap(); + let mut keystorefile = File::open(path.clone())?; // Use Result for error handling + let mut buffer = Vec::new(); - keystorefile.read_to_end(&mut buffer).unwrap(); + keystorefile.read_to_end(&mut buffer)?; // Use Result for error handling let encrypted_key = cipher .encrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) - .unwrap(); + .map_err(|err| err).unwrap(); // Overwrite the file with encrypted keys - keystorefile.write_all(&encrypted_key).unwrap(); + keystorefile.write_all(&encrypted_key)?; // Use Result for error handling + self.nonce = nonce.to_vec(); // Overwrite the buffer with zeros to prevent data leakage buffer.clear(); - std::mem::forget(buffer); + buffer.zeroize(); // Conditional logging debug!("Encryption successful for keystore file: {}", path); + + Ok(()) } - fn decrypt(self, secret: KeyStore) -> Result, chacha20poly1305::aead::Error> { - let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(&self.key)); + fn decrypt(self, secret: KeyStore) -> Result, std::io::Error> { + let key = self.key.expose_secret(); // Access key securely + let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key.as_bytes())); + let path = secret.path(); - let mut keystorefile = File::open(path.clone()).unwrap(); + let mut keystorefile = File::open(path.clone())?; // Use Result for error handling + let mut buffer = Vec::new(); - keystorefile.read_to_end(&mut buffer).unwrap(); + keystorefile.read_to_end(&mut buffer)?; // Use Result for error handling - let decrypted_key = cipher.decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice())?; + let decrypted_key = cipher.decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) + .map_err(|err| err).unwrap(); // Enhanced redaction: Replace all sensitive characters with asterisks let redacted_key = decrypted_key.iter().map(|b| if b.is_ascii_graphic() && !b.is_ascii_whitespace() { '*' as u8 } else { *b }).collect::>(); @@ -91,11 +115,12 @@ impl FileSystemkeystore { info!("Decryption successful for keystore file: {}, redacted key: {:?}", &path, redacted_key); buffer.clear(); - std::mem::forget(buffer); + buffer.zeroize(); Ok(decrypted_key) } } + impl<'a> KeyStore<'a> { /// Constructs file-based key-value store. pub fn new(fs: &'a mut dyn FileSystem, storage_dirpath: &str) -> Self { From 6fd582bed71ec8a941fd7afd75fd4ee43c354308 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Thu, 26 Sep 2024 10:37:24 +0100 Subject: [PATCH 06/10] fix: update error handling in KeyStore. --- crates/keystore/src/errors.rs | 23 +++++++++++ crates/keystore/src/lib.rs | 76 ++++++++++------------------------- 2 files changed, 44 insertions(+), 55 deletions(-) create mode 100644 crates/keystore/src/errors.rs diff --git a/crates/keystore/src/errors.rs b/crates/keystore/src/errors.rs new file mode 100644 index 00000000..a3a10a35 --- /dev/null +++ b/crates/keystore/src/errors.rs @@ -0,0 +1,23 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum KeystoreError { + #[error("File error: {0}")] + FileError(std::io::Error), + #[error("JwkConversionError")] + JwkConversionError, + #[error("KeyPairGenerationError")] + KeyPairGenerationError, + #[error("non compliant")] + NonCompliant, + #[error("not found")] + NotFound, + #[error("parse error")] + ParseError(serde_json::Error), + #[error("serde error")] + SerdeError(serde_json::Error), + #[error("Encryption error: {0}")] + EncryptionError(chacha20poly1305::Error), + #[error("Decryption error: {0}")] + DecryptionError(chacha20poly1305::Error), +} diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index 39349f5c..db99af65 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -1,37 +1,15 @@ pub mod filesystem; - -use chacha20poly1305::{aead::generic_array::GenericArray, KeyInit}; +pub mod errors; use chrono::Utc; use did_utils::{ crypto::{Ed25519KeyPair, Generate, ToPublic, X25519KeyPair}, jwk::Jwk, }; -use std::{ - error::Error, - fs::File, - io::{Read, Write}, -}; +use std::{error::Error, fs::File, io::{Read, Write}}; use crate::filesystem::FileSystem; - -#[derive(Debug, thiserror::Error)] -pub enum KeyStoreError { - #[error("failure to convert to JWK format")] - JwkConversionError, - #[error("failure to generate key pair")] - KeyPairGenerationError, - #[error("ioerror: {0}")] - IoError(std::io::Error), - #[error("non compliant")] - NonCompliant, - #[error("not found")] - NotFound, - #[error("parse error")] - ParseError(serde_json::Error), - #[error("serde error")] - SerdeError(serde_json::Error), -} +use crate::errors::KeystoreError; pub struct KeyStore<'a> { fs: &'a mut dyn FileSystem, @@ -39,27 +17,16 @@ pub struct KeyStore<'a> { filename: String, keys: Vec, } + use chacha20poly1305::{ - aead::{Aead, AeadCore, OsRng}, - ChaCha20Poly1305, + aead::{generic_array::GenericArray, Aead, AeadCore, OsRng}, + ChaCha20Poly1305, KeyInit, }; use log::{debug, info, error}; // Import logging macros use secrecy::{ExposeSecret, SecretString}; use zeroize::Zeroize; -// Define a custom error type for keystore operations -#[derive(Debug, thiserror::Error)] -pub enum KeystoreError { - #[error("File error: {0}")] - FileError(std::io::Error), - #[error("Encryption error: {0}")] - EncryptionError(chacha20poly1305::Error), - #[error("Decryption error: {0}")] - DecryptionError(chacha20poly1305::Error), -} - - struct FileSystemKeystore { key: SecretString, // Store key securely using secrecy crate nonce: Vec, @@ -136,13 +103,13 @@ impl<'a> KeyStore<'a> { pub fn latest( fs: &'a mut dyn FileSystem, storage_dirpath: &str, - ) -> Result { + ) -> Result { let dirpath = format!("{storage_dirpath}/keystore"); // Read directory let paths = fs .read_dir_files(&dirpath) - .map_err(KeyStoreError::IoError)?; + .map_err(KeystoreError::FileError)?; // Collect paths and associated timestamps of files inside `dir` let mut collected: Vec<(String, i32)> = vec![]; @@ -152,7 +119,7 @@ impl<'a> KeyStore<'a> { .trim_start_matches(&format!("{}/", &dirpath)) .trim_end_matches(".json") .parse() - .map_err(|_| KeyStoreError::NonCompliant)?; + .map_err(|_| KeystoreError::NonCompliant)?; collected.push((path, stamp)); } @@ -164,9 +131,9 @@ impl<'a> KeyStore<'a> { .max_by_key(|(_, stamp)| stamp) .map(|(path, _)| path); - let path = file.ok_or(KeyStoreError::NotFound)?; - let content = fs.read_to_string(path).map_err(KeyStoreError::IoError)?; - let keys = serde_json::from_str::>(&content).map_err(KeyStoreError::ParseError)?; + let path = file.ok_or(KeystoreError::NotFound)?; + let content = fs.read_to_string(path).map_err(KeystoreError::FileError)?; + let keys = serde_json::from_str::>(&content).map_err(KeystoreError::ParseError)?; let filename = path .trim_start_matches(&format!("{}/", &dirpath)) @@ -186,16 +153,16 @@ impl<'a> KeyStore<'a> { } /// Persists store on disk - fn persist(&mut self) -> Result<(), KeyStoreError> { + fn persist(&mut self) -> Result<(), KeystoreError> { self.fs .create_dir_all(&self.dirpath) - .map_err(KeyStoreError::IoError)?; + .map_err(KeystoreError::FileError)?; self.fs .write( &self.path(), - &serde_json::to_string_pretty(&self.keys).map_err(KeyStoreError::SerdeError)?, + &serde_json::to_string_pretty(&self.keys).map_err(KeystoreError::SerdeError)?, ) - .map_err(KeyStoreError::IoError) + .map_err(KeystoreError::FileError) } /// Searches keypair given public key @@ -206,10 +173,10 @@ impl<'a> KeyStore<'a> { /// Generates and persists an ed25519 keypair for digital signatures. /// Returns public Jwk for convenience. pub fn gen_ed25519_jwk(&mut self) -> Result> { - let keypair = Ed25519KeyPair::new().map_err(|_| KeyStoreError::KeyPairGenerationError)?; + let keypair = Ed25519KeyPair::new().map_err(|_| KeystoreError::KeyPairGenerationError)?; let jwk: Jwk = keypair .try_into() - .map_err(|_| KeyStoreError::JwkConversionError)?; + .map_err(|_| KeystoreError::JwkConversionError)?; let pub_jwk = jwk.to_public(); self.keys.push(jwk); @@ -220,11 +187,11 @@ impl<'a> KeyStore<'a> { /// Generates and persists an x25519 keypair for digital signatures. /// Returns public Jwk for convenience. - pub fn gen_x25519_jwk(&mut self) -> Result { - let keypair = X25519KeyPair::new().map_err(|_| KeyStoreError::KeyPairGenerationError)?; + pub fn gen_x25519_jwk(&mut self) -> Result { + let keypair = X25519KeyPair::new().map_err(|_| KeystoreError::KeyPairGenerationError)?; let jwk: Jwk = keypair .try_into() - .map_err(|_| KeyStoreError::JwkConversionError)?; + .map_err(|_| KeystoreError::JwkConversionError)?; let pub_jwk = jwk.to_public(); self.keys.push(jwk); @@ -234,7 +201,6 @@ impl<'a> KeyStore<'a> { } } - #[cfg(test)] mod tests { use super::*; From e169c08b6245a80a0a8770f982142fef8d24fc18 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Thu, 26 Sep 2024 11:31:22 +0100 Subject: [PATCH 07/10] Fix: import errors for KeystoreError in mediator-coordination module. --- crates/plugins/mediator-coordination/src/util/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/plugins/mediator-coordination/src/util/mod.rs b/crates/plugins/mediator-coordination/src/util/mod.rs index fed03ee1..f21a8d65 100644 --- a/crates/plugins/mediator-coordination/src/util/mod.rs +++ b/crates/plugins/mediator-coordination/src/util/mod.rs @@ -4,7 +4,8 @@ use did_utils::{ didcore::{AssertionMethod, Document, KeyAgreement, KeyFormat, VerificationMethod}, jwk::Jwk, }; -use keystore::{filesystem::FileSystem, KeyStore, KeyStoreError}; +use keystore::{filesystem::FileSystem, KeyStore}; +use keystore::errors::KeystoreError; use serde_json::Error as SerdeError; use std::io; @@ -43,7 +44,7 @@ pub fn read_diddoc(fs: &dyn FileSystem, storage_dirpath: &str) -> Result( fs: &'a mut dyn FileSystem, storage_dirpath: &str, -) -> Result, KeyStoreError> { +) -> Result, KeystoreError> { KeyStore::latest(fs, storage_dirpath) } From f069f4399708a272e9f2db53ce10bd1d8eb5a281 Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Mon, 30 Sep 2024 15:48:08 +0100 Subject: [PATCH 08/10] fix: dependencies. --- Cargo.toml | 5 +++++ crates/keystore/Cargo.toml | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2eee1fcb..72c717f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,11 @@ json-canon = "0.1.3" qrcode = "0.12.0" image = "0.23" reqwest = "0.11" +chacha20poly1305 = "0.10.1" +log = "0.4.22" +openssl = "0.10.66" +jsonwebtoken = "9.3.0" +secrecy = "0.10.2" tempdir = "0.3.7" headers = "0.3" thiserror = "1.0.48" diff --git a/crates/keystore/Cargo.toml b/crates/keystore/Cargo.toml index 9e5d5bc0..1e9770ec 100644 --- a/crates/keystore/Cargo.toml +++ b/crates/keystore/Cargo.toml @@ -10,10 +10,10 @@ chrono.workspace = true serde_json.workspace = true thiserror.workspace = true nix.workspace = true -chacha20poly1305 = "0.10.1" -log = "0.4.22" -openssl = "0.10.66" -jsonwebtoken = "9.3.0" +chacha20poly1305.workspace =true +log.workspace = true +openssl.workspace = true +jsonwebtoken.workspace = true zeroize.workspace = true -secrecy = "0.10.2" +secrecy.workspace = true From bcb84be91f97e5c70a452dd6d04cdc965c731f6c Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Mon, 30 Sep 2024 15:52:07 +0100 Subject: [PATCH 09/10] Implement From for KeystoreError (propagate file errors) --- crates/keystore/src/errors.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/keystore/src/errors.rs b/crates/keystore/src/errors.rs index a3a10a35..e84f5f49 100644 --- a/crates/keystore/src/errors.rs +++ b/crates/keystore/src/errors.rs @@ -21,3 +21,8 @@ pub enum KeystoreError { #[error("Decryption error: {0}")] DecryptionError(chacha20poly1305::Error), } +impl From for KeystoreError { + fn from(err: std::io::Error) -> Self { + KeystoreError::FileError(err) + } +} \ No newline at end of file From 8fe00a890216663e27b0077e36c6762542eec96e Mon Sep 17 00:00:00 2001 From: Tekum Emmaanuella Date: Mon, 30 Sep 2024 15:55:49 +0100 Subject: [PATCH 10/10] fix: Use map_err for explicit conversion of std::io::Error in FileSystemKeystore. --- crates/keystore/src/lib.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/crates/keystore/src/lib.rs b/crates/keystore/src/lib.rs index db99af65..9745f51b 100644 --- a/crates/keystore/src/lib.rs +++ b/crates/keystore/src/lib.rs @@ -23,7 +23,7 @@ use chacha20poly1305::{ ChaCha20Poly1305, KeyInit, }; -use log::{debug, info, error}; // Import logging macros +use log::{debug, info}; use secrecy::{ExposeSecret, SecretString}; use zeroize::Zeroize; @@ -33,7 +33,7 @@ struct FileSystemKeystore { } impl FileSystemKeystore { - fn encrypt(mut self, secret: KeyStore) -> Result<(), Box> { + fn encrypt(mut self, secret: KeyStore) -> Result<(), KeystoreError> { let key = self.key.expose_secret(); // Access key securely let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key.as_bytes())); @@ -45,11 +45,13 @@ impl FileSystemKeystore { keystorefile.read_to_end(&mut buffer)?; // Use Result for error handling let encrypted_key = cipher - .encrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) - .map_err(|err| err).unwrap(); + .encrypt(GenericArray::from_slice(&nonce), buffer.as_slice()) + .map_err(|err| KeystoreError::EncryptionError(err))?; // Wrap encryption error + // Overwrite the file with encrypted keys keystorefile.write_all(&encrypted_key)?; // Use Result for error handling + // Store the nonce for decryption self.nonce = nonce.to_vec(); // Overwrite the buffer with zeros to prevent data leakage @@ -62,7 +64,7 @@ impl FileSystemKeystore { Ok(()) } - fn decrypt(self, secret: KeyStore) -> Result, std::io::Error> { + fn decrypt(self, secret: KeyStore) -> Result, KeystoreError> { let key = self.key.expose_secret(); // Access key securely let cipher = ChaCha20Poly1305::new(GenericArray::from_slice(key.as_bytes())); @@ -72,8 +74,9 @@ impl FileSystemKeystore { let mut buffer = Vec::new(); keystorefile.read_to_end(&mut buffer)?; // Use Result for error handling - let decrypted_key = cipher.decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) - .map_err(|err| err).unwrap(); + let decrypted_key = cipher + .decrypt(GenericArray::from_slice(&self.nonce), buffer.as_slice()) + .map_err(|err| KeystoreError::DecryptionError(err))?; // Wrap decryption error // Enhanced redaction: Replace all sensitive characters with asterisks let redacted_key = decrypted_key.iter().map(|b| if b.is_ascii_graphic() && !b.is_ascii_whitespace() { '*' as u8 } else { *b }).collect::>(); @@ -88,6 +91,7 @@ impl FileSystemKeystore { } } + impl<'a> KeyStore<'a> { /// Constructs file-based key-value store. pub fn new(fs: &'a mut dyn FileSystem, storage_dirpath: &str) -> Self {