From 2981181817feeba526cfe4ce5ac6432604767e48 Mon Sep 17 00:00:00 2001 From: librelois Date: Sun, 14 Feb 2021 17:14:35 +0100 Subject: [PATCH 1/2] fix(dubp): master pubkey of HD wallet must not be accessible --- Cargo.lock | 4 ++-- native/dubp_rs/Cargo.toml | 2 +- native/dubp_rs/src/dewif.rs | 33 +++++++++++---------------------- native/dubp_rs/src/error.rs | 4 ++++ native/dubp_rs/src/lib.rs | 14 +++++--------- packages/dubp_rs/lib/dubp.dart | 13 ++++--------- 6 files changed, 27 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c46888..d83c496 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "dup-crypto" -version = "0.41.0" +version = "0.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6b6eb9f9a9e92e70515090be3733857966f2a635564f36e78af047e63a1bf" +checksum = "e69f621e9575ed2647fb67a9e8a8d8d5cc8d9281dec2fc848c7619a159501562" dependencies = [ "aes", "arrayvec", diff --git a/native/dubp_rs/Cargo.toml b/native/dubp_rs/Cargo.toml index 3d0519e..e51d6d3 100644 --- a/native/dubp_rs/Cargo.toml +++ b/native/dubp_rs/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["rlib"] [dependencies] allo-isolate = "0.1.6" -dup-crypto = { version = "0.41.0", features = ["bip32-ed25519", "dewif", "mnemonic", "mnemonic_french", "rand", "scrypt"] } +dup-crypto = { version = "0.41.1", features = ["bip32-ed25519", "dewif", "mnemonic", "mnemonic_french", "rand", "scrypt"] } fast-threadpool = { version = "0.3.0", default-features = false } once_cell = { version = "1.3.1", default-features = false, features = ["std"] } thiserror = "1.0.23" diff --git a/native/dubp_rs/src/dewif.rs b/native/dubp_rs/src/dewif.rs index 0c03efa..f317c3e 100644 --- a/native/dubp_rs/src/dewif.rs +++ b/native/dubp_rs/src/dewif.rs @@ -19,14 +19,12 @@ pub mod classic; use crate::*; pub(super) fn change_secret_code( - currency: &str, dewif: &str, old_secret_code: &str, member_wallet: bool, secret_code_type: SecretCodeType, system_memory: i64, ) -> Result, DubpError> { - let currency = parse_currency(currency)?; let new_log_n = log_n(system_memory); let new_secret_code = gen_secret_code(member_wallet, secret_code_type, new_log_n)?; @@ -34,9 +32,7 @@ pub(super) fn change_secret_code( dup_crypto::dewif::change_dewif_passphrase(dewif, old_secret_code, &new_secret_code) .map_err(DubpError::DewifReadError)?; - let pubkey = get_pubkey(currency, &new_dewif, &new_secret_code)?; - - Ok(vec![new_dewif, new_secret_code, pubkey]) + Ok(vec![new_dewif, new_secret_code]) } pub(super) fn gen_dewif( @@ -56,28 +52,19 @@ pub(super) fn gen_dewif( let log_n = log_n(system_memory); let secret_code = gen_secret_code(member_wallet, secret_code_type, log_n)?; - let (dewif, pubkey) = match wallet_type { + let dewif = match wallet_type { WalletType::Bip32Ed25519 => { let keypair = dup_crypto::keys::ed25519::bip32::KeyPair::from_seed(seed.clone()); let pubkey = keypair.public_key(); - let dewif = dup_crypto::dewif::write_dewif_v4_content( - currency, - log_n, - &secret_code, - &pubkey, - seed, - ); - (dewif, pubkey.to_base58()) + dup_crypto::dewif::write_dewif_v4_content(currency, log_n, &secret_code, &pubkey, seed) } WalletType::Ed25519 => { let keypair = KeyPairFromSeed32Generator::generate(seed); - let dewif = - dup_crypto::dewif::write_dewif_v3_content(currency, &keypair, log_n, &secret_code); - (dewif, keypair.public_key().to_base58()) + dup_crypto::dewif::write_dewif_v3_content(currency, &keypair, log_n, &secret_code) } }; - Ok(vec![dewif, secret_code, pubkey]) + Ok(vec![dewif, secret_code]) } pub(super) fn get_secret_code_len( @@ -110,10 +97,12 @@ pub(super) fn get_pubkey( &secret_code.to_ascii_uppercase(), ) .map_err(DubpError::DewifReadError)?; - if let Some(keypair) = keypairs.next() { - Ok(keypair.public_key().to_base58()) - } else { - Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)) + + match keypairs.next() { + Some(KeyPairEnum::Ed25519(keypair)) => Ok(keypair.public_key().to_base58()), + Some(KeyPairEnum::Bip32Ed25519(_)) => Err(DubpError::GetMasterPubkeyOfHdWallet), + Some(_) => Err(DubpError::UnsupportedDewifVersion), + None => Err(DubpError::DewifReadError(DewifReadError::CorruptedContent)), } } diff --git a/native/dubp_rs/src/error.rs b/native/dubp_rs/src/error.rs index 2f55f01..379a48c 100644 --- a/native/dubp_rs/src/error.rs +++ b/native/dubp_rs/src/error.rs @@ -28,6 +28,8 @@ pub(crate) enum DubpError { InvalidDerivationIndex(InvalidDerivationIndex), #[error("Digits secret code forbid for member wallet")] DigitsCodeForbidForMemberWallet, + #[error("It is forbidden to retrieve the master public key of an HD wallet.")] + GetMasterPubkeyOfHdWallet, #[error("this wallet is not an HD wallet")] NotHdWallet, #[error("this account index is not a transparent account index")] @@ -40,6 +42,8 @@ pub(crate) enum DubpError { UnknownCurrencyName, #[error("Unknown language")] UnknownLanguage, + #[error("Unsupported DEWIF version")] + UnsupportedDewifVersion, #[error("{0}")] Utf8Error(std::str::Utf8Error), #[error("Wrong language")] diff --git a/native/dubp_rs/src/lib.rs b/native/dubp_rs/src/lib.rs index 3a319ae..602f49a 100644 --- a/native/dubp_rs/src/lib.rs +++ b/native/dubp_rs/src/lib.rs @@ -45,9 +45,8 @@ use thiserror::Error; #[no_mangle] pub extern "C" fn change_dewif_secret_code( port: i64, - currency: *const raw::c_char, dewif: *const raw::c_char, - old_pin: *const raw::c_char, + old_secret_code: *const raw::c_char, member_wallet: u32, secret_code_type: u32, system_memory: i64, @@ -55,25 +54,22 @@ pub extern "C" fn change_dewif_secret_code( exec_async( port, || { - let currency = char_ptr_to_str(currency)?; let dewif = char_ptr_to_str(dewif)?; - let old_pin = char_ptr_to_str(old_pin)?; + let old_secret_code = char_ptr_to_str(old_secret_code)?; let member_wallet = member_wallet != 0; let secret_code_type = SecretCodeType::from(secret_code_type); Ok(( - currency, dewif, - old_pin, + old_secret_code, member_wallet, secret_code_type, system_memory, )) }, - |(currency, dewif, old_pin, member_wallet, secret_code_type, system_memory)| { + |(dewif, old_secret_code, member_wallet, secret_code_type, system_memory)| { dewif::change_secret_code( - currency, dewif, - old_pin, + old_secret_code, member_wallet, secret_code_type, system_memory, diff --git a/packages/dubp_rs/lib/dubp.dart b/packages/dubp_rs/lib/dubp.dart index c80fafd..f3e692c 100644 --- a/packages/dubp_rs/lib/dubp.dart +++ b/packages/dubp_rs/lib/dubp.dart @@ -23,10 +23,7 @@ class NewWallet { /// Secret code String pin; - /// Public key - String publicKey; - - NewWallet._(this.dewif, this.pin, this.publicKey); + NewWallet._(this.dewif, this.pin); } /// Secret code type @@ -60,7 +57,6 @@ class DubpRust { /// Change the secret code that encrypts the `dewif` keypair. static Future changeDewifPin({ - String currency = "g1", String dewif, String oldPin, SecretCodeType secretCodeType = SecretCodeType.letters, @@ -72,7 +68,6 @@ class DubpRust { callback: _handleErrList); native.change_dewif_secret_code( sendPort.nativePort, - Utf8.toUtf8(currency), Utf8.toUtf8(dewif), Utf8.toUtf8(oldPin), 0, @@ -81,7 +76,7 @@ class DubpRust { ); List newWallet = await completer.future; - return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2])); + return Future.value(NewWallet._(newWallet[0], newWallet[1])); } /// Generate a random mnemonic @@ -122,7 +117,7 @@ class DubpRust { ); List newWallet = await completer.future; - return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2])); + return Future.value(NewWallet._(newWallet[0], newWallet[1])); } /// Generate a wallet from a mnemonic phrase. @@ -157,7 +152,7 @@ class DubpRust { ); List newWallet = await completer.future; - return Future.value(NewWallet._(newWallet[0], newWallet[1], newWallet[2])); + return Future.value(NewWallet._(newWallet[0], newWallet[1])); } //get_bip32_dewif_accounts_pubkeys From 673e2db2ba78c35ff7b1b60317560837f1d6cb8c Mon Sep 17 00:00:00 2001 From: librelois Date: Sun, 14 Feb 2021 17:36:44 +0100 Subject: [PATCH 2/2] feat(dubp): add method getDewifMetaData --- native/dubp_rs/src/dewif.rs | 53 +++++++++++++++++++++++++++++------------- native/dubp_rs/src/lib.rs | 21 +++++++++++++++++ packages/dubp_rs/lib/dubp.dart | 38 ++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 16 deletions(-) diff --git a/native/dubp_rs/src/dewif.rs b/native/dubp_rs/src/dewif.rs index f317c3e..c017d69 100644 --- a/native/dubp_rs/src/dewif.rs +++ b/native/dubp_rs/src/dewif.rs @@ -67,23 +67,25 @@ pub(super) fn gen_dewif( Ok(vec![dewif, secret_code]) } -pub(super) fn get_secret_code_len( - dewif: *const raw::c_char, - member_wallet: u32, - secret_code_type: u32, -) -> Result { - let dewif = char_ptr_to_str(dewif)?; - let member_wallet = member_wallet != 0; - let secret_code_type = SecretCodeType::from(secret_code_type); - - let log_n = dup_crypto::dewif::read_dewif_log_n(ExpectedCurrency::Any, dewif) - .map_err(DubpError::DewifReadError)?; - - Ok(crate::secret_code::compute_secret_code_len( - member_wallet, - secret_code_type, +pub(super) fn get_dewif_meta( + dewif: &str, + member_wallet: bool, + secret_code_type: SecretCodeType, +) -> Result, DubpError> { + let dup_crypto::dewif::DewifMeta { + currency, log_n, - )?) + version, + } = dup_crypto::dewif::read_dewif_meta(dewif).map_err(DubpError::DewifReadError)?; + + let secret_code_len = + crate::secret_code::compute_secret_code_len(member_wallet, secret_code_type, log_n)?; + + Ok(vec![ + currency.to_string(), + secret_code_len.to_string(), + version.to_string(), + ]) } pub(super) fn get_pubkey( @@ -106,6 +108,25 @@ pub(super) fn get_pubkey( } } +pub(super) fn get_secret_code_len( + dewif: *const raw::c_char, + member_wallet: u32, + secret_code_type: u32, +) -> Result { + let dewif = char_ptr_to_str(dewif)?; + let member_wallet = member_wallet != 0; + let secret_code_type = SecretCodeType::from(secret_code_type); + + let log_n = dup_crypto::dewif::read_dewif_log_n(ExpectedCurrency::Any, dewif) + .map_err(DubpError::DewifReadError)?; + + Ok(crate::secret_code::compute_secret_code_len( + member_wallet, + secret_code_type, + log_n, + )?) +} + pub(crate) fn log_n(system_memory: i64) -> u8 { if system_memory > 3_000_000_000 { 15 diff --git a/native/dubp_rs/src/lib.rs b/native/dubp_rs/src/lib.rs index 602f49a..6109089 100644 --- a/native/dubp_rs/src/lib.rs +++ b/native/dubp_rs/src/lib.rs @@ -176,6 +176,27 @@ pub extern "C" fn gen_mnemonic(port: i64, language: u32) { } #[no_mangle] +pub extern "C" fn get_dewif_meta( + port: i64, + dewif: *const raw::c_char, + member_wallet: u32, + secret_code_type: u32, +) { + exec_async( + port, + || { + let dewif = char_ptr_to_str(dewif)?; + let member_wallet = member_wallet != 0; + let secret_code_type = SecretCodeType::from(secret_code_type); + Ok((dewif, member_wallet, secret_code_type)) + }, + |(dewif, member_wallet, secret_code_type)| { + dewif::get_dewif_meta(dewif, member_wallet, secret_code_type) + }, + ) +} + +#[no_mangle] pub extern "C" fn get_dewif_secret_code_len( dewif: *const raw::c_char, member_wallet: u32, diff --git a/packages/dubp_rs/lib/dubp.dart b/packages/dubp_rs/lib/dubp.dart index f3e692c..da50c41 100644 --- a/packages/dubp_rs/lib/dubp.dart +++ b/packages/dubp_rs/lib/dubp.dart @@ -6,6 +6,29 @@ import "package:system_info/system_info.dart"; import 'ffi.dart' as native; +/// DEWIF meta data +class DewifMetaData { + /// Currency name + String currency; + + /// Secret code length + int secretCodeLen; + + /// DEWIF version + int version; + + /// Wallet type + WalletType walletType; + + DewifMetaData._(this.currency, this.secretCodeLen, this.version) { + if (version == 4) { + walletType = WalletType.bip32Ed25519; + } else { + walletType = WalletType.ed25519; + } + } +} + /// Language enum Language { /// English @@ -176,6 +199,21 @@ class DubpRust { return completer.future; } + /// Get `dewif` keypair meta data. + static Future getDewifMetaData( + {String dewif, + SecretCodeType secretCodeType = SecretCodeType.letters}) async { + final completer = Completer>(); + final sendPort = singleCompletePort, List>(completer, + callback: _handleErrList); + native.get_dewif_meta( + sendPort.nativePort, Utf8.toUtf8(dewif), 0, secretCodeType.index); + List dewifMetaData = await completer.future; + + return Future.value(DewifMetaData._(dewifMetaData[0], + int.parse(dewifMetaData[1]), int.parse(dewifMetaData[2]))); + } + /// Get public key (in base 58) of `dewif` keypair. static Future getDewifPublicKey( {String currency = "g1", String dewif, String pin}) async {