-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fffb9c3
commit d3c0623
Showing
11 changed files
with
294 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use clap::{ArgMatches, Command}; | ||
use std::process::ExitCode; | ||
|
||
/// Command to manage file encryption keys. | ||
pub struct Key {} | ||
|
||
impl Key { | ||
pub const NAME: &'static str = "key"; | ||
|
||
pub fn new() -> Self { | ||
Self {} | ||
} | ||
} | ||
|
||
impl super::Command for Key { | ||
fn is_matched(&self, name: &str) -> bool { | ||
name == Self::NAME | ||
} | ||
|
||
fn definition(&self) -> Command { | ||
Command::new(Self::NAME) | ||
.about("Manage file encryption keys") | ||
.subcommand_required(true) | ||
.subcommand(Command::new("ls").about("List all available keys")) | ||
} | ||
|
||
fn exec(&self, _: &ArgMatches) -> ExitCode { | ||
todo!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use crate::key::KeyMgr; | ||
use clap::{ArgMatches, Command}; | ||
use std::process::ExitCode; | ||
use std::sync::Arc; | ||
|
||
/// Command to manage file encryption keystores. | ||
pub struct Keystore { | ||
keymgr: Arc<KeyMgr>, | ||
} | ||
|
||
impl Keystore { | ||
pub const NAME: &'static str = "keystore"; | ||
|
||
pub fn new(keymgr: Arc<KeyMgr>) -> Self { | ||
Self { keymgr } | ||
} | ||
|
||
fn ls(&self) -> ExitCode { | ||
let mut t = tabled::builder::Builder::new(); | ||
|
||
t.push_record(["ID"]); | ||
|
||
for s in self.keymgr.stores() { | ||
t.push_record([s.id()]); | ||
} | ||
|
||
println!("{}", t.build()); | ||
|
||
ExitCode::SUCCESS | ||
} | ||
} | ||
|
||
impl super::Command for Keystore { | ||
fn is_matched(&self, name: &str) -> bool { | ||
name == Self::NAME | ||
} | ||
|
||
fn definition(&self) -> Command { | ||
Command::new(Self::NAME) | ||
.about("Manage file encryption keystores") | ||
.subcommand_required(true) | ||
.subcommand(Command::new("ls").about("List all enabled keystores")) | ||
} | ||
|
||
fn exec(&self, args: &ArgMatches) -> ExitCode { | ||
match args.subcommand().unwrap() { | ||
("ls", _) => self.ls(), | ||
_ => unreachable!(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
use self::store::{DefaultStore, Keystore}; | ||
use crate::config::AppConfig; | ||
use crate::home::Home; | ||
use std::collections::HashMap; | ||
use std::iter::FusedIterator; | ||
use std::sync::Arc; | ||
use thiserror::Error; | ||
|
||
mod store; | ||
|
||
/// Manage file encryption keys. | ||
pub struct KeyMgr { | ||
stores: HashMap<&'static str, Arc<dyn Keystore>>, | ||
keys: HashMap<KeyId, Key>, | ||
} | ||
|
||
impl KeyMgr { | ||
pub fn new(home: &Arc<Home>, config: &Arc<AppConfig>) -> Result<Self, KeyMgrError> { | ||
let mut stores = HashMap::<&'static str, Arc<dyn Keystore>>::new(); | ||
let mut keys = HashMap::new(); | ||
|
||
// Initialize default store. | ||
if config.key.default_storage { | ||
let s = Arc::new(DefaultStore::new(home)); | ||
|
||
for k in s.list() { | ||
assert!(keys.insert(k.id().clone(), k).is_none()); | ||
} | ||
|
||
assert!(stores.insert(s.id(), s).is_none()); | ||
} | ||
|
||
Ok(Self { stores, keys }) | ||
} | ||
|
||
pub fn stores(&self) -> impl Iterator<Item = &dyn Keystore> + FusedIterator { | ||
self.stores.values().map(|s| s.as_ref()) | ||
} | ||
|
||
pub fn keys(&self) -> impl Iterator<Item = &Key> + ExactSizeIterator + FusedIterator { | ||
self.keys.values() | ||
} | ||
} | ||
|
||
/// Unique identifier of a [`Key`]. | ||
#[derive(Clone, PartialEq, Eq, Hash)] | ||
pub struct KeyId([u8; 16]); | ||
|
||
/// Key to encrypt/decrypt files in a repository. | ||
pub struct Key { | ||
id: KeyId, | ||
} | ||
|
||
impl Key { | ||
pub fn id(&self) -> &KeyId { | ||
&self.id | ||
} | ||
} | ||
|
||
/// Represents an error when [`KeyMgr`] fails to initialize. | ||
#[derive(Debug, Error)] | ||
pub enum KeyMgrError {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
use super::Keystore; | ||
use crate::home::Home; | ||
use crate::key::Key; | ||
use aes::cipher::{BlockEncrypt, KeyInit}; | ||
use aes::Aes128; | ||
use getrandom::getrandom; | ||
use sha3::digest::{ExtendableOutput, Update, XofReader}; | ||
use sha3::Shake128; | ||
use std::error::Error; | ||
use std::ops::{Deref, DerefMut}; | ||
use std::sync::Arc; | ||
use thiserror::Error; | ||
use zeroize::Zeroizing; | ||
|
||
/// Implementation of [`Keystore`] using native key store of the OS. | ||
pub struct DefaultStore {} | ||
|
||
impl DefaultStore { | ||
pub fn new(_: &Home) -> Self { | ||
Self {} | ||
} | ||
} | ||
|
||
impl Keystore for DefaultStore { | ||
fn id(&self) -> &'static str { | ||
"default" | ||
} | ||
|
||
fn list(self: &Arc<Self>) -> impl Iterator<Item = Key> | ||
where | ||
Self: Sized, | ||
{ | ||
KeyList {} | ||
} | ||
|
||
fn new(self: Arc<Self>) -> Result<Key, Box<dyn Error>> { | ||
// Generate a new key. | ||
let mut key = Zeroizing::new([0u8; 16]); | ||
|
||
if let Err(e) = getrandom(key.deref_mut()) { | ||
return Err(Box::new(NewError::GenerateKeyFailed(e))); | ||
} | ||
|
||
// Get a key check value. | ||
let mut kcv = [0u8; 16]; | ||
|
||
Aes128::new(key.deref().into()).encrypt_block((&mut kcv).into()); | ||
|
||
// Get key ID. | ||
let mut hasher = Shake128::default(); | ||
let mut id = [0u8; 16]; | ||
|
||
hasher.update(&kcv); | ||
hasher.finalize_xof().read(&mut id); | ||
|
||
todo!() | ||
} | ||
} | ||
|
||
/// Iterator to list all keys in the [`DefaultStore`]. | ||
struct KeyList {} | ||
|
||
impl Iterator for KeyList { | ||
type Item = Key; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
todo!() | ||
} | ||
} | ||
|
||
/// Represents an error when [`DefaultStore::new()`] fails. | ||
#[derive(Debug, Error)] | ||
enum NewError { | ||
#[error("couldn't generate a new key")] | ||
GenerateKeyFailed(#[source] getrandom::Error), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
pub use self::default::*; | ||
use super::Key; | ||
use std::error::Error; | ||
use std::sync::Arc; | ||
|
||
mod default; | ||
|
||
/// Storage to keep encryption keys. | ||
pub trait Keystore { | ||
fn id(&self) -> &'static str; | ||
|
||
fn list(self: &Arc<Self>) -> impl Iterator<Item = Key> | ||
where | ||
Self: Sized; | ||
|
||
fn new(self: Arc<Self>) -> Result<Key, Box<dyn Error>>; | ||
} |
Oops, something went wrong.