Compare commits

..

No commits in common. "628c98a2fe199b54998d11718594bd0ce834e0d6" and "57354fc714ed61a5f8829e1cb09d7875739ce838" have entirely different histories.

4 changed files with 29 additions and 51 deletions

View File

@ -65,7 +65,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(xprv: XPrv, keys: &[KeyFlags], userid: &UserID) -> Result<Cert> { pub fn derive(xprv: XPrv, keys: &[KeyFlags], userid: &UserID) -> Result<Cert> {
let primary_key_flags = match keys.first() { 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),
}; };

View File

@ -102,10 +102,6 @@ pub enum PrivateKeyError {
/// For the given algorithm, the private key must be nonzero. /// For the given algorithm, the private key must be nonzero.
#[error("The provided private key must be nonzero, but is not")] #[error("The provided private key must be nonzero, but is not")]
NonZero, NonZero,
/// A scalar could not be constructed for the given algorithm.
#[error("A scalar could not be constructed for the given algorithm")]
InvalidScalar,
} }
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
@ -134,19 +130,20 @@ impl PrivateKey for k256::SecretKey {
} }
fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err> { fn derive_child(&self, other: &PrivateKeyBytes) -> Result<Self, Self::Err> {
use k256::elliptic_curve::ScalarPrimitive; if other.iter().all(|n| n == &0) {
use k256::{Scalar, Secp256k1}; return Err(PrivateKeyError::NonZero);
}
// Construct a scalar from bytes let other = *other;
let scalar = ScalarPrimitive::<Secp256k1>::from_bytes(other.into()); // Checked: See above nonzero check
let scalar = Option::<ScalarPrimitive<Secp256k1>>::from(scalar); let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
let scalar = scalar.ok_or(PrivateKeyError::InvalidScalar)?; .expect(bug!("Should have been able to get a NonZeroScalar"));
let scalar = Scalar::from(scalar);
let derived_scalar = self.to_nonzero_scalar().as_ref() + scalar.as_ref(); let derived_scalar = self.to_nonzero_scalar().as_ref() + scalar.as_ref();
let nonzero_scalar = Option::<NonZeroScalar>::from(NonZeroScalar::new(derived_scalar)) Ok(
.ok_or(PrivateKeyError::NonZero)?; Option::<NonZeroScalar>::from(NonZeroScalar::new(derived_scalar))
Ok(Self::from(nonzero_scalar)) .map(Into::into)
.expect(bug!("Should be able to make Key")),
)
} }
} }
@ -205,7 +202,9 @@ impl PrivateKey for TestPrivateKey {
type Err = PrivateKeyError; type Err = PrivateKeyError;
fn from_bytes(b: &PrivateKeyBytes) -> Self { fn from_bytes(b: &PrivateKeyBytes) -> Self {
Self { key: *b } Self {
key: *b
}
} }
fn to_bytes(&self) -> PrivateKeyBytes { fn to_bytes(&self) -> PrivateKeyBytes {

View File

@ -77,10 +77,6 @@ pub enum PublicKeyError {
#[error("The provided public key must be nonzero, but is not")] #[error("The provided public key must be nonzero, but is not")]
NonZero, NonZero,
/// A scalar could not be constructed for the given algorithm.
#[error("A scalar could not be constructed for the given algorithm")]
InvalidScalar,
/// Public key derivation is unsupported for this algorithm. /// Public key derivation is unsupported for this algorithm.
#[error("Public key derivation is unsupported for this algorithm")] #[error("Public key derivation is unsupported for this algorithm")]
DerivationUnsupported, DerivationUnsupported,
@ -89,7 +85,7 @@ pub enum PublicKeyError {
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
use k256::{ use k256::{
elliptic_curve::{group::prime::PrimeCurveAffine, sec1::ToEncodedPoint}, elliptic_curve::{group::prime::PrimeCurveAffine, sec1::ToEncodedPoint},
AffinePoint, AffinePoint, NonZeroScalar,
}; };
#[cfg(feature = "secp256k1")] #[cfg(feature = "secp256k1")]
@ -109,16 +105,14 @@ impl PublicKey for k256::PublicKey {
} }
fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Self::Err> { fn derive_child(&self, other: PrivateKeyBytes) -> Result<Self, Self::Err> {
use k256::elliptic_curve::ScalarPrimitive; if other.iter().all(|n| n == &0) {
use k256::{Secp256k1, Scalar}; return Err(PublicKeyError::NonZero);
}
// Checked: See above
let scalar = Option::<NonZeroScalar>::from(NonZeroScalar::from_repr(other.into()))
.expect(bug!("Should have been able to get a NonZeroScalar"));
// Construct a scalar from bytes let point = self.to_projective() + (AffinePoint::generator() * *scalar);
let scalar = ScalarPrimitive::<Secp256k1>::from_bytes(&other.into());
let scalar = Option::<ScalarPrimitive<Secp256k1>>::from(scalar);
let scalar = scalar.ok_or(PublicKeyError::InvalidScalar)?;
let scalar = Scalar::from(scalar);
let point = self.to_projective() + (AffinePoint::generator() * scalar);
Ok(Self::from_affine(point.into()) Ok(Self::from_affine(point.into())
.expect(bug!("Could not from_affine after scalar arithmetic"))) .expect(bug!("Could not from_affine after scalar arithmetic")))
} }

View File

@ -10,7 +10,6 @@ use aes_gcm::{
aead::{consts::U12, Aead}, aead::{consts::U12, Aead},
Aes256Gcm, KeyInit, Nonce, Aes256Gcm, KeyInit, Nonce,
}; };
use base64::prelude::{Engine, BASE64_STANDARD};
use hkdf::Hkdf; use hkdf::Hkdf;
use keyfork_bug::{bug, POISONED_MUTEX}; use keyfork_bug::{bug, POISONED_MUTEX};
use keyfork_mnemonic_util::{English, Mnemonic}; use keyfork_mnemonic_util::{English, Mnemonic};
@ -24,6 +23,7 @@ use keyfork_prompt::{
use sha2::Sha256; use sha2::Sha256;
use sharks::{Share, Sharks}; use sharks::{Share, Sharks};
use x25519_dalek::{EphemeralSecret, PublicKey}; use x25519_dalek::{EphemeralSecret, PublicKey};
use base64::prelude::{BASE64_STANDARD, Engine};
// 32-byte share, 1-byte index, 1-byte threshold, 1-byte version == 36 bytes // 32-byte share, 1-byte index, 1-byte threshold, 1-byte version == 36 bytes
// Encrypted, is 52 bytes // Encrypted, is 52 bytes
@ -212,9 +212,7 @@ pub trait Format {
if let Ok(Some(qrcode_content)) = if let Ok(Some(qrcode_content)) =
keyfork_qrcode::scan_camera(std::time::Duration::from_secs(30), 0) keyfork_qrcode::scan_camera(std::time::Duration::from_secs(30), 0)
{ {
let decoded_data = BASE64_STANDARD let decoded_data = BASE64_STANDARD.decode(qrcode_content).unwrap();
.decode(qrcode_content)
.expect(bug!("qrcode should contain base64 encoded data"));
pubkey_data = Some(decoded_data.try_into().map_err(|_| InvalidData)?) pubkey_data = Some(decoded_data.try_into().map_err(|_| InvalidData)?)
} else { } else {
prompt prompt
@ -302,10 +300,7 @@ pub trait Format {
use keyfork_qrcode::{qrencode, ErrorCorrection}; use keyfork_qrcode::{qrencode, ErrorCorrection};
let mut qrcode_data = our_pubkey_mnemonic.to_bytes(); let mut qrcode_data = our_pubkey_mnemonic.to_bytes();
qrcode_data.extend(payload_mnemonic.as_bytes()); qrcode_data.extend(payload_mnemonic.as_bytes());
if let Ok(qrcode) = qrencode( if let Ok(qrcode) = qrencode(&BASE64_STANDARD.encode(qrcode_data), ErrorCorrection::Highest) {
&BASE64_STANDARD.encode(qrcode_data),
ErrorCorrection::Highest,
) {
prompt prompt
.lock() .lock()
.expect(bug!(POISONED_MUTEX)) .expect(bug!(POISONED_MUTEX))
@ -438,10 +433,7 @@ pub fn remote_decrypt(w: &mut impl Write) -> Result<(), Box<dyn std::error::Erro
{ {
use keyfork_qrcode::{qrencode, ErrorCorrection}; use keyfork_qrcode::{qrencode, ErrorCorrection};
let qrcode_data = key_mnemonic.to_bytes(); let qrcode_data = key_mnemonic.to_bytes();
if let Ok(qrcode) = qrencode( if let Ok(qrcode) = qrencode(&BASE64_STANDARD.encode(qrcode_data), ErrorCorrection::Highest) {
&BASE64_STANDARD.encode(qrcode_data),
ErrorCorrection::Highest,
) {
pm.prompt_message(PromptMessage::Text(format!( pm.prompt_message(PromptMessage::Text(format!(
concat!( concat!(
"A QR code will be displayed after this prompt. ", "A QR code will be displayed after this prompt. ",
@ -472,14 +464,7 @@ pub fn remote_decrypt(w: &mut impl Write) -> Result<(), Box<dyn std::error::Erro
if let Ok(Some(qrcode_content)) = if let Ok(Some(qrcode_content)) =
keyfork_qrcode::scan_camera(std::time::Duration::from_secs(QRCODE_TIMEOUT), 0) keyfork_qrcode::scan_camera(std::time::Duration::from_secs(QRCODE_TIMEOUT), 0)
{ {
let decoded_data = BASE64_STANDARD let decoded_data = BASE64_STANDARD.decode(qrcode_content).unwrap();
.decode(qrcode_content)
.expect(bug!("qrcode should contain base64 encoded data"));
assert_eq!(
decoded_data.len(),
ENCRYPTED_LENGTH as usize,
bug!("invalid payload data")
);
let _ = pubkey_data.insert(decoded_data[..32].try_into().map_err(|_| InvalidData)?); let _ = pubkey_data.insert(decoded_data[..32].try_into().map_err(|_| InvalidData)?);
let _ = payload_data.insert(decoded_data[32..].to_vec()); let _ = payload_data.insert(decoded_data[32..].to_vec());
} else { } else {