keyfork-derive-util, keyforkd-client: support fearless conversions

This commit is contained in:
Ryan Heywood 2024-02-11 20:14:35 -05:00
parent 4e2c4487e9
commit 8108f5e61a
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
8 changed files with 201 additions and 121 deletions

View File

@ -2,8 +2,13 @@
use std::{collections::HashMap, os::unix::net::UnixStream, path::PathBuf}; use std::{collections::HashMap, os::unix::net::UnixStream, path::PathBuf};
use keyfork_derive_util::{
request::{AsAlgorithm, DerivationRequest},
DerivationPath, ExtendedPrivateKey, PrivateKey,
};
use keyfork_frame::{try_decode_from, try_encode_to, DecodeError, EncodeError}; use keyfork_frame::{try_decode_from, try_encode_to, DecodeError, EncodeError};
use keyforkd_models::{Request, Response, Error as KeyforkdError}; use keyforkd_models::{Error as KeyforkdError, Request, Response};
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -11,6 +16,10 @@ mod tests;
/// An error occurred while interacting with Keyforkd. /// An error occurred while interacting with Keyforkd.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
/// The response from the server did not match the request.
#[error("The response from the server did not match the request")]
InvalidResponse,
/// The environment variables used for determining a Keyforkd socket path were not set. /// The environment variables used for determining a Keyforkd socket path were not set.
#[error("Neither KEYFORK_SOCKET_PATH nor XDG_RUNTIME_DIR were set")] #[error("Neither KEYFORK_SOCKET_PATH nor XDG_RUNTIME_DIR were set")]
EnvVarsNotFound, EnvVarsNotFound,
@ -37,7 +46,7 @@ pub enum Error {
/// An error encountered in Keyforkd. /// An error encountered in Keyforkd.
#[error("Error in Keyforkd: {0}")] #[error("Error in Keyforkd: {0}")]
Keyforkd(#[from] KeyforkdError) Keyforkd(#[from] KeyforkdError),
} }
#[allow(missing_docs)] #[allow(missing_docs)]
@ -95,6 +104,38 @@ impl Client {
get_socket().map(|socket| Self { socket }) get_socket().map(|socket| Self { socket })
} }
/// Request an [`ExtendedPrivateKey`] for a given [`DerivationPath`].
///
/// # Errors
/// An error may be returned if:
/// * Reading or writing from or to the socket encountered an error.
/// * Bincode could not serialize the request or deserialize the response.
/// * An error occurred in Keyforkd.
/// * Keyforkd returned invalid data.
pub fn request_xprv<K>(&mut self, path: &DerivationPath) -> Result<ExtendedPrivateKey<K>>
where
K: PrivateKey + Clone + AsAlgorithm,
{
let algo = K::as_algorithm();
let request = Request::Derivation(DerivationRequest::new(algo.clone(), path));
let response = self.request(&request)?;
match response {
Response::Derivation(d) => {
if d.algorithm != algo {
return Err(Error::InvalidResponse);
}
let depth = path.len() as u8;
Ok(ExtendedPrivateKey::new_from_parts(
&d.data,
depth,
d.chain_code,
))
}
_ => Err(Error::InvalidResponse),
}
}
/// Serialize and send a [`Request`] to the server, awaiting a [`Result<Response>`]. /// Serialize and send a [`Request`] to the server, awaiting a [`Result<Response>`].
/// ///
/// # Errors /// # Errors

View File

