keyfork-shard: add shard_and_encrypt

This commit is contained in:
Ryan Heywood 2024-02-15 03:01:23 -05:00
parent 92fa68fa3b
commit 9f9ad54445
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
5 changed files with 165 additions and 115 deletions

View File

@ -2,14 +2,12 @@
use std::{env, path::PathBuf, process::ExitCode, str::FromStr}; use std::{env, path::PathBuf, process::ExitCode, str::FromStr};
use keyfork_shard::openpgp::{discover_certs, openpgp::Cert, split}; use keyfork_shard::{Format, openpgp::OpenPGP};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum Error { enum Error {
Usage(String), Usage(String),
Input, Input,
Threshold(u8, u8),
InvalidCertCount(usize, u8),
} }
impl std::fmt::Display for Error { impl std::fmt::Display for Error {
@ -19,15 +17,6 @@ impl std::fmt::Display for Error {
write!(f, "Usage: {program_name} threshold max key_discovery") write!(f, "Usage: {program_name} threshold max key_discovery")
} }
Error::Input => f.write_str("Expected hex encoded input"), Error::Input => f.write_str("Expected hex encoded input"),
Error::Threshold(threshold, max) => {
write!(
f,
"Invalid threshold: 0 < threshold {threshold} <= max {max} < 256"
)
}
Error::InvalidCertCount(count, max) => {
write!(f, "Invalid cert count: count {count} != max {max}")
}
} }
} }
} }
@ -36,31 +25,20 @@ impl std::error::Error for Error {}
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>; type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
fn validate(threshold: &str, max: &str, key_discovery: &str) -> Result<(u8, Vec<Cert>)> { fn validate(threshold: &str, max: &str, key_discovery: &str) -> Result<(u8, u8, PathBuf)> {
let threshold = u8::from_str(threshold)?; let threshold = u8::from_str(threshold)?;
let max = u8::from_str(max)?; let max = u8::from_str(max)?;
let key_discovery = PathBuf::from(key_discovery); let key_discovery = PathBuf::from(key_discovery);
if threshold > max {
return Err(Error::Threshold(threshold, max).into());
}
// Verify path exists
std::fs::metadata(&key_discovery)?; std::fs::metadata(&key_discovery)?;
// Load certs from path Ok((threshold, max, key_discovery))
let certs = discover_certs(key_discovery)?;
if certs.len() != max.into() {
return Err(Error::InvalidCertCount(certs.len(), max).into());
}
Ok((threshold, certs))
} }
fn run() -> Result<()> { fn run() -> Result<()> {
let mut args = env::args(); let mut args = env::args();
let program_name = args.next().expect("program name"); let program_name = args.next().expect("program name");
let args = args.collect::<Vec<_>>(); let args = args.collect::<Vec<_>>();
let (threshold, cert_list) = match args.as_slice() { let (threshold, max, key_discovery) = match args.as_slice() {
[threshold, max, key_discovery] => validate(threshold, max, key_discovery)?, [threshold, max, key_discovery] => validate(threshold, max, key_discovery)?,
_ => return Err(Error::Usage(program_name).into()), _ => return Err(Error::Usage(program_name).into()),
}; };
@ -72,8 +50,9 @@ fn run() -> Result<()> {
smex::decode(&line?)? smex::decode(&line?)?
}; };
split(threshold, cert_list, &input, std::io::stdout())?; let openpgp = OpenPGP;
openpgp.shard_and_encrypt(threshold, max, &input, key_discovery, std::io::stdout())?;
Ok(()) Ok(())
} }

View File

