From 4817bf9526470f0bfa55b3aa68e961dc47a442d3 Mon Sep 17 00:00:00 2001 From: Ed Tubbs Date: Mon, 23 Oct 2023 21:23:46 -0500 Subject: [PATCH] spvnode: added software decrypts, master_key and encrypted file such: added software encrypts/decrypts, bip32_master_key, mnemonic_to_key, use_tpm, encrypted file and parameter checks seal: updated file names, error output and un-used variables wallet: added master_key parameter and software encrypts/decypts doc: added mnemonic_to_key, use_tpm, encrypted file and bip32_master_key in tools.md ci: added test-passwd config option cmake: added WIN32 and enabled USE_TPM2 config: disabled test-passwd by default --- .github/workflows/ci.yml | 22 +-- .github/workflows/ql.yml | 2 +- CMakeLists.txt | 12 +- configure.ac | 4 +- doc/tools.md | 41 +++-- include/dogecoin/wallet.h | 2 +- src/address.c | 5 +- src/cli/spvnode.c | 23 ++- src/cli/such.c | 320 +++++++++++++++++++++++++++----------- src/seal.c | 299 ++++++++++++++++++++++++++--------- src/wallet.c | 55 +++++-- tooltests.py | 4 +- 12 files changed, 567 insertions(+), 222 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae6fd332b..a2a8b8c27 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: os: ubuntu-20.04 packages: g++-arm-linux-gnueabihf qemu-user-static qemu-user dep-opts: "CROSS_COMPILE='yes' SPEED=slow V=1" - config-opts: "--enable-static --disable-shared" + config-opts: "--enable-static --disable-shared --enable-test-passwd" run-tests: true goal: install - name: aarch64-linux @@ -46,7 +46,7 @@ jobs: os: ubuntu-20.04 packages: g++-aarch64-linux-gnu qemu-user-static qemu-user dep-opts: "CROSS_COMPILE='yes' SPEED=slow V=1" - config-opts: "LIBS='-levent_pthreads' --enable-static --disable-shared" + config-opts: "LIBS='-levent_pthreads' --enable-static --disable-shared --enable-test-passwd" run-tests: true goal: install - name: x86_64-linux-dbg @@ -55,14 +55,14 @@ jobs: run-tests: true packages: python3-dev python3-dbg python dep-opts: "DEBUG=1 SPEED=slow V=1" - config-opts: "--enable-debug" + config-opts: "--enable-debug --enable-test-passwd" goal: install - name: x86_64-macos host: x86_64-apple-darwin15 os: macos-latest run-tests: true dep-opts: "SPEED=slow V=1" - config-opts: "--enable-static --disable-shared" + config-opts: "--enable-static --disable-shared --enable-test-passwd" packages: cmake zlib xorriso goal: install sdk: 12.2 @@ -90,7 +90,7 @@ jobs: sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix sudo update-binfmts --import /usr/share/binfmts/wine dep-opts: "CROSS_COMPILE='yes' SPEED=slow V=1" - config-opts: "" + config-opts: "--enable-test-passwd" run-tests: true goal: install - name: i686-win @@ -112,7 +112,7 @@ jobs: sudo update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix sudo update-binfmts --import /usr/share/binfmts/wine dep-opts: "CROSS_COMPILE='yes' SPEED=slow V=1" - config-opts: "" + config-opts: "--enable-test-passwd" run-tests: true goal: install - name: i686-linux @@ -121,7 +121,7 @@ jobs: packages: g++-multilib bc run-tests: true dep-opts: "SPEED=slow V=1" - config-opts: "--enable-static --disable-shared" + config-opts: "--enable-static --disable-shared --enable-test-passwd" goal: install runs-on: ${{ matrix.os }} @@ -227,17 +227,17 @@ jobs: if: ${{ matrix.run-tests }} run: | case "${{ matrix.name }}" in - "armhf-linux") + "armhf-linux") qemu-arm -E LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib/ /usr/arm-linux-gnueabihf/lib/ld-linux-armhf.so.3 ./tests ;; - "aarch64-linux") + "aarch64-linux") qemu-aarch64 -E LD_LIBRARY_PATH=/usr/aarch64-linux-gnu/lib/ /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 ./tests ;; - "x86_64-linux-dbg") + "x86_64-linux-dbg") make check -j"$(getconf _NPROCESSORS_ONLN)" V=1 python3 tooltests.py ;; - *) + *) make check -j"$(getconf _NPROCESSORS_ONLN)" V=1 ;; esac diff --git a/.github/workflows/ql.yml b/.github/workflows/ql.yml index c481e8362..00fb3240a 100755 --- a/.github/workflows/ql.yml +++ b/.github/workflows/ql.yml @@ -62,7 +62,7 @@ jobs: - name: build libdogecoin run: | ./autogen.sh - ./configure --prefix=`pwd`/depends/x86_64-pc-linux-gnu + ./configure --prefix=`pwd`/depends/x86_64-pc-linux-gnu --enable-test-passwd make check -j3 VERBOSE=1 - name: perform codeql analysis diff --git a/CMakeLists.txt b/CMakeLists.txt index 867bf50a2..abc204d9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,8 +26,8 @@ SET(WITH_LOGDB TRUE CACHE BOOL "enable logdb") SET(WITH_UNISTRING TRUE CACHE BOOL "enable unistring functions") SET(WITH_WALLET TRUE CACHE BOOL "enable wallet") SET(USE_SSE2 FALSE CACHE BOOL "enable scrypt sse2") -SET(USE_TPM2 FALSE CACHE BOOL "enable tpm_tests") -SET(TEST_PASSWD TRUE CACHE BOOL "enable test password") +SET(USE_TPM2 TRUE CACHE BOOL "enable tpm2") +SET(TEST_PASSWD FALSE CACHE BOOL "enable test password") SET(RANDOM_DEVICE "/dev/urandom" CACHE STRING "set the device to read random data from") # Set a default build type if none was specified @@ -267,7 +267,7 @@ IF(USE_TESTS) test/utils_tests.c test/vector_tests.c ) -IF (USE_TPM2) +IF (WIN32 AND USE_TPM2) TARGET_LINK_LIBRARIES(tests ${LIBDOGECOIN_NAME} ${LIBUNISTRING} tbs ncrypt crypt32) ELSE() TARGET_LINK_LIBRARIES(tests ${LIBDOGECOIN_NAME} ${LIBUNISTRING}) @@ -323,7 +323,7 @@ IF(WITH_NET) src/spv.c ) - IF(USE_TPM2) + IF(WIN32 AND USE_TPM2) TARGET_LINK_LIBRARIES(${LIBDOGECOIN_NAME} ${LIBEVENT} ${LIBEVENT_PTHREADS} ${LIBUNISTRING} ncrypt crypt32) ELSE() TARGET_LINK_LIBRARIES(${LIBDOGECOIN_NAME} ${LIBEVENT} ${LIBEVENT_PTHREADS} ${LIBUNISTRING}) @@ -346,7 +346,7 @@ IF(WITH_TOOLS) ADD_EXECUTABLE(such src/cli/such.c) INSTALL(TARGETS such RUNTIME) - IF (USE_TPM2) + IF (WIN32 AND USE_TPM2) TARGET_LINK_LIBRARIES(such ${LIBDOGECOIN_NAME} ${LIBUNISTRING} tbs ncrypt crypt32) ELSE() TARGET_LINK_LIBRARIES(such ${LIBDOGECOIN_NAME} ${LIBUNISTRING}) @@ -361,7 +361,7 @@ IF(WITH_TOOLS) ADD_EXECUTABLE(spvnode src/cli/spvnode.c) INSTALL(TARGETS spvnode RUNTIME) - IF (USE_TPM2) + IF (WIN32 AND USE_TPM2) TARGET_LINK_LIBRARIES(spvnode ${LIBDOGECOIN_NAME} tbs ncrypt crypt32) ELSE() TARGET_LINK_LIBRARIES(spvnode ${LIBDOGECOIN_NAME}) diff --git a/configure.ac b/configure.ac index 349a79dcc..2626fd3de 100644 --- a/configure.ac +++ b/configure.ac @@ -133,11 +133,11 @@ AC_ARG_ENABLE(tests, [use_tests=$enableval], [use_tests=yes]) -AC_ARG_ENABLE([test_passwd], +AC_ARG_ENABLE([test-passwd], [AS_HELP_STRING([--enable-test-passwd], [enable test password for encrypt/decrypt])], [test_passwd=$enableval], - [test_passwd=yes]) + [test_passwd=no]) AC_MSG_CHECKING([for __builtin_expect]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], diff --git a/doc/tools.md b/doc/tools.md index f6a0ac87b..584917862 100644 --- a/doc/tools.md +++ b/doc/tools.md @@ -14,12 +14,13 @@ The `such` tool can be used by simply running the command `./such` in the top le - generate_private_key - generate_public_key - p2pkh -- bip32_extended_master_key +- bip32_master_key - derive_child_keys - generate_mnemonic - list_encryption_keys_in_tpm -- decrypt_master_key_with_tpm -- decrypt_mnemonic_with_tpm +- decrypt_master_key +- decrypt_mnemonic +- mnemonic_to_key - mnemonic_to_addresses - print_keys - sign @@ -41,14 +42,15 @@ Most of these commands require a flag following them to denote things like exist | -k, --pubkey | public_key | yes | p2pkh -k | | -m, --derived_path | derived_path | yes | derive_child_key -p -m | | -e, --entropy | hex_entropy | yes | generate_mnemonic -e | -| -n, --mnemonic | seed_phrase | yes | mnemonic_to_addresses -n | -| -a, --pass_phrase | pass_phrase | yes | mnemonic_to_addresses -n -a | -| -o, --account_int | account_int | yes | mnemonic_to_addresses -n -o | -| -g, --change_level | change_level | yes | mnemonic_to_addresses -n -g | -| -i, --address_index | address_index | yes | mnemonic_to_addresses -n -i | -| -y, --tpm_file | file_num | yes | generate_mnemonic, bip32_extended_master_key, decrypt_master_key_with_tpm, decrypt_mnemonic_with_tpm or mnemonic_to_addresses -y -| -w, --overwrite | overwrite | no | generate_mnemonic or bip32_extended_master_key -w | -| -b, --silent | silent | no | generate_mnemonic or bip32_extended_master_key -b | +| -n, --mnemonic | seed_phrase | yes | mnemonic_to_key or mnemonic_to_addresses -n | +| -a, --pass_phrase | pass_phrase | yes | mnemonic_to_key or mnemonic_to_addresses -n -a | +| -o, --account_int | account_int | yes | mnemonic_to_key or mnemonic_to_addresses -n -o | +| -g, --change_level | change_level | yes | mnemonic_to_key or mnemonic_to_addresses -n -g | +| -i, --address_index | address_index | yes | mnemonic_to_key or mnemonic_to_addresses -n -i | +| -y, --encrypted_file | file_num | yes | generate_mnemonic, bip32_master_key, decrypt_master_key, decrypt_mnemonic, mnemonic_to_key or mnemonic_to_addresses -y +| -w, --overwrite | overwrite | no | generate_mnemonic or bip32_master_key -w | +| -b, --silent | silent | no | generate_mnemonic or bip32_master_key -b | +| -j, --use_tpm | use_tpm | no | generate_mnemonic, bip32_master_key, decrypt_master_key, decrypt_mnemonic, mnemonic_to_key or mnemonic_to_addresses -j | | -t, --testnet | designate_testnet | no | generate_private_key -t | | -s | script_hex | yes | comp2der -s | | -x | transaction_hex | yes | sign -x -s -i -h | @@ -62,13 +64,14 @@ Below is a list of all the commands and the flags that they require. As a remind | generate_private_key | None | -t | Generates a private key from a secp256k1 context for either mainnet or testnet. | | generate_public_key | -p | -t | Generates a public key derived from the private key specified. Include the testnet flag if it was generated from testnet. | | p2pkh | -k | -t | Generates a p2pkh address derived from the public key specified. Include the testnet flag if it was generated from testnet. | -| bip32_extended_master_key | None | -t | Generate an extended master private key from a secp256k1 context for either mainnet or testnet. | +| bip32_master_key | None | -t | Generate an extended master private key from a secp256k1 context for either mainnet or testnet. | | bip32maintotest | -p | None | Convert a mainnet private key into an equivalent testnet key. | | derive_child_keys | -p, -m | -t | Generates a child key derived from the specified private key using the specified derivation path. | generate_mnemonic | None | -e, -y, -w, -b | Generates a 24-word english seed phrase randomly or from optional hex entropy. | | list_encryption_keys_in_tpm | None | None | List the encryption keys in the TPM. | -| decrypt_master_key_with_tpm | -y | None | Decrypt the master key with the TPM. | -| decrypt_mnemonic_with_tpm | -y | None | Decrypt the mnemonic with the TPM. | +| decrypt_master_key | -y | -j | Decrypt the master key with the TPM or SW. | +| decrypt_mnemonic | -y | -j | Decrypt the mnemonic with the TPM or SW. | +| mnemonic_to_key | -n | -a, -y, -o, g, -i, -t | Generates a private key from a seed phrase with a default path or specified account, change level and index for either mainnet or testnet. | | mnemonic_to_addresses | -n | -a, -y, -o, g, -i, -t | Generates an address from a seed phrase with a default path or specified account, change level and index for either mainnet or testnet. | | print_keys | -p | -t | Print all keys associated with the provided private key. | sign | -x, -s, -i, -h, -p | -t | See the definition of sign_raw_transaction in the Transaction API. @@ -104,7 +107,7 @@ Below are some examples on how to use the `such` tool in practice. ##### Generate new BIP32 master key - ./such -c bip32_extended_master_key + ./such -c bip32_master_key > masterkey: dgpv51eADS3spNJh9qLpW8S7B7uZmusTpNE85NgXsYD7eGuVhebMDfEsj6fNR6DHgpSBCmYdAvw9YRSqRWnFxtYn1bM8AdNipwdi9dDXFCY8vkY @@ -136,7 +139,13 @@ Below are some examples on how to use the `such` tool in practice. ./such -c generate_mnemonic > they nuclear observe moral twenty gym hedgehog damage reveal syrup negative beach best silk alone feel vapor deposit belt host purity run clever deer -#### Geneate an HD address from the seed phrase for a given account (2), change level (1, internal) and index (0) for testnet +#### Generate a HD master key from the seed phrase for a given account (2), change level (1, internal) and index (0) for testnet + + ./such -c mnemonic_to_key -n "they nuclear observe moral twenty gym hedgehog damage reveal syrup negative beach best silk alone feel vapor deposit belt host purity run clever deer" -o 2 -g 1 -i 0 -t + > keypath: m/44'/1'/2'/1/0 + > private key (wif): cniAjMkD7HpzQKw67ByNsyzqMF8MEJo2y4viH2WEZRXoKHNih1sH + +#### Generate an HD address from the seed phrase for a given account (2), change level (1, internal) and index (0) for testnet ./such -c mnemonic_to_addresses -n "they nuclear observe moral twenty gym hedgehog damage reveal syrup negative beach best silk alone feel vapor deposit belt host purity run clever deer" -o 2 -g 1 -i 0 -t > Address: nW7ndt4HZh8XwLYN6v6N2S4mZCbpZPuFxh diff --git a/include/dogecoin/wallet.h b/include/dogecoin/wallet.h index 08ab9fe28..ddbbb6e22 100644 --- a/include/dogecoin/wallet.h +++ b/include/dogecoin/wallet.h @@ -129,7 +129,7 @@ LIBDOGECOIN_API void dogecoin_wallet_output_free(dogecoin_output* output); /** ------------------------------------ */ LIBDOGECOIN_API dogecoin_wallet* dogecoin_wallet_new(const dogecoin_chainparams *params); -LIBDOGECOIN_API dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const char* address, const char* name, const char* mnemonic_in, const char* pass, const dogecoin_bool tpm, const int file_num); +LIBDOGECOIN_API dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const char* address, const char* name, const char* mnemonic_in, const char* pass, const dogecoin_bool encrypted, const dogecoin_bool tpm, const int file_num, const dogecoin_bool master_key); LIBDOGECOIN_API void print_utxos(dogecoin_wallet* wallet); LIBDOGECOIN_API void dogecoin_wallet_free(dogecoin_wallet* wallet); diff --git a/src/address.c b/src/address.c index 388f6ebce..0e723c6db 100644 --- a/src/address.c +++ b/src/address.c @@ -763,6 +763,7 @@ int verifyHDMasterPubKeypairFromEncryptedSeed(const char* wif_privkey_master, co * @param account The BIP44 account to generate the derived address. * @param index The BIP44 index to generate the derived address. * @param change_level The BIP44 change level flag to generate derived address. + * @param pass The passphrase (optional). * @param p2pkh_pubkey_master The generated master public key. * @param is_testnet The flag denoting which network, 0 for mainnet and 1 for testnet. * @param file_num The file number to store the encrypted seed. @@ -788,7 +789,9 @@ int getDerivedHDAddressFromEncryptedMnemonic(const uint32_t account, const uint3 } /* Generate the root key from the mnemonic */ - dogecoin_seed_from_mnemonic(mnemonic, pass, seed); + if (dogecoin_seed_from_mnemonic(mnemonic, pass, seed) == -1) { + return -1; + } /* Generate the root key from the seed */ dogecoin_hdnode_from_seed(seed, MAX_SEED_SIZE, &node); diff --git a/src/cli/spvnode.c b/src/cli/spvnode.c index 377829880..4ab68b6d7 100644 --- a/src/cli/spvnode.c +++ b/src/cli/spvnode.c @@ -179,7 +179,9 @@ static struct option long_options[] = { {"checkpoint", no_argument, NULL, 'p'}, {"wallet_file", required_argument, NULL, 'w'}, {"headers_file", required_argument, NULL, 'h'}, - {"tpm_file", required_argument, NULL, 'y'}, + {"encrypted_file", required_argument, NULL, 'y'}, + {"use_tpm", no_argument, NULL, 'j'}, + {"master_key", no_argument, NULL, 'k'}, {"daemon", no_argument, NULL, 'z'}, {NULL, 0, NULL, 0} }; @@ -196,7 +198,8 @@ static void print_version() { static void print_usage() { print_version(); printf("Usage: spvnode (-c|continuous) (-i|-ips ) (-m[--maxpeers] ) (-t[--testnet]) (-f ) \ -(-n|-mnemonic ) (-s|-pass_phrase ) (-y|-tpm_file ) (-w|-wallet_file ) (-h|-headers_file ) (-r[--regtest]) (-d[--debug]) (-s[--timeout] ) \n"); +(-n|-mnemonic ) (-s|-pass_phrase ) (-y|-encrypted_file ) (-w|-wallet_file ) (-h|-headers_file ) \ +(-k[--master_key] (-j[--use_tpm]) (-r[--regtest]) (-d[--debug]) (-s[--timeout] ) \n"); printf("Supported commands:\n"); printf(" scan (scan blocks up to the tip, creates header.db file)\n"); printf("\nExamples: \n"); @@ -270,9 +273,10 @@ int main(int argc, char* argv[]) { char* headers_name = 0; dogecoin_bool full_sync = false; dogecoin_bool have_decl_daemon = false; + dogecoin_bool encrypted = false; + dogecoin_bool master_key = false; dogecoin_bool tpm = false; int file_num = NO_FILE; - char* wallet_name = NULL; if (argc <= 1 || strlen(argv[argc - 1]) == 0 || argv[argc - 1][0] == '-') { /* exit if no command was provided */ @@ -282,7 +286,7 @@ int main(int argc, char* argv[]) { data = argv[argc - 1]; /* get arguments */ - while ((opt = getopt_long_only(argc, argv, "i:ctrds:m:n:f:y:a:w:h:bpz:", long_options, &long_index)) != -1) { + while ((opt = getopt_long_only(argc, argv, "i:ctrds:m:n:f:y:a:w:h:bpzkj:", long_options, &long_index)) != -1) { switch (opt) { case 'c': quit_when_synced = false; @@ -319,10 +323,17 @@ int main(int argc, char* argv[]) { break; case 'h': headers_name = optarg; + break; case 'y': - tpm = true; + encrypted = true; file_num = (int)strtol(optarg, (char**)NULL, 10); break; + case 'k': + master_key = true; + break; + case 'j': + tpm = true; + break; case 'w': name = optarg; break; @@ -346,7 +357,7 @@ int main(int argc, char* argv[]) { client->sync_completed = spv_sync_completed; #if WITH_WALLET - dogecoin_wallet* wallet = dogecoin_wallet_init(chain, address, name, mnemonic_in, pass, tpm, file_num); + dogecoin_wallet* wallet = dogecoin_wallet_init(chain, address, name, mnemonic_in, pass, encrypted, tpm, file_num, master_key); print_utxos(wallet); client->sync_transaction = dogecoin_wallet_check_transaction; client->sync_transaction_ctx = wallet; diff --git a/src/cli/such.c b/src/cli/such.c index 74484a574..c76e0d7fb 100644 --- a/src/cli/such.c +++ b/src/cli/such.c @@ -619,7 +619,8 @@ static struct option long_options[] = {"account_int", required_argument, NULL, 'o'}, {"change_level", required_argument, NULL, 'g'}, {"address_index", required_argument, NULL, 'i'}, - {"tpm_file", required_argument, NULL, 'y'}, + {"encrypted_file", required_argument, NULL, 'y'}, + {"use_tpm", no_argument, NULL, 'j'}, {"command", required_argument, NULL, 'c'}, {"silent", no_argument, NULL, 'b'}, {"overwrite", no_argument, NULL, 'w'}, @@ -637,18 +638,19 @@ static void print_usage() { print_version(); printf("Usage: such -c (-m|-derived_path ) (-k|-pubkey ) (-p|-privkey ) \ -(-e|-entropy ) (-n|-mnemonic ) (-a|-pass_phrase ) (-y|-tpm_file ) (-w[--overwrite]) (-b[--silent]) \ -(-t[--testnet]) (-r[--regtest])\n"); +(-e|-entropy ) (-n|-mnemonic ) (-a|-pass_phrase ) (-y|-encrypted_file ) (-w[--overwrite]) (-b[--silent]) \ +(-j[--use_tpm]) (-t[--testnet]) (-r[--regtest])\n"); printf("Available commands:\n"); printf("generate_public_key (requires -p ),\n"); printf("p2pkh (requires -k ),\n"); printf("generate_private_key,\n"); - printf("bip32_extended_master_key (-y and -w (overwrite), both optional),\n"); - printf("generate_mnemonic (-e or -y , -w (overwrite) and -b (silent), all optional),\n"); + printf("bip32_master_key (-y , -j (use_tpm), -w (overwrite) and -b (silent), all optional),\n"); + printf("generate_mnemonic (-e or -y , -j (use_tpm), -w (overwrite) and -b (silent), all optional),\n"); printf("list_encryption_keys_in_tpm,\n"); - printf("decrypt_master_key_with_tpm (-y ),\n"); - printf("decrypt_mnemonic_with_tpm (-y ),\n"); - printf("mnemonic_to_addresses (requires -n or -y , -o , -g , -i and -a , all optional),\n"); + printf("decrypt_master_key (requires -y , -j (use_tpm) optional),\n"); + printf("decrypt_mnemonic (requires -y , -j (use_tpm) optional),\n"); + printf("mnemonic_to_key (requires -n or -y , -j (use_tpm), -o , -g , -i and -a , all optional),\n"); + printf("mnemonic_to_addresses (requires -n or -y , -j (use_tpm), -o , -g , -i and -a , all optional),\n"); printf("print_keys (requires -p ),\n"); printf("derive_child_keys (requires -m -p ),\n"); printf("sign (-x -s