Compare commits
No commits in common. "4ab1e8afa6e909b284d0b1f7ffeb37ebcf76ba98" and "c25c11d1a02cf1c16ba23002dc8680c847cc23b8" have entirely different histories.
4ab1e8afa6
...
c25c11d1a0
|
@ -11,7 +11,7 @@ fn secp256k1_test_suite() {
|
||||||
|
|
||||||
let tests = test_data()
|
let tests = test_data()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remove("secp256k1")
|
.remove(&"secp256k1".to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for seed_test in tests {
|
for seed_test in tests {
|
||||||
|
@ -70,7 +70,7 @@ fn secp256k1_test_suite() {
|
||||||
fn ed25519_test_suite() {
|
fn ed25519_test_suite() {
|
||||||
use ed25519_dalek::SigningKey;
|
use ed25519_dalek::SigningKey;
|
||||||
|
|
||||||
let tests = test_data().unwrap().remove("ed25519").unwrap();
|
let tests = test_data().unwrap().remove(&"ed25519".to_string()).unwrap();
|
||||||
|
|
||||||
for seed_test in tests {
|
for seed_test in tests {
|
||||||
let seed = seed_test.seed;
|
let seed = seed_test.seed;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Launch the Keyfork Server from using a mnemonic passed through standard input.
|
//!
|
||||||
|
|
||||||
use keyfork_mnemonic::Mnemonic;
|
use keyfork_mnemonic::Mnemonic;
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ mod tests {
|
||||||
async fn properly_derives_secp256k1() {
|
async fn properly_derives_secp256k1() {
|
||||||
let tests = test_data()
|
let tests = test_data()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remove("secp256k1")
|
.remove(&"secp256k1".to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for per_seed in tests {
|
for per_seed in tests {
|
||||||
|
@ -146,7 +146,7 @@ mod tests {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn properly_derives_ed25519() {
|
async fn properly_derives_ed25519() {
|
||||||
let tests = test_data().unwrap().remove("ed25519").unwrap();
|
let tests = test_data().unwrap().remove(&"ed25519".to_string()).unwrap();
|
||||||
|
|
||||||
for per_seed in tests {
|
for per_seed in tests {
|
||||||
let seed = &per_seed.seed;
|
let seed = &per_seed.seed;
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "keyfork-derive-age"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
license = "AGPL-3.0-only"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
keyfork-derive-util = { workspace = true, default-features = false, features = ["ed25519"] }
|
|
||||||
keyforkd-client = { workspace = true }
|
|
||||||
smex = { workspace = true }
|
|
||||||
thiserror = "1.0.48"
|
|
||||||
bech32 = "0.11.0"
|
|
||||||
keyfork-derive-path-data = { workspace = true }
|
|
||||||
ed25519-dalek = "2.1.1"
|
|
|
@ -1,69 +0,0 @@
|
||||||
use std::{env, process::ExitCode, str::FromStr};
|
|
||||||
|
|
||||||
use keyfork_derive_path_data::paths;
|
|
||||||
use keyfork_derive_util::{DerivationPath, ExtendedPrivateKey, PathError};
|
|
||||||
use keyforkd_client::Client;
|
|
||||||
|
|
||||||
use ed25519_dalek::SigningKey;
|
|
||||||
|
|
||||||
type XPrv = ExtendedPrivateKey<SigningKey>;
|
|
||||||
|
|
||||||
/// Any error that can occur while deriving a key.
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
/// The given path could not be parsed.
|
|
||||||
#[error("Could not parse the given path: {0}")]
|
|
||||||
PathFormat(#[from] PathError),
|
|
||||||
|
|
||||||
/// The request to derive data failed.
|
|
||||||
#[error("Unable to perform key derivation request: {0}")]
|
|
||||||
KeyforkdClient(#[from] keyforkd_client::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
|
||||||
|
|
||||||
fn validate(path: &str) -> Result<DerivationPath> {
|
|
||||||
let index = paths::AGE.inner().first().unwrap();
|
|
||||||
|
|
||||||
let path = DerivationPath::from_str(path)?;
|
|
||||||
assert!(
|
|
||||||
path.len() >= 2,
|
|
||||||
"Expected path of at least m/{index}/account_id'"
|
|
||||||
);
|
|
||||||
|
|
||||||
let given_index = path.iter().next().expect("checked .len() above");
|
|
||||||
assert_eq!(
|
|
||||||
index, given_index,
|
|
||||||
"Expected derivation path starting with m/{index}, got: {given_index}",
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut args = env::args();
|
|
||||||
let program_name = args.next().expect("program name");
|
|
||||||
let args = args.collect::<Vec<_>>();
|
|
||||||
let path = match args.as_slice() {
|
|
||||||
[path] => validate(path)?,
|
|
||||||
_ => panic!("Usage: {program_name} path"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut client = Client::discover_socket()?;
|
|
||||||
// TODO: should this key be clamped to Curve25519 specs?
|
|
||||||
let xprv: XPrv = client.request_xprv(&path)?;
|
|
||||||
let hrp = bech32::Hrp::parse("AGE-SECRET-KEY-")?;
|
|
||||||
let age_key = bech32::encode::<bech32::Bech32>(hrp, &xprv.private_key().to_bytes())?;
|
|
||||||
println!("{}", age_key.to_uppercase());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
|
||||||
if let Err(e) = run() {
|
|
||||||
eprintln!("Error: {e}");
|
|
||||||
ExitCode::FAILURE
|
|
||||||
} else {
|
|
||||||
ExitCode::SUCCESS
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Query the Keyfork Server to generate a hex-encoded key for a given algorithm.
|
//!
|
||||||
|
|
||||||
use std::{env, process::ExitCode, str::FromStr};
|
use std::{env, process::ExitCode, str::FromStr};
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,8 @@ use sequoia_openpgp::{
|
||||||
Cert, Packet,
|
Cert, Packet,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: this key type is actually _not_ the extended private key, so it should be renamed
|
|
||||||
// something like Prv or PrvKey.
|
|
||||||
|
|
||||||
/// The private key type used with OpenPGP.
|
|
||||||
pub type XPrvKey = SigningKey;
|
pub type XPrvKey = SigningKey;
|
||||||
|
pub type XPrv = ExtendedPrivateKey<SigningKey>;
|
||||||
/// The extended private key type used with OpenPGP.
|
|
||||||
pub type XPrv = ExtendedPrivateKey<XPrvKey>;
|
|
||||||
|
|
||||||
/// An error occurred while creating an OpenPGP key.
|
/// An error occurred while creating an OpenPGP key.
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Query the Keyfork Servre to derive an OpenPGP Secret Key.
|
//!
|
||||||
|
|
||||||
use std::{env, process::ExitCode, str::FromStr};
|
use std::{env, process::ExitCode, str::FromStr};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ use once_cell::sync::Lazy;
|
||||||
|
|
||||||
use keyfork_derive_util::{DerivationIndex, DerivationPath};
|
use keyfork_derive_util::{DerivationIndex, DerivationPath};
|
||||||
|
|
||||||
/// All common paths for key derivation.
|
|
||||||
pub mod paths {
|
pub mod paths {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
///
|
||||||
pub mod private_key;
|
pub mod private_key;
|
||||||
#[allow(missing_docs)]
|
///
|
||||||
pub mod public_key;
|
pub mod public_key;
|
||||||
|
|
||||||
pub use {private_key::ExtendedPrivateKey, public_key::ExtendedPublicKey};
|
pub use {private_key::ExtendedPrivateKey, public_key::ExtendedPublicKey};
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn secp256k1() {
|
||||||
|
|
||||||
let tests = test_data()
|
let tests = test_data()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remove("secp256k1")
|
.remove(&"secp256k1".to_string())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for per_seed in tests {
|
for per_seed in tests {
|
||||||
|
@ -62,7 +62,7 @@ fn secp256k1() {
|
||||||
fn ed25519() {
|
fn ed25519() {
|
||||||
use ed25519_dalek::SigningKey;
|
use ed25519_dalek::SigningKey;
|
||||||
|
|
||||||
let tests = test_data().unwrap().remove("ed25519").unwrap();
|
let tests = test_data().unwrap().remove(&"ed25519".to_string()).unwrap();
|
||||||
|
|
||||||
for per_seed in tests {
|
for per_seed in tests {
|
||||||
let seed = &per_seed.seed;
|
let seed = &per_seed.seed;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Combine OpenPGP shards and output the hex-encoded secret.
|
//!
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Decrypt a single OpenPGP shard and encapsulate it for remote transport.
|
//!
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Combine OpenPGP shards using remote transport and output the hex-encoded secret.
|
//!
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Split a hex-encoded secret into OpenPGP shards
|
//!
|
||||||
|
|
||||||
use std::{env, path::PathBuf, process::ExitCode, str::FromStr};
|
use std::{env, path::PathBuf, process::ExitCode, str::FromStr};
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ use openpgp::{
|
||||||
stream::{DecryptionHelper, DecryptorBuilder, VerificationHelper},
|
stream::{DecryptionHelper, DecryptorBuilder, VerificationHelper},
|
||||||
Parse,
|
Parse,
|
||||||
},
|
},
|
||||||
policy::{NullPolicy, StandardPolicy, Policy},
|
policy::{NullPolicy, Policy},
|
||||||
serialize::{
|
serialize::{
|
||||||
stream::{ArbitraryWriter, Encryptor2, LiteralWriter, Message, Recipient, Signer},
|
stream::{ArbitraryWriter, Encryptor2, LiteralWriter, Message, Recipient, Signer},
|
||||||
Marshal,
|
Marshal,
|
||||||
|
@ -77,10 +77,6 @@ pub enum Error {
|
||||||
/// An IO error occurred.
|
/// An IO error occurred.
|
||||||
#[error("IO error: {0}")]
|
#[error("IO error: {0}")]
|
||||||
Io(#[source] std::io::Error),
|
Io(#[source] std::io::Error),
|
||||||
|
|
||||||
/// No valid keys were found for the given recipient.
|
|
||||||
#[error("No valid keys were found for the recipient {0}")]
|
|
||||||
NoValidKeys(KeyID),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
@ -185,7 +181,7 @@ impl EncryptedMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encoding and decoding shards using OpenPGP.
|
///
|
||||||
pub struct OpenPGP<P: PromptHandler> {
|
pub struct OpenPGP<P: PromptHandler> {
|
||||||
p: PhantomData<P>,
|
p: PhantomData<P>,
|
||||||
}
|
}
|
||||||
|
@ -243,13 +239,6 @@ impl<P: PromptHandler> OpenPGP<P> {
|
||||||
certs.insert(certfp, cert);
|
certs.insert(certfp, cert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for cert in certs.values() {
|
|
||||||
let policy = StandardPolicy::new();
|
|
||||||
let valid_cert = cert.with_policy(&policy, None).map_err(Error::Sequoia)?;
|
|
||||||
if get_encryption_keys(&valid_cert).next().is_none() {
|
|
||||||
return Err(Error::NoValidKeys(valid_cert.keyid()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(certs.into_values().collect())
|
Ok(certs.into_values().collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +276,7 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
||||||
key_data: &[Self::PublicKey],
|
key_data: &[Self::PublicKey],
|
||||||
threshold: u8,
|
threshold: u8,
|
||||||
) -> Result<Self::EncryptedData, Self::Error> {
|
) -> Result<Self::EncryptedData, Self::Error> {
|
||||||
let policy = StandardPolicy::new();
|
let policy = NullPolicy::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
|
||||||
signing_key
|
signing_key
|
||||||
|
@ -373,7 +362,7 @@ impl<P: PromptHandler> Format for OpenPGP<P> {
|
||||||
public_key: &Cert,
|
public_key: &Cert,
|
||||||
signing_key: &mut Self::SigningKey,
|
signing_key: &mut Self::SigningKey,
|
||||||
) -> Result<EncryptedMessage> {
|
) -> Result<EncryptedMessage> {
|
||||||
let policy = StandardPolicy::new();
|
let policy = NullPolicy::new();
|
||||||
let valid_cert = public_key
|
let valid_cert = public_key
|
||||||
.with_policy(&policy, None)
|
.with_policy(&policy, None)
|
||||||
.map_err(Error::Sequoia)?;
|
.map_err(Error::Sequoia)?;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(missing_docs)]
|
//!
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
|
@ -103,11 +103,6 @@ pub fn qrencode(
|
||||||
const VIDEO_FORMAT_READ_ERROR: &str = "Failed to read video device format";
|
const VIDEO_FORMAT_READ_ERROR: &str = "Failed to read video device format";
|
||||||
|
|
||||||
/// Continuously scan the `index`-th camera for a QR code.
|
/// Continuously scan the `index`-th camera for a QR code.
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// The function may return an error if the hardware is unable to scan video or if an image could
|
|
||||||
/// not be decoded.
|
|
||||||
#[cfg(feature = "decode-backend-rqrr")]
|
#[cfg(feature = "decode-backend-rqrr")]
|
||||||
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
||||||
let device = Device::new(index)?;
|
let device = Device::new(index)?;
|
||||||
|
@ -138,11 +133,6 @@ pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QR
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Continuously scan the `index`-th camera for a QR code.
|
/// Continuously scan the `index`-th camera for a QR code.
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// The function may return an error if the hardware is unable to scan video or if an image could
|
|
||||||
/// not be decoded.
|
|
||||||
#[cfg(feature = "decode-backend-zbar")]
|
#[cfg(feature = "decode-backend-zbar")]
|
||||||
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
pub fn scan_camera(timeout: Duration, index: usize) -> Result<Option<String>, QRCodeScanError> {
|
||||||
let device = Device::new(index)?;
|
let device = Device::new(index)?;
|
||||||
|
|
|
@ -33,7 +33,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.decode()?,
|
.decode()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(symbol) = scanner.scan_image(&image).first() {
|
if let Some(symbol) = scanner.scan_image(&image).get(0) {
|
||||||
println!("{}", String::from_utf8_lossy(symbol.data()));
|
println!("{}", String::from_utf8_lossy(symbol.data()));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! A Symbol represents some form of encoded data.
|
//!
|
||||||
|
|
||||||
use super::sys;
|
use super::sys;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(missing_docs)]
|
//!
|
||||||
|
|
||||||
use keyfork_crossterm::{
|
use keyfork_crossterm::{
|
||||||
execute,
|
execute,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Generate entropy of a given size, encoded as hex.
|
//!
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let bit_size: usize = std::env::args()
|
let bit_size: usize = std::env::args()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Generate a mnemonic from hex-encoded input.
|
//!
|
||||||
|
|
||||||
use keyfork_mnemonic::Mnemonic;
|
use keyfork_mnemonic::Mnemonic;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(missing_docs)]
|
//!
|
||||||
|
|
||||||
use std::io::{stdin, stdout};
|
use std::io::{stdin, stdout};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
//! A terminal prompt handler.
|
|
||||||
//!
|
|
||||||
//! This prompt handler uses a raw terminal device to read inputs and uses ANSI escape codes to
|
|
||||||
//! provide formatting for prompts. Because of these reasons, it is not intended to be
|
|
||||||
//! machine-readable.
|
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
io::{stderr, stdin, BufRead, BufReader, Read, Stderr, Stdin, Write},
|
io::{stderr, stdin, BufRead, BufReader, Read, Stderr, Stdin, Write},
|
||||||
|
|
Loading…
Reference in New Issue