keyfork: impl `shard transport`

This commit is contained in:
Ryan Heywood 2024-01-07 02:41:26 -05:00
parent d548276bc3
commit 6fc2c47391
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
1 changed files with 63 additions and 13 deletions

View File

@ -1,10 +1,12 @@
use super::Keyfork;
use clap::{builder::PossibleValue, Parser, Subcommand, ValueEnum};
use std::{
io::{stdin, stdout, BufRead, BufReader, Read, Write},
io::{stdin, stdout, Read, Write},
path::{Path, PathBuf},
};
const COULD_NOT_DETERMINE_FORMAT: &str = "could not determine format, try including --format";
#[derive(Debug, Clone)]
enum Format {
OpenPGP(OpenPGP),
@ -42,6 +44,14 @@ trait ShardExec {
) -> Result<(), Box<dyn std::error::Error>>
where
T: AsRef<Path>;
fn decrypt<T>(
&self,
key_discovery: Option<T>,
input: impl Read + Send + Sync,
) -> Result<(), Box<dyn std::error::Error>>
where
T: AsRef<Path>;
}
#[derive(Clone, Debug)]
@ -99,6 +109,32 @@ impl ShardExec for OpenPGP {
Ok(())
}
fn decrypt<T>(
&self,
key_discovery: Option<T>,
input: impl Read + Send + Sync,
) -> Result<(), Box<dyn std::error::Error>>
where
T: AsRef<Path>,
{
let certs = key_discovery
.map(|kd| keyfork_shard::openpgp::discover_certs(kd.as_ref()))
.transpose()?
.unwrap_or(vec![]);
let mut encrypted_messages = keyfork_shard::openpgp::parse_messages(input)?;
let encrypted_metadata = encrypted_messages
.pop_front()
.expect("any pgp encrypted message");
keyfork_shard::openpgp::decrypt(
&certs,
&encrypted_metadata,
encrypted_messages.make_contiguous(),
)?;
Ok(())
}
}
#[derive(Clone, Debug)]
@ -125,6 +161,13 @@ pub enum ShardSubcommands {
key_discovery: PathBuf,
},
/// Decrypt a single share and re-encrypt it to an ephemeral symmetric key using mnemonic-based
/// prompts. The mnemonics can be sent over insecure channels.
Transport {
/// The path to discover private keys from.
key_discovery: Option<PathBuf>,
},
/// Combine multiple encrypted shares into a hex-encoded secret, printed to stdout.
///
/// This command only accepts input from `keyfork shard split`, and is dependent on the format
@ -143,8 +186,15 @@ impl ShardSubcommands {
shard: &Shard,
_keyfork: &Keyfork,
) -> Result<(), Box<dyn std::error::Error>> {
let stdin = stdin();
let mut stdin = stdin();
let mut stdout = stdout();
let mut input = String::new();
stdin.read_to_string(&mut input)?;
let mut format = shard.format.clone();
// bang sandwich macro fun
if input.contains("BEGIN PGP MESSAGE") && !matches!(self, ShardSubcommands::Split { .. }) {
let _ = format.insert(Format::OpenPGP(OpenPGP));
}
match self {
ShardSubcommands::Split {
threshold,
@ -152,30 +202,30 @@ impl ShardSubcommands {
key_discovery,
} => {
assert!(threshold <= max, "threshold {threshold} <= max {max}");
let mut input = BufReader::new(stdin);
let mut hex_line = String::new();
input.read_line(&mut hex_line)?;
let secret = smex::decode(hex_line.trim())?;
match &shard.format {
let secret = smex::decode(input.trim())?;
match format {
Some(Format::OpenPGP(o)) => {
o.split(*threshold, *max, key_discovery, &secret, &mut stdout)
}
Some(Format::P256(_p)) => {
todo!()
}
None => panic!("--format was not given"),
None => panic!("{COULD_NOT_DETERMINE_FORMAT}"),
}
}
ShardSubcommands::Combine {
key_discovery,
} => match &shard.format {
ShardSubcommands::Transport { key_discovery } => match format {
Some(Format::OpenPGP(o)) => o.decrypt(key_discovery.as_ref(), input.as_bytes()),
Some(Format::P256(_p)) => todo!(),
None => panic!("{COULD_NOT_DETERMINE_FORMAT}"),
},
ShardSubcommands::Combine { key_discovery } => match format {
Some(Format::OpenPGP(o)) => {
o.combine(key_discovery.as_ref(), stdin, &mut stdout)
o.combine(key_discovery.as_ref(), input.as_bytes(), &mut stdout)
}
Some(Format::P256(_p)) => {
todo!()
}
None => panic!("--format was not given"),
None => panic!("{COULD_NOT_DETERMINE_FORMAT}"),
},
}
}