@ -30,9 +30,6 @@ pub trait Format {
/// The error type returned from any failed operations. /// The error type returned from any failed operations.
type Error: std::error::Error + 'static; type Error: std::error::Error + 'static;
/// A type encapsulating the public key recipients of shards.
type PublicKeyData: IntoIterator<Item = Self::PublicKey>;
/// A type encapsulating a single public key recipient. /// A type encapsulating a single public key recipient.
type PublicKey; type PublicKey;
@ -43,7 +40,7 @@ pub trait Format {
type SigningKey; type SigningKey;
/// A type representing the parsed, but encrypted, Shard data. /// A type representing the parsed, but encrypted, Shard data.
type ShardData; type EncryptedData;
/// Parse the public key data from a readable type. /// Parse the public key data from a readable type.
/// ///
@ -54,7 +51,7 @@ pub trait Format {
fn parse_public_key_data( fn parse_public_key_data(
&self, &self,
key_data_path: impl AsRef<Path>, key_data_path: impl AsRef<Path>,
) -> Result<Self::PublicKeyData, Self::Error>; ) -> Result<Vec<Self::PublicKey>, Self::Error>;
/// Derive a signer /// Derive a signer
fn derive_signing_key(&self, seed: &[u8]) -> Self::SigningKey; fn derive_signing_key(&self, seed: &[u8]) -> Self::SigningKey;
@ -70,9 +67,9 @@ pub trait Format {
fn format_encrypted_header( fn format_encrypted_header(
&self, &self,
signing_key: &Self::SigningKey, signing_key: &Self::SigningKey,
key_data: &Self::PublicKeyData, key_data: &[Self::PublicKey],
threshold: u8, threshold: u8,
) -> Result<Vec<u8>, Self::Error>; ) -> Result<Self::EncryptedData, Self::Error>;
/// Format a shard encrypted to the given public key, signing with the private key. /// Format a shard encrypted to the given public key, signing with the private key.
/// ///
@ -84,7 +81,7 @@ pub trait Format {
shard: &[u8], shard: &[u8],
public_key: &Self::PublicKey, public_key: &Self::PublicKey,
signing_key: &mut Self::SigningKey, signing_key: &mut Self::SigningKey,
) -> Result<Vec<u8>, Self::Error>; ) -> Result<Self::EncryptedData, Self::Error>;
/// Parse the private key data from a readable type. The private key may not be accessible (it /// Parse the private key data from a readable type. The private key may not be accessible (it
/// may be hardware only, such as a smartcard), for which this method may return None. /// may be hardware only, such as a smartcard), for which this method may return None.
@ -105,7 +102,7 @@ pub trait Format {
fn parse_shard_file( fn parse_shard_file(
&self, &self,
shard_file: impl Read + Send + Sync, shard_file: impl Read + Send + Sync,
) -> Result<Self::ShardData, Self::Error>; ) -> Result<Vec<Self::EncryptedData>, Self::Error>;
/// Write the Shard data to a Shard file. /// Write the Shard data to a Shard file.
/// ///
@ -114,8 +111,8 @@ pub trait Format {
/// Shard file could not be written to. /// Shard file could not be written to.
fn format_shard_file( fn format_shard_file(
&self, &self,
shard_data: Self::ShardData, encrypted_data: &[Self::EncryptedData],
shard_file: impl Write, shard_file: impl Write + Send + Sync,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
/// Decrypt shares and associated metadata from a readable input. For the current version of /// Decrypt shares and associated metadata from a readable input. For the current version of
@ -128,7 +125,7 @@ pub trait Format {
fn decrypt_all_shards( fn decrypt_all_shards(
&self, &self,
private_keys: Option<Self::PrivateKeyData>, private_keys: Option<Self::PrivateKeyData>,
shard_data: Self::ShardData, encrypted_messages: &[Self::EncryptedData],
) -> Result<(Vec<Share>, u8), Self::Error>; ) -> Result<(Vec<Share>, u8), Self::Error>;
/// Decrypt a single share and associated metadata from a reaable input. For the current /// Decrypt a single share and associated metadata from a reaable input. For the current
@ -141,7 +138,7 @@ pub trait Format {
fn decrypt_one_shard( fn decrypt_one_shard(
&self, &self,
private_keys: Option<Self::PrivateKeyData>, private_keys: Option<Self::PrivateKeyData>,
shard_data: Self::ShardData, encrypted_data: &[Self::EncryptedData],
) -> Result<(Share, u8), Self::Error>; ) -> Result<(Share, u8), Self::Error>;
/// Decrypt multiple shares and combine them to recreate a secret. /// Decrypt multiple shares and combine them to recreate a secret.
@ -157,8 +154,8 @@ pub trait Format {
let private_keys = private_key_data_path let private_keys = private_key_data_path
.map(|p| self.parse_private_key_data(p)) .map(|p| self.parse_private_key_data(p))
.transpose()?; .transpose()?;
let shard_data = self.parse_shard_file(reader)?; let encrypted_messages = self.parse_shard_file(reader)?;
let (shares, threshold) = self.decrypt_all_shards(private_keys, shard_data)?; let (shares, threshold) = self.decrypt_all_shards(private_keys, &encrypted_messages)?;
let secret = Sharks(threshold) let secret = Sharks(threshold)
.recover(&shares) .recover(&shares)
@ -186,7 +183,7 @@ pub trait Format {
let private_keys = private_key_data_path let private_keys = private_key_data_path
.map(|p| self.parse_private_key_data(p)) .map(|p| self.parse_private_key_data(p))
.transpose()?; .transpose()?;
let shard_data = self.parse_shard_file(reader)?; let encrypted_messages = self.parse_shard_file(reader)?;
// establish AES-256-GCM key via ECDH // establish AES-256-GCM key via ECDH
let mut nonce_data: Option<[u8; 12]> = None; let mut nonce_data: Option<[u8; 12]> = None;
@ -246,7 +243,7 @@ pub trait Format {
let shared_key = Aes256Gcm::new_from_slice(&hkdf_output)?; let shared_key = Aes256Gcm::new_from_slice(&hkdf_output)?;
// decrypt a single shard and create the payload // decrypt a single shard and create the payload
let (share, threshold) = self.decrypt_one_shard(private_keys, shard_data)?; let (share, threshold) = self.decrypt_one_shard(private_keys, &encrypted_messages)?;
let mut payload = Vec::from(&share); let mut payload = Vec::from(&share);
payload.insert(0, HUNK_VERSION); payload.insert(0, HUNK_VERSION);
payload.insert(1, threshold); payload.insert(1, threshold);
@ -313,6 +310,49 @@ pub trait Format {
Ok(()) Ok(())
} }
/// Split a secret into a shard for every shard in keys, with the given Shamir's Secret Sharing
/// threshold.
///
/// # Errors
/// The method may return an error if the shares can't be encrypted.
fn shard_and_encrypt(
&self,
threshold: u8,
max: u8,
secret: &[u8],
public_key_data_path: impl AsRef<Path>,
writer: impl Write + Send + Sync,
) -> Result<(), Box<dyn std::error::Error>> {
let mut signing_key = self.derive_signing_key(secret);
let sharks = Sharks(threshold);
let dealer = sharks.dealer(secret);
let public_keys = self.parse_public_key_data(public_key_data_path)?;
assert!(
public_keys.len() < u8::MAX as usize,
"must have less than u8::MAX public keys"
);
assert_eq!(
max,
public_keys.len() as u8,
"max must be equal to amount of public keys"
);
let max = public_keys.len() as u8;
assert!(max >= threshold, "threshold must not exceed max keys");
let header = self.format_encrypted_header(&signing_key, &public_keys, threshold)?;
let mut messages = vec![header];
for (pk, share) in public_keys.iter().zip(dealer) {
let shard = Vec::from(&share);
messages.push(self.encrypt_shard(&shard, pk, &mut signing_key)?);
}
self.format_shard_file(&messages, writer)?;
Ok(())
}
} }
/// Errors encountered while creating or combining shares using Shamir's Secret Sharing. /// Errors encountered while creating or combining shares using Shamir's Secret Sharing.

View File

@ -163,15 +163,52 @@ impl EncryptedMessage {
} }
} }
/// Parse OpenPGP packets for encrypted messages.
pub fn from_reader(input: impl Read + Send + Sync) -> openpgp::Result<Vec<Self>> {
let mut pkesks = Vec::new();
let mut encrypted_messages = vec![];
for packet in PacketPile::from_reader(input)
.map_err(Error::Sequoia)?
.into_children()
{
match packet {
Packet::PKESK(p) => pkesks.push(p),
Packet::SEIP(s) => {
encrypted_messages.push(EncryptedMessage::new(&mut pkesks, s));
}
s => {
panic!("Invalid variant found: {}", s.tag());
}
}
}
Ok(encrypted_messages)
}
/// Serialize all contents of the message to a writer. /// Serialize all contents of the message to a writer.
/// ///
/// # Errors /// # Errors
/// The function may error for any condition in Sequoia's Serialize trait. /// The function may error for any condition in Sequoia's Serialize trait.
pub fn serialize(&self, o: &mut dyn std::io::Write) -> openpgp::Result<()> { fn serialize(&self, mut o: impl std::io::Write + Send + Sync) -> openpgp::Result<()> {
for pkesk in &self.pkesks { for pkesk in &self.pkesks {
pkesk.serialize(o)?; let mut packet = vec![];
pkesk.serialize(&mut packet).map_err(Error::Sequoia)?;
let message = Message::new(&mut o);
let mut message = ArbitraryWriter::new(message, Tag::PKESK).map_err(Error::Sequoia)?;
message.write_all(&packet).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
} }
self.message.serialize(o)?; let mut packet = vec![];
self.message
.serialize(&mut packet)
.map_err(Error::Sequoia)?;
let message = Message::new(&mut o);
let mut message = ArbitraryWriter::new(message, Tag::SEIP).map_err(Error::Sequoia)?;
message.write_all(&packet).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
Ok(()) Ok(())
} }
@ -188,23 +225,8 @@ impl EncryptedMessage {
H: VerificationHelper + DecryptionHelper, H: VerificationHelper + DecryptionHelper,
{ {
let mut packets = vec![]; let mut packets = vec![];
self.serialize(&mut packets)
for pkesk in &self.pkesks {
let mut packet = vec![];
pkesk.serialize(&mut packet).map_err(Error::Sequoia)?;
let message = Message::new(&mut packets);
let mut message = ArbitraryWriter::new(message, Tag::PKESK).map_err(Error::Sequoia)?;
message.write_all(&packet).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
}
let mut packet = vec![];
self.message
.serialize(&mut packet)
.map_err(Error::Sequoia)?; .map_err(Error::Sequoia)?;
let message = Message::new(&mut packets);
let mut message = ArbitraryWriter::new(message, Tag::SEIP).map_err(Error::Sequoia)?;
message.write_all(&packet).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
let mut decryptor = DecryptorBuilder::from_bytes(&packets) let mut decryptor = DecryptorBuilder::from_bytes(&packets)
.map_err(Error::Sequoia)? .map_err(Error::Sequoia)?
@ -256,15 +278,14 @@ impl OpenPGP {
impl Format for OpenPGP { impl Format for OpenPGP {
type Error = Error; type Error = Error;
type PublicKey = Cert; type PublicKey = Cert;
type PublicKeyData = Vec<Cert>;
type PrivateKeyData = Vec<Cert>; type PrivateKeyData = Vec<Cert>;
type SigningKey = Cert; type SigningKey = Cert;
type ShardData = Vec<EncryptedMessage>; type EncryptedData = EncryptedMessage;
fn parse_public_key_data( fn parse_public_key_data(
&self, &self,
key_data_path: impl AsRef<Path>, key_data_path: impl AsRef<Path>,
) -> std::result::Result<Self::PublicKeyData, Self::Error> { ) -> std::result::Result<Vec<Self::PublicKey>, Self::Error> {
Self::discover_certs(key_data_path) Self::discover_certs(key_data_path)
} }
@ -288,9 +309,9 @@ impl Format for OpenPGP {
fn format_encrypted_header( fn format_encrypted_header(
&self, &self,
signing_key: &Self::SigningKey, signing_key: &Self::SigningKey,
key_data: &Self::PublicKeyData, key_data: &[Self::PublicKey],
threshold: u8, threshold: u8,
) -> Result<Vec<u8>, Self::Error> { ) -> Result<Self::EncryptedData, Self::Error> {
let policy = StandardPolicy::new(); let policy = StandardPolicy::new();
let mut pp = vec![SHARD_METADATA_VERSION, threshold]; let mut pp = vec![SHARD_METADATA_VERSION, threshold];
// Note: Sequoia does not export private keys on a Cert, only on a TSK // Note: Sequoia does not export private keys on a Cert, only on a TSK
@ -348,7 +369,22 @@ impl Format for OpenPGP {
literal_message.write_all(&pp).map_err(Error::SequoiaIo)?; literal_message.write_all(&pp).map_err(Error::SequoiaIo)?;
literal_message.finalize().map_err(Error::Sequoia)?; literal_message.finalize().map_err(Error::Sequoia)?;
Ok(output) // Parse it into an EncryptedMessage. Yes, this takes a serialized message
// and deserializes it. Don't think about it too hard. It's easier this way.
let mut pkesks = vec![];
for packet in PacketPile::from_reader(output.as_slice())
.map_err(Error::Sequoia)?
.into_children()
{
match packet {
Packet::PKESK(p) => pkesks.push(p),
Packet::SEIP(s) => return Ok(EncryptedMessage::new(&mut pkesks, s)),
s => panic!("Invalid variant found: {}", s.tag()),
}
}
panic!("Unable to build EncryptedMessage from PacketPile");
} }
fn encrypt_shard( fn encrypt_shard(
@ -356,7 +392,7 @@ impl Format for OpenPGP {
shard: &[u8], shard: &[u8],
public_key: &Cert, public_key: &Cert,
signing_key: &mut Self::SigningKey, signing_key: &mut Self::SigningKey,
) -> Result<Vec<u8>> { ) -> Result<EncryptedMessage> {
let policy = StandardPolicy::new(); let policy = StandardPolicy::new();
let valid_cert = public_key let valid_cert = public_key
.with_policy(&policy, None) .with_policy(&policy, None)
@ -404,7 +440,13 @@ impl Format for OpenPGP {
message.write_all(shard).map_err(Error::SequoiaIo)?; message.write_all(shard).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?; message.finalize().map_err(Error::Sequoia)?;
Ok(message_output) let message = EncryptedMessage::from_reader(message_output.as_slice())
.map_err(Error::Sequoia)?
.into_iter()
.next()
.expect("serialized message should be parseable");
Ok(message)
} }
fn parse_private_key_data( fn parse_private_key_data(
@ -417,35 +459,17 @@ impl Format for OpenPGP {
fn parse_shard_file( fn parse_shard_file(
&self, &self,
shard_file: impl Read + Send + Sync, shard_file: impl Read + Send + Sync,
) -> Result<Self::ShardData, Self::Error> { ) -> Result<Vec<Self::EncryptedData>, Self::Error> {
let mut pkesks = Vec::new(); EncryptedMessage::from_reader(shard_file).map_err(Error::Sequoia)
let mut encrypted_messages = vec![];
for packet in PacketPile::from_reader(shard_file)
.map_err(Error::Sequoia)?
.into_children()
{
match packet {
Packet::PKESK(p) => pkesks.push(p),
Packet::SEIP(s) => {
encrypted_messages.push(EncryptedMessage::new(&mut pkesks, s));
}
s => {
panic!("Invalid variant found: {}", s.tag());
}
}
}
Ok(encrypted_messages)
} }
fn format_shard_file( fn format_shard_file(
&self, &self,
shard_data: Self::ShardData, encrypted_data: &[Self::EncryptedData],
shard_file: impl Write, shard_file: impl Write + Send + Sync,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
let mut writer = Writer::new(shard_file, Kind::Message).map_err(Error::SequoiaIo)?; let mut writer = Writer::new(shard_file, Kind::Message).map_err(Error::SequoiaIo)?;
for message in shard_data { for message in encrypted_data {
message.serialize(&mut writer).map_err(Error::Sequoia)?; message.serialize(&mut writer).map_err(Error::Sequoia)?;
} }
writer.finalize().map_err(Error::SequoiaIo)?; writer.finalize().map_err(Error::SequoiaIo)?;
@ -455,7 +479,7 @@ impl Format for OpenPGP {
fn decrypt_all_shards( fn decrypt_all_shards(
&self, &self,
private_keys: Option<Self::PrivateKeyData>, private_keys: Option<Self::PrivateKeyData>,
mut shard_data: Self::ShardData, encrypted_data: &[Self::EncryptedData],
) -> std::result::Result<(Vec<Share>, u8), Self::Error> { ) -> std::result::Result<(Vec<Share>, u8), Self::Error> {
// Be as liberal as possible when decrypting. // Be as liberal as possible when decrypting.
// We don't want to invalidate someone's keys just because the old sig expired. // We don't want to invalidate someone's keys just because the old sig expired.
@ -463,8 +487,10 @@ impl Format for OpenPGP {
let mut keyring = Keyring::new(private_keys.unwrap_or_default())?; let mut keyring = Keyring::new(private_keys.unwrap_or_default())?;
let mut manager = SmartcardManager::new()?; let mut manager = SmartcardManager::new()?;
let metadata = shard_data.remove(0); let mut encrypted_messages = encrypted_data.iter();
let metadata_content = decrypt_metadata(&metadata, &policy, &mut keyring, &mut manager)?;
let metadata = encrypted_messages.next().expect("metdata");
let metadata_content = decrypt_metadata(metadata, &policy, &mut keyring, &mut manager)?;
let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?; let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?;
@ -475,8 +501,11 @@ impl Format for OpenPGP {
// because we control the order packets are encrypted and certificates are stored. // because we control the order packets are encrypted and certificates are stored.
// TODO: remove alloc, convert EncryptedMessage to &EncryptedMessage // TODO: remove alloc, convert EncryptedMessage to &EncryptedMessage
let mut messages: HashMap<KeyID, EncryptedMessage> = let mut messages: HashMap<KeyID, EncryptedMessage> = certs
certs.iter().map(Cert::keyid).zip(shard_data).collect(); .iter()
.map(Cert::keyid)
.zip(encrypted_messages.cloned())
.collect();
let mut decrypted_messages = let mut decrypted_messages =
decrypt_with_keyring(&mut messages, &certs, &policy, &mut keyring)?; decrypt_with_keyring(&mut messages, &certs, &policy, &mut keyring)?;
@ -507,21 +536,26 @@ impl Format for OpenPGP {
fn decrypt_one_shard( fn decrypt_one_shard(
&self, &self,
private_keys: Option<Self::PrivateKeyData>, private_keys: Option<Self::PrivateKeyData>,
mut shard_data: Self::ShardData, encrypted_data: &[Self::EncryptedData],
) -> std::result::Result<(Share, u8), Self::Error> { ) -> std::result::Result<(Share, u8), Self::Error> {
let policy = NullPolicy::new(); let policy = NullPolicy::new();
let mut keyring = Keyring::new(private_keys.unwrap_or_default())?; let mut keyring = Keyring::new(private_keys.unwrap_or_default())?;
let mut manager = SmartcardManager::new()?; let mut manager = SmartcardManager::new()?;
let metadata = shard_data.remove(0); let mut encrypted_messages = encrypted_data.iter();
let metadata_content = decrypt_metadata(&metadata, &policy, &mut keyring, &mut manager)?;
let metadata = encrypted_messages.next().expect("metadata");
let metadata_content = decrypt_metadata(metadata, &policy, &mut keyring, &mut manager)?;
let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?; let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?;
keyring.set_root_cert(root_cert.clone()); keyring.set_root_cert(root_cert.clone());
manager.set_root_cert(root_cert.clone()); manager.set_root_cert(root_cert.clone());
let mut messages: HashMap<KeyID, EncryptedMessage> = let mut messages: HashMap<KeyID, EncryptedMessage> = certs
certs.iter().map(Cert::keyid).zip(shard_data).collect(); .iter()
.map(Cert::keyid)
.zip(encrypted_messages.cloned())
.collect();
let decrypted_messages = let decrypted_messages =
decrypt_with_keyring(&mut messages, &certs, &policy, &mut keyring)?; decrypt_with_keyring(&mut messages, &certs, &policy, &mut keyring)?;
@ -935,6 +969,7 @@ pub fn decrypt(
/// # Errors /// # Errors
/// The function may return an error if an error occurs while decrypting shards, parsing shards, or /// The function may return an error if an error occurs while decrypting shards, parsing shards, or
/// combining the shards into a secret. /// combining the shards into a secret.
#[deprecated]
pub fn combine( pub fn combine(
certs: Vec<Cert>, certs: Vec<Cert>,
metadata: &EncryptedMessage, metadata: &EncryptedMessage,
@ -1022,6 +1057,7 @@ pub fn combine(
/// ///
/// The function may panic if the metadata can't properly store the certificates used to generate /// The function may panic if the metadata can't properly store the certificates used to generate
/// the encrypted shares. /// the encrypted shares.
#[deprecated]
pub fn split(threshold: u8, certs: Vec<Cert>, secret: &[u8], output: impl Write) -> Result<()> { pub fn split(threshold: u8, certs: Vec<Cert>, secret: &[u8], output: impl Write) -> Result<()> {
let seed = VariableLengthSeed::new(secret); let seed = VariableLengthSeed::new(secret);
// build cert to sign encrypted shares // build cert to sign encrypted shares

View File

@ -34,7 +34,7 @@ trait ShardExec {
max: u8, max: u8,
key_discovery: impl AsRef<Path>, key_discovery: impl AsRef<Path>,
secret: &[u8], secret: &[u8],
output: &mut impl Write, output: &mut (impl Write + Send + Sync),
) -> Result<(), Box<dyn std::error::Error>>; ) -> Result<(), Box<dyn std::error::Error>>;
fn combine<T>( fn combine<T>(
@ -65,17 +65,10 @@ impl ShardExec for OpenPGP {
max: u8, max: u8,
key_discovery: impl AsRef<Path>, key_discovery: impl AsRef<Path>,
secret: &[u8], secret: &[u8],
output: &mut impl Write, output: &mut (impl Write + Send + Sync),
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
// Get certs and input let opgp = keyfork_shard::openpgp::OpenPGP;
let certs = keyfork_shard::openpgp::discover_certs(key_discovery.as_ref())?; opgp.shard_and_encrypt(threshold, max, secret, key_discovery, output)
assert_eq!(
certs.len(),
max.into(),
"cert count {} != max {max}",
certs.len()
);
keyfork_shard::openpgp::split(threshold, certs, secret, output).map_err(Into::into)
} }
fn combine<T>( fn combine<T>(

View File

@ -165,8 +165,10 @@ fn generate_shard_secret(
if let Some(output_file) = output_file { if let Some(output_file) = output_file {
let output = File::create(output_file)?; let output = File::create(output_file)?;
#[allow(deprecated)]
keyfork_shard::openpgp::split(threshold, certs, &seed, output)?; keyfork_shard::openpgp::split(threshold, certs, &seed, output)?;
} else { } else {
#[allow(deprecated)]
keyfork_shard::openpgp::split(threshold, certs, &seed, std::io::stdout())?; keyfork_shard::openpgp::split(threshold, certs, &seed, std::io::stdout())?;
} }
Ok(()) Ok(())