Compare commits
2 Commits
536e6da5ad
...
f5627e5bd9
Author | SHA1 | Date |
---|---|---|
Ryan Heywood | f5627e5bd9 | |
Ryan Heywood | 02e5b545a4 |
|
@ -57,7 +57,7 @@ pub async fn start_and_run_server_on(
|
||||||
let service = ServiceBuilder::new()
|
let service = ServiceBuilder::new()
|
||||||
.layer(middleware::BincodeLayer::new())
|
.layer(middleware::BincodeLayer::new())
|
||||||
// TODO: passphrase support and/or store passphrase with mnemonic
|
// TODO: passphrase support and/or store passphrase with mnemonic
|
||||||
.service(Keyforkd::new(mnemonic.generate_seed(None)));
|
.service(Keyforkd::new(mnemonic.generate_seed(None).to_vec()));
|
||||||
|
|
||||||
let mut server = match UnixServer::bind(socket_path) {
|
let mut server = match UnixServer::bind(socket_path) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
|
|
|
@ -249,7 +249,7 @@ pub trait Format {
|
||||||
|
|
||||||
// create our shared key
|
// create our shared key
|
||||||
let our_key = EphemeralSecret::random();
|
let our_key = EphemeralSecret::random();
|
||||||
let our_pubkey_mnemonic = Mnemonic::from_bytes(PublicKey::from(&our_key).as_bytes())?;
|
let our_pubkey_mnemonic = Mnemonic::try_from_slice(PublicKey::from(&our_key).as_bytes())?;
|
||||||
let shared_secret = our_key.diffie_hellman(&PublicKey::from(their_pubkey));
|
let shared_secret = our_key.diffie_hellman(&PublicKey::from(their_pubkey));
|
||||||
assert!(
|
assert!(
|
||||||
shared_secret.was_contributory(),
|
shared_secret.was_contributory(),
|
||||||
|
@ -302,7 +302,7 @@ pub trait Format {
|
||||||
let mut mnemonic_bytes = [0u8; ENCRYPTED_LENGTH as usize];
|
let mut mnemonic_bytes = [0u8; ENCRYPTED_LENGTH as usize];
|
||||||
mnemonic_bytes.copy_from_slice(&encrypted_bytes);
|
mnemonic_bytes.copy_from_slice(&encrypted_bytes);
|
||||||
|
|
||||||
let payload_mnemonic = Mnemonic::from_nonstandard_bytes(mnemonic_bytes);
|
let payload_mnemonic = Mnemonic::from_array(mnemonic_bytes);
|
||||||
|
|
||||||
#[cfg(feature = "qrcode")]
|
#[cfg(feature = "qrcode")]
|
||||||
{
|
{
|
||||||
|
@ -439,7 +439,7 @@ pub fn remote_decrypt(w: &mut impl Write) -> Result<(), Box<dyn std::error::Erro
|
||||||
while iter_count.is_none() || iter_count.is_some_and(|i| i > 0) {
|
while iter_count.is_none() || iter_count.is_some_and(|i| i > 0) {
|
||||||
iter += 1;
|
iter += 1;
|
||||||
let our_key = EphemeralSecret::random();
|
let our_key = EphemeralSecret::random();
|
||||||
let key_mnemonic = Mnemonic::from_bytes(PublicKey::from(&our_key).as_bytes())?;
|
let key_mnemonic = Mnemonic::try_from_slice(PublicKey::from(&our_key).as_bytes())?;
|
||||||
|
|
||||||
#[cfg(feature = "qrcode")]
|
#[cfg(feature = "qrcode")]
|
||||||
{
|
{
|
||||||
|
|
|
@ -109,7 +109,7 @@ impl MnemonicSeedSource {
|
||||||
MnemonicSeedSource::Tarot => todo!(),
|
MnemonicSeedSource::Tarot => todo!(),
|
||||||
MnemonicSeedSource::Dice => todo!(),
|
MnemonicSeedSource::Dice => todo!(),
|
||||||
};
|
};
|
||||||
let mnemonic = keyfork_mnemonic_util::Mnemonic::from_bytes(&seed)?;
|
let mnemonic = keyfork_mnemonic_util::Mnemonic::try_from_slice(&seed)?;
|
||||||
Ok(mnemonic.to_string())
|
Ok(mnemonic.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ pub struct Recover {
|
||||||
impl Recover {
|
impl Recover {
|
||||||
pub fn handle(&self, _k: &Keyfork) -> Result<()> {
|
pub fn handle(&self, _k: &Keyfork) -> Result<()> {
|
||||||
let seed = self.command.handle()?;
|
let seed = self.command.handle()?;
|
||||||
let mnemonic = Mnemonic::from_bytes(&seed)?;
|
let mnemonic = Mnemonic::try_from_slice(&seed)?;
|
||||||
tokio::runtime::Builder::new_multi_thread()
|
tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
.build()
|
.build()
|
||||||
|
|
|
@ -14,7 +14,7 @@ use keyfork_derive_openpgp::{
|
||||||
openpgp::{self, packet::UserID, types::KeyFlags, Cert, serialize::Marshal, armor::{Writer, Kind}},
|
openpgp::{self, packet::UserID, types::KeyFlags, Cert, serialize::Marshal, armor::{Writer, Kind}},
|
||||||
XPrv,
|
XPrv,
|
||||||
};
|
};
|
||||||
use keyfork_derive_util::{DerivationIndex, DerivationPath, VariableLengthSeed};
|
use keyfork_derive_util::{DerivationIndex, DerivationPath};
|
||||||
use keyfork_prompt::{
|
use keyfork_prompt::{
|
||||||
default_terminal,
|
default_terminal,
|
||||||
validators::{SecurePinValidator, Validator},
|
validators::{SecurePinValidator, Validator},
|
||||||
|
@ -195,8 +195,7 @@ fn generate_shard_secret(
|
||||||
|
|
||||||
fn bottoms_up(key_discovery: &Path, threshold: u8, output_shardfile: &Path, output_cert: &Path, user_id: &str,) -> Result<()> {
|
fn bottoms_up(key_discovery: &Path, threshold: u8, output_shardfile: &Path, output_cert: &Path, user_id: &str,) -> Result<()> {
|
||||||
let entropy = keyfork_entropy::generate_entropy_of_const_size::<{ 256 / 8 }>()?;
|
let entropy = keyfork_entropy::generate_entropy_of_const_size::<{ 256 / 8 }>()?;
|
||||||
let mnemonic = Mnemonic::from_nonstandard_bytes(entropy);
|
let mnemonic = Mnemonic::from_array(entropy);
|
||||||
// TODO: make this return const size, since is hash based
|
|
||||||
let seed = mnemonic.generate_seed(None);
|
let seed = mnemonic.generate_seed(None);
|
||||||
|
|
||||||
// TODO: should this allow for customizing the account index from 0? Potential for key reuse
|
// TODO: should this allow for customizing the account index from 0? Potential for key reuse
|
||||||
|
@ -213,7 +212,7 @@ fn bottoms_up(key_discovery: &Path, threshold: u8, output_shardfile: &Path, outp
|
||||||
.set_storage_encryption(),
|
.set_storage_encryption(),
|
||||||
KeyFlags::empty().set_authentication(),
|
KeyFlags::empty().set_authentication(),
|
||||||
];
|
];
|
||||||
let xprv = XPrv::new(VariableLengthSeed::new(&seed))
|
let xprv = XPrv::new(seed)
|
||||||
.expect("could not construct master key from seed")
|
.expect("could not construct master key from seed")
|
||||||
.derive_path(&path)?;
|
.derive_path(&path)?;
|
||||||
let userid = UserID::from(user_id);
|
let userid = UserID::from(user_id);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
//! use keyfork_mnemonic_util::Mnemonic;
|
//! use keyfork_mnemonic_util::Mnemonic;
|
||||||
//! let data = b"Hello, world! I am a mnemonic :)";
|
//! let data = b"Hello, world! I am a mnemonic :)";
|
||||||
//! assert_eq!(data.len(), 32);
|
//! assert_eq!(data.len(), 32);
|
||||||
//! let mnemonic = Mnemonic::from_bytes(data).unwrap();
|
//! let mnemonic = Mnemonic::try_from_slice(data).unwrap();
|
||||||
//! println!("Our mnemonic is: {mnemonic}");
|
//! println!("Our mnemonic is: {mnemonic}");
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
@ -270,9 +270,9 @@ where
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use keyfork_mnemonic_util::Mnemonic;
|
/// use keyfork_mnemonic_util::Mnemonic;
|
||||||
/// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
/// let data = b"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||||
/// let mnemonic = Mnemonic::from_bytes(data.as_slice()).unwrap();
|
/// let mnemonic = Mnemonic::try_from_slice(data.as_slice()).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Result<MnemonicBase<W>, MnemonicGenerationError> {
|
pub fn try_from_slice(bytes: &[u8]) -> Result<MnemonicBase<W>, MnemonicGenerationError> {
|
||||||
let bit_count = bytes.len() * 8;
|
let bit_count = bytes.len() * 8;
|
||||||
|
|
||||||
if bit_count % 32 != 0 {
|
if bit_count % 32 != 0 {
|
||||||
|
@ -292,21 +292,21 @@ where
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use keyfork_mnemonic_util::Mnemonic;
|
/// use keyfork_mnemonic_util::Mnemonic;
|
||||||
/// let data = b"hello world!";
|
/// let data = b"hello world!";
|
||||||
/// let mnemonic = Mnemonic::from_nonstandard_bytes(*data);
|
/// let mnemonic = Mnemonic::from_array(*data);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If an invalid size is requested, the code will fail to compile:
|
/// If an invalid size is requested, the code will fail to compile:
|
||||||
///
|
///
|
||||||
/// ```rust,compile_fail
|
/// ```rust,compile_fail
|
||||||
/// use keyfork_mnemonic_util::Mnemonic;
|
/// use keyfork_mnemonic_util::Mnemonic;
|
||||||
/// let mnemonic = Mnemonic::from_nonstandard_bytes([0u8; 53]);
|
/// let mnemonic = Mnemonic::from_array([0u8; 53]);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ```rust,compile_fail
|
/// ```rust,compile_fail
|
||||||
/// use keyfork_mnemonic_util::Mnemonic;
|
/// use keyfork_mnemonic_util::Mnemonic;
|
||||||
/// let mnemonic = Mnemonic::from_nonstandard_bytes([0u8; 1024 + 4]);
|
/// let mnemonic = Mnemonic::from_array([0u8; 1024 + 4]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_nonstandard_bytes<const N: usize>(bytes: [u8; N]) -> MnemonicBase<W> {
|
pub fn from_array<const N: usize>(bytes: [u8; N]) -> MnemonicBase<W> {
|
||||||
#[allow(clippy::let_unit_value)]
|
#[allow(clippy::let_unit_value)]
|
||||||
{
|
{
|
||||||
let () = AssertValidMnemonicSize::<N>::OK_CHUNKS;
|
let () = AssertValidMnemonicSize::<N>::OK_CHUNKS;
|
||||||
|
@ -315,16 +315,6 @@ where
|
||||||
Self::from_raw_bytes(&bytes)
|
Self::from_raw_bytes(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data is expected to be
|
|
||||||
/// of 128, 192, or 256 bits, as per BIP-0039.
|
|
||||||
///
|
|
||||||
/// # Errors
|
|
||||||
/// An error may be returned if the data is not within the expected lengths.
|
|
||||||
#[deprecated = "use Mnemonic::from_bytes"]
|
|
||||||
pub fn from_entropy(bytes: &[u8]) -> Result<MnemonicBase<W>, MnemonicGenerationError> {
|
|
||||||
MnemonicBase::from_bytes(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a Mnemonic using an arbitrary length of given data. The length does not need to
|
/// Create a Mnemonic using an arbitrary length of given data. The length does not need to
|
||||||
/// conform to BIP-0039 standards, but should be a multiple of 32 bits or 4 bytes.
|
/// conform to BIP-0039 standards, but should be a multiple of 32 bits or 4 bytes.
|
||||||
///
|
///
|
||||||
|
@ -332,8 +322,8 @@ where
|
||||||
/// This function can potentially produce mnemonics that are not BIP-0039 compliant or can't
|
/// This function can potentially produce mnemonics that are not BIP-0039 compliant or can't
|
||||||
/// properly be encoded as a mnemonic. It is assumed the caller asserts the byte count is `% 4
|
/// properly be encoded as a mnemonic. It is assumed the caller asserts the byte count is `% 4
|
||||||
/// == 0`. If the assumption is incorrect, code may panic. The
|
/// == 0`. If the assumption is incorrect, code may panic. The
|
||||||
/// [`MnemonicBase::from_nonstandard_bytes`] function may be used to generate entropy if the
|
/// [`MnemonicBase::from_array`] function may be used to generate entropy if the length of the
|
||||||
/// length of the data is known at compile-time.
|
/// data is known at compile-time.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```rust
|
/// ```rust
|
||||||
|
@ -408,7 +398,7 @@ where
|
||||||
&self,
|
&self,
|
||||||
passphrase: impl Into<Option<&'a str>>,
|
passphrase: impl Into<Option<&'a str>>,
|
||||||
) -> Result<Vec<u8>, MnemonicGenerationError> {
|
) -> Result<Vec<u8>, MnemonicGenerationError> {
|
||||||
Ok(self.generate_seed(passphrase))
|
Ok(self.generate_seed(passphrase).to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a BIP-0032 seed from the provided data and an optional passphrase.
|
/// Create a BIP-0032 seed from the provided data and an optional passphrase.
|
||||||
|
@ -416,8 +406,7 @@ where
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// The function may panic if the HmacSha512 function returns an error. The only error the
|
/// The function may panic if the HmacSha512 function returns an error. The only error the
|
||||||
/// HmacSha512 function should return is an invalid length, which should not be possible.
|
/// HmacSha512 function should return is an invalid length, which should not be possible.
|
||||||
///
|
pub fn generate_seed<'a>(&self, passphrase: impl Into<Option<&'a str>>) -> [u8; 64] {
|
||||||
pub fn generate_seed<'a>(&self, passphrase: impl Into<Option<&'a str>>) -> Vec<u8> {
|
|
||||||
let passphrase = passphrase.into();
|
let passphrase = passphrase.into();
|
||||||
|
|
||||||
let mut seed = [0u8; 64];
|
let mut seed = [0u8; 64];
|
||||||
|
@ -425,7 +414,7 @@ where
|
||||||
let salt = ["mnemonic", passphrase.unwrap_or("")].join("");
|
let salt = ["mnemonic", passphrase.unwrap_or("")].join("");
|
||||||
pbkdf2::<Hmac<Sha512>>(mnemonic.as_bytes(), salt.as_bytes(), 2048, &mut seed)
|
pbkdf2::<Hmac<Sha512>>(mnemonic.as_bytes(), salt.as_bytes(), 2048, &mut seed)
|
||||||
.expect(bug!("HmacSha512 InvalidLength should be infallible"));
|
.expect(bug!("HmacSha512 InvalidLength should be infallible"));
|
||||||
seed.to_vec()
|
seed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encode the mnemonic into a list of integers 11 bits in length, matching the length of a
|
/// Encode the mnemonic into a list of integers 11 bits in length, matching the length of a
|
||||||
|
@ -462,6 +451,39 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<W> MnemonicBase<W>
|
||||||
|
where
|
||||||
|
W: Wordlist,
|
||||||
|
{
|
||||||
|
/// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data is expected to be
|
||||||
|
/// of 128, 192, or 256 bits, as per BIP-0039.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// An error may be returned if the data is not within the expected lengths.
|
||||||
|
#[deprecated = "use Mnemonic::try_from_slice"]
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> Result<MnemonicBase<W>, MnemonicGenerationError> {
|
||||||
|
MnemonicBase::try_from_slice(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data is expected to be
|
||||||
|
/// of 128, 192, or 256 bits, as per BIP-0039.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// An error may be returned if the data is not within the expected lengths.
|
||||||
|
#[deprecated = "use Mnemonic::try_from_slice"]
|
||||||
|
pub fn from_entropy(bytes: &[u8]) -> Result<MnemonicBase<W>, MnemonicGenerationError> {
|
||||||
|
MnemonicBase::try_from_slice(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a [`Mnemonic`] from the provided data and [`Wordlist`]. The data may be of a size
|
||||||
|
/// of a factor of 4, up to 1024 bytes.
|
||||||
|
///
|
||||||
|
#[deprecated = "Use Mnemonic::from_array"]
|
||||||
|
pub fn from_nonstandard_bytes<const N: usize>(bytes: [u8; N]) -> MnemonicBase<W> {
|
||||||
|
MnemonicBase::from_array(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{collections::HashSet, fs::File, io::Read};
|
use std::{collections::HashSet, fs::File, io::Read};
|
||||||
|
@ -478,7 +500,7 @@ mod tests {
|
||||||
let mut random_handle = File::open("/dev/random").unwrap();
|
let mut random_handle = File::open("/dev/random").unwrap();
|
||||||
let entropy = &mut [0u8; 256 / 8];
|
let entropy = &mut [0u8; 256 / 8];
|
||||||
random_handle.read_exact(&mut entropy[..]).unwrap();
|
random_handle.read_exact(&mut entropy[..]).unwrap();
|
||||||
let mnemonic = super::Mnemonic::from_bytes(&entropy[..256 / 8]).unwrap();
|
let mnemonic = super::Mnemonic::try_from_slice(&entropy[..256 / 8]).unwrap();
|
||||||
let new_entropy = mnemonic.as_bytes();
|
let new_entropy = mnemonic.as_bytes();
|
||||||
assert_eq!(new_entropy, entropy);
|
assert_eq!(new_entropy, entropy);
|
||||||
}
|
}
|
||||||
|
@ -494,7 +516,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
let hex = hex::decode(hex_.as_str().unwrap()).unwrap();
|
let hex = hex::decode(hex_.as_str().unwrap()).unwrap();
|
||||||
|
|
||||||
let mnemonic = Mnemonic::from_bytes(&hex).unwrap();
|
let mnemonic = Mnemonic::try_from_slice(&hex).unwrap();
|
||||||
|
|
||||||
assert_eq!(mnemonic.to_string(), seed.as_str().unwrap());
|
assert_eq!(mnemonic.to_string(), seed.as_str().unwrap());
|
||||||
}
|
}
|
||||||
|
@ -505,7 +527,7 @@ mod tests {
|
||||||
let mut random_handle = File::open("/dev/random").unwrap();
|
let mut random_handle = File::open("/dev/random").unwrap();
|
||||||
let entropy = &mut [0u8; 256 / 8];
|
let entropy = &mut [0u8; 256 / 8];
|
||||||
random_handle.read_exact(&mut entropy[..]).unwrap();
|
random_handle.read_exact(&mut entropy[..]).unwrap();
|
||||||
let my_mnemonic = Mnemonic::from_bytes(&entropy[..256 / 8]).unwrap();
|
let my_mnemonic = Mnemonic::try_from_slice(&entropy[..256 / 8]).unwrap();
|
||||||
let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap();
|
let their_mnemonic = bip39::Mnemonic::from_entropy(&entropy[..256 / 8]).unwrap();
|
||||||
assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string());
|
assert_eq!(my_mnemonic.to_string(), their_mnemonic.to_string());
|
||||||
assert_eq!(my_mnemonic.generate_seed(None), their_mnemonic.to_seed(""));
|
assert_eq!(my_mnemonic.generate_seed(None), their_mnemonic.to_seed(""));
|
||||||
|
@ -529,7 +551,7 @@ mod tests {
|
||||||
|
|
||||||
for _ in 0..tests {
|
for _ in 0..tests {
|
||||||
random.read_exact(&mut entropy[..]).unwrap();
|
random.read_exact(&mut entropy[..]).unwrap();
|
||||||
let mnemonic = Mnemonic::from_bytes(&entropy[..256 / 8]).unwrap();
|
let mnemonic = Mnemonic::try_from_slice(&entropy[..256 / 8]).unwrap();
|
||||||
let words = mnemonic.words();
|
let words = mnemonic.words();
|
||||||
hs.clear();
|
hs.clear();
|
||||||
hs.extend(words);
|
hs.extend(words);
|
||||||
|
@ -560,7 +582,7 @@ mod tests {
|
||||||
let mut entropy = [0u8; 1024];
|
let mut entropy = [0u8; 1024];
|
||||||
let mut random = std::fs::File::open("/dev/urandom").unwrap();
|
let mut random = std::fs::File::open("/dev/urandom").unwrap();
|
||||||
random.read_exact(&mut entropy[..]).unwrap();
|
random.read_exact(&mut entropy[..]).unwrap();
|
||||||
let mnemonic = Mnemonic::from_nonstandard_bytes(entropy);
|
let mnemonic = Mnemonic::from_array(entropy);
|
||||||
let words = mnemonic.words();
|
let words = mnemonic.words();
|
||||||
assert_eq!(words.len(), 768);
|
assert_eq!(words.len(), 768);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue