Skip to content

Commit

Permalink
wallet: added prompt to dogecoin_wallet_load
Browse files Browse the repository at this point in the history
headersdb_file: added prompt to dogecoin_headers_db_load
headersdb_file: removed check from dogecoin_headers_db_free
spv: moved fcntl to dogecoin_spv_client_discover_peers
spvnode: added handle_sigint to reset stdin to blocking
spvnode: added dogecoin_spv_client_free and dogecoin_ecc_stop on failure
wallet: added prompt to dogecoin_wallet_init
wallet: added encryption of random seed with software
wallet: added dogecoin_wallet_free to dogecoin_wallet_init on failures
such: added seed_to_master_key command
doc: added seed_to_master_key to tools.md
  • Loading branch information
edtubbs committed Jan 19, 2024
1 parent 2341064 commit a040b7d
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 15 deletions.
16 changes: 12 additions & 4 deletions doc/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The `such` tool can be used by simply running the command `./such` in the top le
- list_encryption_keys_in_tpm
- decrypt_master_key
- decrypt_mnemonic
- seed_to_master_key
- mnemonic_to_key
- mnemonic_to_addresses
- print_keys
Expand Down Expand Up @@ -47,10 +48,10 @@ Most of these commands require a flag following them to denote things like exist
| -o, --account_int | account_int | yes | mnemonic_to_key or mnemonic_to_addresses -n <seed_phrase> -o <account_int> |
| -g, --change_level | change_level | yes | mnemonic_to_key or mnemonic_to_addresses -n <seed_phrase> -g <change_level> |
| -i, --address_index | address_index | yes | mnemonic_to_key or mnemonic_to_addresses -n <seed_phrase> -i <address_index> |
| -y, --encrypted_file | file_num | yes | generate_mnemonic, bip32_extended_master_key, decrypt_master_key, decrypt_mnemonic, mnemonic_to_key or mnemonic_to_addresses -y <file_num>
| -y, --encrypted_file | file_num | yes | generate_mnemonic, bip32_extended_master_key, decrypt_master_key, decrypt_mnemonic, seed_to_master_key, mnemonic_to_key or mnemonic_to_addresses -y <file_num>
| -w, --overwrite | overwrite | no | generate_mnemonic or bip32_extended_master_key -w |
| -b, --silent | silent | no | generate_mnemonic or bip32_extended_master_key -b |
| -j, --use_tpm | use_tpm | no | generate_mnemonic, bip32_extended_master_key, decrypt_master_key, decrypt_mnemonic, mnemonic_to_key or mnemonic_to_addresses -j |
| -j, --use_tpm | use_tpm | no | generate_mnemonic, bip32_extended_master_key, decrypt_master_key, decrypt_mnemonic, seed_to_master_key, mnemonic_to_key or mnemonic_to_addresses -j |
| -t, --testnet | designate_testnet | no | generate_private_key -t |
| -s | script_hex | yes | comp2der -s <compact_signature> |
| -x | transaction_hex | yes | sign -x <transaction_hex> -s <pubkey_script> -i <index_of_utxo_to_sign> -h <sig_hash_type> |
Expand All @@ -71,6 +72,7 @@ Below is a list of all the commands and the flags that they require. As a remind
| list_encryption_keys_in_tpm | None | None | List the encryption keys in 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. |
| seed_to_master_key | -y | -j, -t | Generates an extended master private key from a seed for either mainnet or testnet. |
| 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.
Expand Down Expand Up @@ -172,9 +174,9 @@ Below are some examples on how to use the `such` tool in practice.
./such -c verifymessage -x bleh -s ICrbftD0KamyaB68IoXbeke3w4CpcIvv+Q4pncBNpMk8fF5+xsR9H9gqmfM0JrjlfzZZA3E8AJ0Nug1KWeoVw3g= -k D8mQ2sKYpLbFCQLhGeHCPBmkLJRi6kRoSg
Message is verified!

## Encrypted Mnemonics and Key Backups
## Encrypted Mnemonics, Key and Seed Backups

The `such` tool provides functionality to securely manage your encrypted mnemonics and key backups. With the ability to generate mnemonics and encrypt them for safe storage, and to decrypt them when needed, managing your cryptographic assets is made easier. To use encrypted files with `spvnode`, you must first use the `such` tool to generate and encrypt your mnemonic or master key. You can then use the `spvnode` tool to import the encrypted file and use it to connect to the network.
The `such` tool provides functionality to securely manage your encrypted mnemonics, key and seed backups. With the ability to generate mnemonics and encrypt them for safe storage, and to decrypt them when needed, managing your cryptographic assets is made easier. To use encrypted files with `spvnode`, you must first use the `such` tool to generate and encrypt your mnemonic or master key. You can then use the `spvnode` tool to import the encrypted file and use it to connect to the network.

### Generating and Encrypting Mnemonics

Expand Down Expand Up @@ -218,6 +220,12 @@ And to decrypt it back when required:

Always ensure to replace `<file_num>` with the actual number of the encrypted file.

### Handling Seed Backups

You can also decrypt your seed backups using the `seed_to_master_key` command. This command will decrypt the seed and generate a master key from it. If the seed was encrypted using TPM (Trusted Platform Module), you can use the `-j` flag as shown:

./such -c seed_to_master_key -y <file_num> -j

### Overwriting Encrypted Files

If you want to overwrite an existing encrypted file, you can use the `-w` flag as shown:
Expand Down
14 changes: 14 additions & 0 deletions src/cli/spvnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#endif

#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -273,6 +274,16 @@ void spv_sync_completed(dogecoin_spv_client* client) {
}
}

// Signal handler for SIGINT
void handle_sigint() {
// Reset standard input back to blocking mode
#ifndef _WIN32
int stdin_flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, stdin_flags & ~O_NONBLOCK);
#endif
exit(0);
}

int main(int argc, char* argv[]) {
int ret = 0;
int long_index = 0;
Expand Down Expand Up @@ -372,6 +383,7 @@ int main(int argc, char* argv[]) {
dogecoin_spv_client* client = dogecoin_spv_client_new(chain, debug, (dbfile && (dbfile[0] == '0' || (strlen(dbfile) > 1 && dbfile[0] == 'n' && dbfile[0] == 'o'))) ? true : false, use_checkpoint, full_sync);
client->header_message_processed = spv_header_message_processed;
client->sync_completed = spv_sync_completed;
signal(SIGINT, handle_sigint);

#if WITH_WALLET
dogecoin_wallet* wallet = dogecoin_wallet_init(chain, address, name, mnemonic_in, pass, encrypted, tpm, file_num, master_key);
Expand All @@ -382,6 +394,8 @@ int main(int argc, char* argv[]) {
dogecoin_mem_zero (pass, strlen(pass));
dogecoin_free(pass);
}
dogecoin_spv_client_free(client);
dogecoin_ecc_stop();
return EXIT_FAILURE;
}
// clear and free the passphrase
Expand Down
46 changes: 46 additions & 0 deletions src/cli/such.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ static void print_usage()
printf("list_encryption_keys_in_tpm,\n");
printf("decrypt_master_key (requires -y <file_num>, -j (use_tpm) optional),\n");
printf("decrypt_mnemonic (requires -y <file_num>, -j (use_tpm) optional),\n");
printf("seed_to_master_key (-y <file_num>, -j (use_tpm) optional),\n");
printf("mnemonic_to_key (requires -n <seed_phrase> or -y <file_num>, -j (use_tpm), -o <account_int>, -g <change_level>, -i <address_index> and -a, all optional),\n");
printf("mnemonic_to_addresses (requires -n <seed_phrase> or -y <file_num>, -j (use_tpm), -o <account_int>, -g <change_level>, -i <address_index> and -a, all optional),\n");
printf("print_keys (requires -p <private key hex>),\n");
Expand Down Expand Up @@ -688,6 +689,7 @@ int main(int argc, char* argv[])
char* pass = 0;
char* entropy = 0;
MNEMONIC mnemonic = {0};
SEED seed = {0};
dogecoin_bool tpm = false;
dogecoin_bool encrypted = false;
dogecoin_bool overwrite = false;
Expand Down Expand Up @@ -1292,6 +1294,50 @@ int main(int argc, char* argv[])
return showError("decrypt_mnemonic (requires -y <file_num>, -j (use_tpm) optional\n");
}
}
else if (strcmp(cmd, "seed_to_master_key") == 0) { /* Creating a bip32 master key from a seed. */

/* if tpm is enabled, get seed from tpm */
if (encrypted) {
printf("Decrypt seed for master key? Y/N\n");

char buffer[MAX_LEN];
/* get user input */
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
if (buffer[0] != 'Y' && buffer[0] != 'y') {

/* if not confirmed, abort */
printf("aborted\n");
dogecoin_ecc_stop();
return 1;
}
}

if (tpm) {
/* get seed from tpm */
if (!dogecoin_decrypt_seed_with_tpm (seed, file_num)) {
printf("seed_to_master_key (requires -y <file_num>, -j (use_tpm) optional),\n");
return showError("failed to decrypt seed with tpm\n");
}
}

else {
/* get seed from software */
if (dogecoin_decrypt_seed_with_sw (seed, file_num, NULL) == false) {
printf("seed_to_master_key (requires -y <file_num>, -j (use_tpm) optional),\n");
return showError("failed to decrypt seed with software\n");
}
}
}

/* print master key from seed */
dogecoin_hdnode node;
char masterkey[HDKEYLEN];
dogecoin_hdnode_from_seed(seed, sizeof(seed), &node);
dogecoin_hdnode_serialize_private(&node, chain, masterkey, sizeof(masterkey));
printf("bip32 extended master key: %s\n", masterkey);
dogecoin_mem_zero(masterkey, strlen(masterkey));
dogecoin_mem_zero(seed, sizeof(seed));
}
else if (strcmp(cmd, "mnemonic_to_key") == 0) { /* Creating a bip32 master key from a mnemonic. */

/* if tpm is enabled, get mnemonic from tpm */
Expand Down
30 changes: 26 additions & 4 deletions src/headersdb_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ void dogecoin_headers_db_free(dogecoin_headers_db* db) {
dogecoin_free(scan_tip);
scan_tip = prev;
}
// If scan_tip is chainbottom, free it
if (scan_tip == db->chainbottom && scan_tip != &db->genesis) {
// If scan_tip is not the genesis block, free it
if (scan_tip != &db->genesis) {
dogecoin_free(scan_tip);
}
}
Expand Down Expand Up @@ -169,8 +169,30 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file

struct stat buffer;
dogecoin_bool create = true;
if (stat(file_path_local, &buffer) == 0)
create = false;
if (stat(file_path_local, &buffer) == 0) {
printf("\nLoad %s? ", file_path_local);
char response[MAX_LEN];
if (!fgets(response, MAX_LEN, stdin)) {
printf("Error reading input.\n");
return false;
}
if (response[0] == 'o' || response[0] == 'O') {
printf("Are you sure? (y/n): \n");
char confirm[MAX_LEN];
if (!fgets(confirm, MAX_LEN, stdin)) {
printf("Error reading input.\n");
return false;
}
if (confirm[0] == 'y' || confirm[0] == 'Y') {
remove(file_path_local); // remove the existing file
create = true;
} else {
create = false;
}
} else {
create = false;
}
}

db->headers_tree_file = fopen(file_path_local, create ? "a+b" : "r+b");
cstr_free(path_ret, true);
Expand Down
12 changes: 6 additions & 6 deletions src/spv.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ dogecoin_spv_client* dogecoin_spv_client_new(const dogecoin_chainparams *params,
*/
void dogecoin_spv_client_discover_peers(dogecoin_spv_client* client, const char *ips)
{
#ifndef _WIN32
// set stdin to non-blocking for quit command
int stdin_flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK);
#endif

dogecoin_node_group_add_peers_by_ip_or_seed(client->nodegroup, ips);
}

Expand Down Expand Up @@ -197,12 +203,6 @@ dogecoin_bool dogecoin_spv_client_load(dogecoin_spv_client *client, const char *
if (!client->headers_db)
return false;

#ifndef _WIN32
// set stdin to non-blocking for quit command
int stdin_flags = fcntl(STDIN_FILENO, F_GETFL);
fcntl(STDIN_FILENO, F_SETFL, stdin_flags | O_NONBLOCK);
#endif

return client->headers_db->load(client->headers_db_ctx, file_path);

}
Expand Down
61 changes: 60 additions & 1 deletion src/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
dogecoin_free(walletfile);
if (!res) {
showError("Loading wallet failed\n");
dogecoin_wallet_free(wallet);
return NULL;
}
if (created) {
Expand All @@ -365,6 +366,7 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
// generate seed from mnemonic
if (dogecoin_seed_from_mnemonic(mnemonic_in, pass, seed) == -1) {
showError("Invalid mnemonic\n");
dogecoin_wallet_free(wallet);
return NULL;
}
} else if (encrypted && !master_key) {
Expand All @@ -384,13 +386,15 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
if (!tpmSuccess) {
if (!dogecoin_decrypt_mnemonic_with_sw(mnemonic, file_num, NULL)) {
showError("Decrypting mnemonic from software failed\n");
dogecoin_wallet_free(wallet);
return NULL;
}
}

// generate seed from mnemonic
if (dogecoin_seed_from_mnemonic(mnemonic, pass, seed) == -1) {
showError("Invalid mnemonic\n");
dogecoin_wallet_free(wallet);
return NULL;
}
} else if (encrypted && master_key) {
Expand All @@ -409,6 +413,7 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
if (!tpmSuccess) {
if (!dogecoin_decrypt_hdnode_with_sw(&node, file_num, NULL)) {
showError("Decrypting master key from software failed\n");
dogecoin_wallet_free(wallet);
return NULL;
}
}
Expand All @@ -417,8 +422,33 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
res = dogecoin_random_bytes(seed, sizeof(seed), true);
if (!res) {
showError("Generating random bytes failed\n");
dogecoin_wallet_free(wallet);
return NULL;
}
printf("Store seed in encrypted file? (Y/n): ");

char buffer[MAX_LEN];
int file_id = 0; // Variable to store file ID, defaulting to 0

// read user input
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
if (buffer[0] == 'Y' || buffer[0] == 'y') {
printf("Enter file ID (0-999): ");
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
file_id = atoi(buffer); // Update file_id with user input
}

printf("Overwrite file if found? (Y/n): ");
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
bool overwrite = (buffer[0] == 'Y' || buffer[0] == 'y');
// encrypt seed for storage with software
if (dogecoin_encrypt_seed_with_sw(seed, sizeof(seed), file_id, overwrite, NULL) == false) {
dogecoin_wallet_free(wallet);
return NULL;
}
}
}
}
}
if (!master_key) {
// generate hdnode from mnemonic or random seed
Expand All @@ -429,6 +459,7 @@ dogecoin_wallet* dogecoin_wallet_init(const dogecoin_chainparams* chain, const c
// ensure we have a key/address
if (wallet->masterkey == NULL && address == NULL) {
showError("No master key or address in wallet.\n");
dogecoin_wallet_free(wallet);
exit(EXIT_FAILURE);
}
}
Expand Down Expand Up @@ -833,7 +864,35 @@ dogecoin_bool dogecoin_wallet_load(dogecoin_wallet* wallet, const char* file_pat

struct stat buffer;
*created = true;
if (stat(file_path, &buffer) == 0) *created = false;

if (stat(file_path, &buffer) == 0) {
if (!strstr(file_path, "dummy")) { // ignore dummy wallet
printf("Load %s? (Enter) or (o)verwrite:\n", file_path);
char response[MAX_LEN];
if (!fgets(response, MAX_LEN, stdin)) {
printf("Error reading input.\n");
return false;
}
if (response[0] == 'o' || response[0] == 'O') {
printf("Are you sure? (y/n): \n");
char confirm[MAX_LEN];
if (!fgets(confirm, MAX_LEN, stdin)) {
printf("Error reading input.\n");
return false;
}
if (confirm[0] == 'y' || confirm[0] == 'Y') {
remove(file_path); // remove the existing file
*created = true;
} else {
*created = false;
}
} else {
*created = false;
}
} else {
*created = false;
}
}

wallet->dbfile = fopen(file_path, *created ? "a+b" : "r+b");

Expand Down

0 comments on commit a040b7d

Please sign in to comment.