@ -2,13 +2,10 @@
use std::time::{Duration, SystemTime, SystemTimeError}; use std::time::{Duration, SystemTime, SystemTimeError};
use derive_util::{ use derive_util::{DerivationIndex, ExtendedPrivateKey, IndexError, PrivateKey};
request::{DerivationResponse, TryFromDerivationResponseError},
DerivationIndex, ExtendedPrivateKey, PrivateKey,
IndexError,
};
use ed25519_dalek::SigningKey; use ed25519_dalek::SigningKey;
pub use keyfork_derive_util as derive_util; pub use keyfork_derive_util as derive_util;
pub use sequoia_openpgp as openpgp;
use sequoia_openpgp::{ use sequoia_openpgp::{
packet::{ packet::{
key::{Key4, PrimaryRole, SubordinateRole}, key::{Key4, PrimaryRole, SubordinateRole},
@ -18,7 +15,9 @@ use sequoia_openpgp::{
types::{KeyFlags, SignatureType}, types::{KeyFlags, SignatureType},
Cert, Packet, Cert, Packet,
}; };
pub use sequoia_openpgp as openpgp;
pub type XPrvKey = SigningKey;
pub type XPrv = ExtendedPrivateKey<SigningKey>;
/// An error occurred while creating an OpenPGP key. /// An error occurred while creating an OpenPGP key.
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -32,10 +31,6 @@ pub enum Error {
#[error("Key configured with both encryption and non-encryption key flags: {0:?}")] #[error("Key configured with both encryption and non-encryption key flags: {0:?}")]
InvalidKeyFlags(KeyFlags), InvalidKeyFlags(KeyFlags),
/// The derivation response contained incorrect data.
#[error("Incorrect derived data: {0}")]
IncorrectDerivedData(#[from] TryFromDerivationResponseError),
/// A derivation index could not be created from the given index. /// A derivation index could not be created from the given index.
#[error("Could not create derivation index: {0}")] #[error("Could not create derivation index: {0}")]
Index(#[from] IndexError), Index(#[from] IndexError),
@ -66,7 +61,7 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
/// ///
/// # Errors /// # Errors
/// The function may error for any condition mentioned in [`Error`]. /// The function may error for any condition mentioned in [`Error`].
pub fn derive(data: DerivationResponse, keys: &[KeyFlags], userid: &UserID) -> Result<Cert> { pub fn derive(xprv: XPrv, keys: &[KeyFlags], userid: &UserID) -> Result<Cert> {
let primary_key_flags = match keys.get(0) { let primary_key_flags = match keys.get(0) {
Some(kf) if kf.for_certification() => kf, Some(kf) if kf.for_certification() => kf,
_ => return Err(Error::NotCert), _ => return Err(Error::NotCert),
@ -76,7 +71,6 @@ pub fn derive(data: DerivationResponse, keys: &[KeyFlags], userid: &UserID) -> R
let one_day = SystemTime::now() + Duration::from_secs(60 * 60 * 24); let one_day = SystemTime::now() + Duration::from_secs(60 * 60 * 24);
// Create certificate with initial key and signature // Create certificate with initial key and signature
let xprv = ExtendedPrivateKey::<SigningKey>::try_from(data)?;
let derived_primary_key = xprv.derive_child(&DerivationIndex::new(0, true)?)?; let derived_primary_key = xprv.derive_child(&DerivationIndex::new(0, true)?)?;
let primary_key = Key::from(Key4::<_, PrimaryRole>::import_secret_ed25519( let primary_key = Key::from(Key4::<_, PrimaryRole>::import_secret_ed25519(
&PrivateKey::to_bytes(derived_primary_key.private_key()), &PrivateKey::to_bytes(derived_primary_key.private_key()),
@ -118,21 +112,14 @@ pub fn derive(data: DerivationResponse, keys: &[KeyFlags], userid: &UserID) -> R
bytes[0] &= 0b1111_1000; bytes[0] &= 0b1111_1000;
bytes[31] &= !0b1000_0000; bytes[31] &= !0b1000_0000;
bytes[31] |= 0b0100_0000; bytes[31] |= 0b0100_0000;
Key::from( Key::from(Key4::<_, SubordinateRole>::import_secret_cv25519(
Key4::<_, SubordinateRole>::import_secret_cv25519( &bytes, None, None, epoch,
&bytes, )?)
None,
None,
epoch,
)?
)
} else { } else {
Key::from( Key::from(Key4::<_, SubordinateRole>::import_secret_ed25519(
Key4::<_, SubordinateRole>::import_secret_ed25519(
&PrivateKey::to_bytes(derived_key.private_key()), &PrivateKey::to_bytes(derived_key.private_key()),
epoch, epoch,
)? )?)
)
}; };
// As per OpenPGP spec, signing keys must backsig the primary key // As per OpenPGP spec, signing keys must backsig the primary key

View File

@ -2,12 +2,16 @@
use std::{env, process::ExitCode, str::FromStr}; use std::{env, process::ExitCode, str::FromStr};
use keyfork_derive_util::{ use keyfork_derive_util::{DerivationIndex, DerivationPath};
request::{DerivationAlgorithm, DerivationRequest, DerivationResponse},
DerivationIndex, DerivationPath,
};
use keyforkd_client::Client; use keyforkd_client::Client;
use sequoia_openpgp::{packet::UserID, types::KeyFlags, armor::{Kind, Writer}, serialize::Marshal};
use ed25519_dalek::SigningKey;
use sequoia_openpgp::{
armor::{Kind, Writer},
packet::UserID,
serialize::Marshal,
types::KeyFlags,
};
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
enum Error { enum Error {
@ -108,16 +112,13 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
_ => panic!("Usage: {program_name} path subkey_format default_userid"), _ => panic!("Usage: {program_name} path subkey_format default_userid"),
}; };
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path); let derived_xprv = Client::discover_socket()?.request_xprv::<SigningKey>(&path)?;
let derived_data: DerivationResponse = Client::discover_socket()?
.request(&request.into())?
.try_into()?;
let subkeys = subkey_format let subkeys = subkey_format
.iter() .iter()
.map(|kt| kt.inner().clone()) .map(|kt| kt.inner().clone())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let cert = keyfork_derive_openpgp::derive(derived_data, subkeys.as_slice(), &default_userid)?; let cert = keyfork_derive_openpgp::derive(derived_xprv, subkeys.as_slice(), &default_userid)?;
let mut w = Writer::new(std::io::stdout(), Kind::SecretKey)?; let mut w = Writer::new(std::io::stdout(), Kind::SecretKey)?;

View File

@ -45,11 +45,36 @@ type HmacSha512 = Hmac<Sha512>;
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct ExtendedPrivateKey<K: PrivateKey + Clone> { pub struct ExtendedPrivateKey<K: PrivateKey + Clone> {
/// The internal private key data. /// The internal private key data.
#[serde(with = "serde_with")]
private_key: K, private_key: K,
depth: u8, depth: u8,
chain_code: ChainCode, chain_code: ChainCode,
} }
mod serde_with {
use super::*;
pub(crate) fn serialize<S, K>(value: &K, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
K: PrivateKey + Clone,
{
serializer.serialize_bytes(&value.to_bytes())
}
pub(crate) fn deserialize<'de, D, K>(deserializer: D) -> Result<K, D::Error>
where
D: serde::Deserializer<'de>,
K: PrivateKey + Clone,
{
let variable_len_bytes = <&[u8]>::deserialize(deserializer)?;
let bytes: [u8; 32] = variable_len_bytes
.try_into()
.expect("unable to parse serialized private key; no support for static len");
Ok(K::from_bytes(&bytes))
}
}
impl<K: PrivateKey + Clone> std::fmt::Debug for ExtendedPrivateKey<K> { impl<K: PrivateKey + Clone> std::fmt::Debug for ExtendedPrivateKey<K> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ExtendedPrivateKey") f.debug_struct("ExtendedPrivateKey")
@ -105,12 +130,14 @@ where
.into_bytes(); .into_bytes();
let (private_key, chain_code) = hash.split_at(KEY_SIZE / 8); let (private_key, chain_code) = hash.split_at(KEY_SIZE / 8);
Self::new_from_parts( Ok(Self::new_from_parts(
private_key, private_key
.try_into()
.expect("KEY_SIZE / 8 did not give a 32 byte slice"),
0, 0,
// Checked: chain_code is always the same length, hash is static size // Checked: chain_code is always the same length, hash is static size
chain_code.try_into().expect("Invalid chain code length"), chain_code.try_into().expect("Invalid chain code length"),
) ))
} }
/// Create an [`ExtendedPrivateKey`] from a given `seed`, `depth`, and `chain_code`. /// Create an [`ExtendedPrivateKey`] from a given `seed`, `depth`, and `chain_code`.
@ -125,21 +152,18 @@ where
/// # public_key::TestPublicKey as PublicKey, /// # public_key::TestPublicKey as PublicKey,
/// # private_key::TestPrivateKey as PrivateKey, /// # private_key::TestPrivateKey as PrivateKey,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let key: &[u8; 32] = // /// let key: &[u8; 32] = //
/// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code)?; /// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code);
/// # Ok(())
/// # }
/// ``` /// ```
pub fn new_from_parts(seed: &[u8], depth: u8, chain_code: [u8; 32]) -> Result<Self> { pub fn new_from_parts(key: &[u8; 32], depth: u8, chain_code: [u8; 32]) -> Self {
Ok(Self { Self {
private_key: K::from_bytes(seed.try_into()?), private_key: K::from_bytes(&key),
depth, depth,
chain_code, chain_code,
}) }
} }
/// Returns a reference to the [`PrivateKey`]. /// Returns a reference to the [`PrivateKey`].
@ -152,15 +176,12 @@ where
/// # public_key::TestPublicKey as PublicKey, /// # public_key::TestPublicKey as PublicKey,
/// # private_key::TestPrivateKey as PrivateKey, /// # private_key::TestPrivateKey as PrivateKey,
/// # }; /// # };
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let key: &[u8; 32] = // /// let key: &[u8; 32] = //
/// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; /// # b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/// let chain_code: &[u8; 32] = // /// let chain_code: &[u8; 32] = //
/// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; /// # b"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
/// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code)?; /// let xprv = ExtendedPrivateKey::<PrivateKey>::new_from_parts(key, 4, *chain_code);
/// assert_eq!(xprv.private_key(), &PrivateKey::from_bytes(key)); /// assert_eq!(xprv.private_key(), &PrivateKey::from_bytes(key));
/// # Ok(())
/// # }
/// ``` /// ```
pub fn private_key(&self) -> &K { pub fn private_key(&self) -> &K {
&self.private_key &self.private_key

View File

@ -110,6 +110,18 @@ impl std::str::FromStr for DerivationAlgorithm {
} }
} }
/// Acquire the associated [`DerivationAlgorithm`] for a [`PrivateKey`].
pub trait AsAlgorithm: PrivateKey {
/// Return the appropriate [`DerivationAlgorithm`].
fn as_algorithm() -> DerivationAlgorithm;
}
impl AsAlgorithm for TestPrivateKey {
fn as_algorithm() -> DerivationAlgorithm {
DerivationAlgorithm::Internal
}
}
/// A derivation request. /// A derivation request.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct DerivationRequest { pub struct DerivationRequest {
@ -234,7 +246,7 @@ pub struct DerivationResponse {
pub algorithm: DerivationAlgorithm, pub algorithm: DerivationAlgorithm,
/// The derived private key. /// The derived private key.
pub data: Vec<u8>, pub data: [u8; 32],
/// The chain code, used for further derivation. /// The chain code, used for further derivation.
pub chain_code: [u8; 32], pub chain_code: [u8; 32],
@ -251,7 +263,7 @@ impl DerivationResponse {
) -> Self { ) -> Self {
Self { Self {
algorithm, algorithm,
data: PrivateKey::to_bytes(xprv.private_key()).to_vec(), data: PrivateKey::to_bytes(xprv.private_key()),
chain_code: xprv.chain_code(), chain_code: xprv.chain_code(),
depth: xprv.depth(), depth: xprv.depth(),
} }
@ -272,47 +284,71 @@ pub enum TryFromDerivationResponseError {
} }
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
impl TryFrom<&DerivationResponse> for ExtendedPrivateKey<k256::SecretKey> { mod secp256k1 {
use super::*;
use k256::SecretKey;
impl AsAlgorithm for SecretKey {
fn as_algorithm() -> DerivationAlgorithm {
DerivationAlgorithm::Secp256k1
}
}
impl TryFrom<&DerivationResponse> for ExtendedPrivateKey<SecretKey> {
type Error = TryFromDerivationResponseError; type Error = TryFromDerivationResponseError;
fn try_from(value: &DerivationResponse) -> std::result::Result<Self, Self::Error> { fn try_from(value: &DerivationResponse) -> Result<Self, Self::Error> {
match value.algorithm { match value.algorithm {
DerivationAlgorithm::Secp256k1 => { DerivationAlgorithm::Secp256k1 => Ok(Self::new_from_parts(
Self::new_from_parts(&value.data, value.depth, value.chain_code).map_err(From::from) &value.data,
} value.depth,
value.chain_code,
)),
_ => Err(Self::Error::Algorithm), _ => Err(Self::Error::Algorithm),
} }
} }
} }
#[cfg(feature = "secp256k1")] impl TryFrom<DerivationResponse> for ExtendedPrivateKey<SecretKey> {
impl TryFrom<DerivationResponse> for ExtendedPrivateKey<k256::SecretKey> {
type Error = TryFromDerivationResponseError; type Error = TryFromDerivationResponseError;
fn try_from(value: DerivationResponse) -> std::result::Result<Self, Self::Error> { fn try_from(value: DerivationResponse) -> Result<Self, Self::Error> {
ExtendedPrivateKey::<k256::SecretKey>::try_from(&value) ExtendedPrivateKey::<SecretKey>::try_from(&value)
}
} }
} }
#[cfg(feature = "ed25519")] #[cfg(feature = "ed25519")]
impl TryFrom<&DerivationResponse> for ExtendedPrivateKey<ed25519_dalek::SigningKey> { mod ed25519 {
use super::*;
use ed25519_dalek::SigningKey;
impl AsAlgorithm for SigningKey {
fn as_algorithm() -> DerivationAlgorithm {
DerivationAlgorithm::Ed25519
}
}
impl TryFrom<&DerivationResponse> for ExtendedPrivateKey<SigningKey> {
type Error = TryFromDerivationResponseError; type Error = TryFromDerivationResponseError;
fn try_from(value: &DerivationResponse) -> std::result::Result<Self, Self::Error> { fn try_from(value: &DerivationResponse) -> Result<Self, Self::Error> {
match value.algorithm { match value.algorithm {
DerivationAlgorithm::Ed25519 => { DerivationAlgorithm::Ed25519 => Ok(Self::new_from_parts(
Self::new_from_parts(&value.data, value.depth, value.chain_code).map_err(From::from) &value.data,
} value.depth,
value.chain_code,
)),
_ => Err(Self::Error::Algorithm), _ => Err(Self::Error::Algorithm),
} }
} }
} }
#[cfg(feature = "ed25519")] impl TryFrom<DerivationResponse> for ExtendedPrivateKey<SigningKey> {
impl TryFrom<DerivationResponse> for ExtendedPrivateKey<ed25519_dalek::SigningKey> {
type Error = TryFromDerivationResponseError; type Error = TryFromDerivationResponseError;
fn try_from(value: DerivationResponse) -> std::result::Result<Self, Self::Error> { fn try_from(value: DerivationResponse) -> Result<Self, Self::Error> {
ExtendedPrivateKey::<ed25519_dalek::SigningKey>::try_from(&value) ExtendedPrivateKey::<SigningKey>::try_from(&value)
}
} }
} }

View File

@ -13,9 +13,9 @@ use aes_gcm::{
Aes256Gcm, Error as AesError, KeyInit, Nonce, Aes256Gcm, Error as AesError, KeyInit, Nonce,
}; };
use hkdf::{Hkdf, InvalidLength as HkdfInvalidLength}; use hkdf::{Hkdf, InvalidLength as HkdfInvalidLength};
use keyfork_derive_openpgp::derive_util::{ use keyfork_derive_openpgp::{
request::{DerivationAlgorithm, DerivationRequest}, derive_util::{DerivationPath, PathError},
DerivationPath, PathError, XPrv,
}; };
use keyfork_mnemonic_util::{Mnemonic, MnemonicFromStrError, MnemonicGenerationError, Wordlist}; use keyfork_mnemonic_util::{Mnemonic, MnemonicFromStrError, MnemonicGenerationError, Wordlist};
use keyfork_prompt::{ use keyfork_prompt::{
@ -123,6 +123,10 @@ pub enum Error {
#[error("IO error: {0}")] #[error("IO error: {0}")]
Io(#[source] std::io::Error), Io(#[source] std::io::Error),
/// An error occurred while deriving data.
#[error("Derivation: {0}")]
Derivation(#[from] keyfork_derive_openpgp::derive_util::extended_key::private_key::Error),
/// An error occurred while parsing a derivation path. /// An error occurred while parsing a derivation path.
#[error("Derivation path: {0}")] #[error("Derivation path: {0}")]
DerivationPath(#[from] PathError), DerivationPath(#[from] PathError),
@ -643,13 +647,10 @@ pub fn combine(
// TODO: extract as function // TODO: extract as function
let userid = UserID::from("keyfork-sss"); let userid = UserID::from("keyfork-sss");
let kdr = DerivationRequest::new( let path = DerivationPath::from_str("m/7366512'/0'")?;
DerivationAlgorithm::Ed25519, let xprv = XPrv::new(&secret)?.derive_path(&path)?;
&DerivationPath::from_str("m/7366512'/0'")?,
)
.derive_with_master_seed(secret.clone())?;
let derived_cert = keyfork_derive_openpgp::derive( let derived_cert = keyfork_derive_openpgp::derive(
kdr, xprv,
&[KeyFlags::empty().set_certification().set_signing()], &[KeyFlags::empty().set_certification().set_signing()],
&userid, &userid,
)?; )?;
@ -680,13 +681,10 @@ pub fn combine(
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<()> {
// build cert to sign encrypted shares // build cert to sign encrypted shares
let userid = UserID::from("keyfork-sss"); let userid = UserID::from("keyfork-sss");
let kdr = DerivationRequest::new( let path = DerivationPath::from_str("m/7366512'/0'")?;
DerivationAlgorithm::Ed25519, let xprv = XPrv::new(&secret)?.derive_path(&path)?;
&DerivationPath::from_str("m/7366512'/0'")?,
)
.derive_with_master_seed(secret.to_vec())?;
let derived_cert = keyfork_derive_openpgp::derive( let derived_cert = keyfork_derive_openpgp::derive(
kdr, xprv,
&[KeyFlags::empty().set_certification().set_signing()], &[KeyFlags::empty().set_certification().set_signing()],
&userid, &userid,
)?; )?;

View File

@ -1,16 +1,16 @@
use super::Keyfork; use super::Keyfork;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use keyfork_derive_openpgp::openpgp::{ use keyfork_derive_openpgp::{
openpgp::{
armor::{Kind, Writer}, armor::{Kind, Writer},
packet::UserID, packet::UserID,
serialize::Marshal, serialize::Marshal,
types::KeyFlags, types::KeyFlags,
},
XPrvKey,
}; };
use keyfork_derive_util::{ use keyfork_derive_util::{DerivationIndex, DerivationPath};
request::{DerivationAlgorithm, DerivationRequest, DerivationResponse},
DerivationIndex, DerivationPath,
};
use keyforkd_client::Client; use keyforkd_client::Client;
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>;
@ -48,12 +48,9 @@ impl DeriveSubcommands {
.set_storage_encryption(), .set_storage_encryption(),
KeyFlags::empty().set_authentication(), KeyFlags::empty().set_authentication(),
]; ];
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path); let xprv = Client::discover_socket()?.request_xprv::<XPrvKey>(&path)?;
let derived_data: DerivationResponse = Client::discover_socket()?
.request(&request.into())?
.try_into()?;
let default_userid = UserID::from(user_id.as_str()); let default_userid = UserID::from(user_id.as_str());
let cert = keyfork_derive_openpgp::derive(derived_data, &subkeys, &default_userid)?; let cert = keyfork_derive_openpgp::derive(xprv, &subkeys, &default_userid)?;
let mut w = Writer::new(std::io::stdout(), Kind::SecretKey)?; let mut w = Writer::new(std::io::stdout(), Kind::SecretKey)?;

View File

@ -5,11 +5,11 @@ use std::{collections::HashSet, fs::File, io::IsTerminal, path::PathBuf};
use card_backend_pcsc::PcscBackend; use card_backend_pcsc::PcscBackend;
use openpgp_card_sequoia::{state::Open, types::KeyType, Card}; use openpgp_card_sequoia::{state::Open, types::KeyType, Card};
use keyfork_derive_openpgp::openpgp::{self, packet::UserID, types::KeyFlags, Cert}; use keyfork_derive_openpgp::{
use keyfork_derive_util::{ openpgp::{self, packet::UserID, types::KeyFlags, Cert},
request::{DerivationAlgorithm, DerivationRequest}, XPrv,
DerivationIndex, DerivationPath,
}; };
use keyfork_derive_util::{DerivationIndex, DerivationPath};
use keyfork_prompt::{ use keyfork_prompt::{
validators::{PinValidator, Validator}, validators::{PinValidator, Validator},
Message, PromptHandler, Terminal, Message, PromptHandler, Terminal,
@ -42,10 +42,9 @@ fn derive_key(seed: &[u8], index: u8) -> Result<Cert> {
.chain_push(chain) .chain_push(chain)
.chain_push(account) .chain_push(account)
.chain_push(subkey); .chain_push(subkey);
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path); let xprv = XPrv::new(seed)?.derive_path(&path)?;
let response = request.derive_with_master_seed(seed.to_vec())?;
let userid = UserID::from(format!("Keyfork Shard {index}")); let userid = UserID::from(format!("Keyfork Shard {index}"));
let cert = keyfork_derive_openpgp::derive(response, &subkeys, &userid)?; let cert = keyfork_derive_openpgp::derive(xprv, &subkeys, &userid)?;
Ok(cert) Ok(cert)
} }