diff --git a/rai/core_test/wallet.cpp b/rai/core_test/wallet.cpp index b2e7e130..b804c5db 100644 --- a/rai/core_test/wallet.cpp +++ b/rai/core_test/wallet.cpp @@ -96,7 +96,7 @@ TEST (wallet, one_item_iteration) rai::raw_key password; wallet.wallet_key (password, transaction); rai::raw_key key; - key.decrypt (rai::wallet_value (i->second).key, password, wallet.salt (transaction).owords[0]); + key.decrypt (rai::wallet_value (i->second).key, password, i->first.uint256 ().owords[0]); ASSERT_EQ (key1.prv, key); } } @@ -124,7 +124,7 @@ TEST (wallet, two_item_iteration) rai::raw_key password; wallet.wallet_key (password, transaction); rai::raw_key key; - key.decrypt (rai::wallet_value (i->second).key, password, wallet.salt (transaction).owords[0]); + key.decrypt (rai::wallet_value (i->second).key, password, i->first.uint256 ().owords[0]); prvs.insert (key.data); } } @@ -658,7 +658,7 @@ TEST (wallet, insert_locked) ASSERT_TRUE (wallet->insert_adhoc (rai::keypair ().prv).is_zero ()); } -TEST (wallet, version_1_2_upgrade) +TEST (wallet, version_1_upgrade) { rai::system system (24000, 1); auto wallet (system.wallet (0)); @@ -683,7 +683,7 @@ TEST (wallet, version_1_2_upgrade) wallet->enter_password ("1"); ASSERT_TRUE (wallet->valid_password ()); - ASSERT_EQ (2, wallet->store.version (rai::transaction (wallet->store.environment, nullptr, false))); + ASSERT_EQ (wallet->store.version_current, wallet->store.version (rai::transaction (wallet->store.environment, nullptr, false))); rai::raw_key prv; ASSERT_FALSE (wallet->store.fetch (rai::transaction (wallet->store.environment, nullptr, false), key.pub, prv)); ASSERT_EQ (key.prv, prv); @@ -702,7 +702,7 @@ TEST (wallet, version_1_2_upgrade) } wallet->enter_password ("1"); ASSERT_TRUE (wallet->valid_password ()); - ASSERT_EQ (2, wallet->store.version (rai::transaction (wallet->store.environment, nullptr, false))); + ASSERT_EQ (wallet->store.version_current, wallet->store.version (rai::transaction (wallet->store.environment, nullptr, false))); rai::raw_key prv2; ASSERT_FALSE (wallet->store.fetch (rai::transaction (wallet->store.environment, nullptr, false), key.pub, prv2)); ASSERT_EQ (key.prv, prv2); @@ -798,7 +798,7 @@ TEST (wallet, insert_deterministic_locked) ASSERT_TRUE (wallet->deterministic_insert ().is_zero ()); } -TEST (wallet, version_2_3_upgrade) +TEST (wallet, version_2_upgrade) { rai::system system (24000, 1); auto wallet (system.wallet (0)); @@ -818,12 +818,53 @@ TEST (wallet, version_2_3_upgrade) wallet->store.attempt_password (transaction, "1"); } rai::transaction transaction (wallet->store.environment, nullptr, false); - ASSERT_EQ (3, wallet->store.version (transaction)); + ASSERT_EQ (wallet->store.version_current, wallet->store.version (transaction)); ASSERT_TRUE (wallet->store.exists (transaction, rai::wallet_store::deterministic_index_special)); ASSERT_TRUE (wallet->store.exists (transaction, rai::wallet_store::seed_special)); ASSERT_FALSE (wallet->deterministic_insert ().is_zero ()); } +TEST (wallet, version_3_upgrade) +{ + rai::system system (24000, 1); + auto wallet (system.wallet (0)); + wallet->store.rekey (rai::transaction (wallet->store.environment, nullptr, true), "1"); + wallet->enter_password ("1"); + ASSERT_TRUE (wallet->valid_password ()); + ASSERT_EQ (wallet->store.version_current, wallet->store.version (rai::transaction (wallet->store.environment, nullptr, false))); + rai::keypair key; + rai::raw_key seed; + rai::uint256_union seed_ciphertext; + rai::random_pool.GenerateBlock (seed.data.bytes.data (), seed.data.bytes.size ()); + { + rai::transaction transaction (wallet->store.environment, nullptr, true); + rai::raw_key password_l; + rai::wallet_value value (wallet->store.entry_get_raw (transaction, rai::wallet_store::wallet_key_special)); + rai::raw_key kdf; + wallet->store.derive_key (kdf, transaction, "1"); + password_l.decrypt (value.key, kdf, wallet->store.salt (transaction).owords[0]); + rai::uint256_union ciphertext; + ciphertext.encrypt (key.prv, password_l, wallet->store.salt (transaction).owords[0]); + wallet->store.entry_put_raw (transaction, key.pub, rai::wallet_value (ciphertext, 0)); + seed_ciphertext.encrypt (seed, password_l, wallet->store.salt (transaction).owords[0]); + wallet->store.entry_put_raw (transaction, rai::wallet_store::seed_special, rai::wallet_value (seed_ciphertext, 0)); + wallet->store.version_put (transaction, 3); + } + wallet->enter_password ("1"); + ASSERT_TRUE (wallet->valid_password ()); + ASSERT_EQ (wallet->store.version_current, wallet->store.version (rai::transaction (wallet->store.environment, nullptr, false))); + rai::raw_key prv; + ASSERT_FALSE (wallet->store.fetch (rai::transaction (wallet->store.environment, nullptr, false), key.pub, prv)); + ASSERT_EQ (key.prv, prv); + { + rai::transaction transaction (wallet->store.environment, nullptr, false); + rai::raw_key seed_compare; + wallet->store.seed (seed_compare, transaction); + ASSERT_EQ (seed, seed_compare); + ASSERT_NE (seed_ciphertext, wallet->store.entry_get_raw (transaction, rai::wallet_store::seed_special).key); + } +} + TEST (wallet, no_work) { rai::system system (24000, 1); diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 7d841de9..ea23f054 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -53,7 +53,8 @@ address (boost::asio::ip::address_v6::loopback ()), port (rai::rpc::rpc_port), enable_control (false), frontier_request_limit (16384), -chain_request_limit (16384) +chain_request_limit (16384), +max_json_depth (20) { } @@ -62,7 +63,8 @@ address (boost::asio::ip::address_v6::loopback ()), port (rai::rpc::rpc_port), enable_control (enable_control_a), frontier_request_limit (16384), -chain_request_limit (16384) +chain_request_limit (16384), +max_json_depth (20) { } @@ -73,6 +75,7 @@ void rai::rpc_config::serialize_json (boost::property_tree::ptree & tree_a) cons tree_a.put ("enable_control", enable_control); tree_a.put ("frontier_request_limit", frontier_request_limit); tree_a.put ("chain_request_limit", chain_request_limit); + tree_a.put ("max_json_depth", max_json_depth); } bool rai::rpc_config::deserialize_json (boost::property_tree::ptree const & tree_a) @@ -93,6 +96,7 @@ bool rai::rpc_config::deserialize_json (boost::property_tree::ptree const & tree enable_control = tree_a.get ("enable_control"); auto frontier_request_limit_l (tree_a.get ("frontier_request_limit")); auto chain_request_limit_l (tree_a.get ("chain_request_limit")); + max_json_depth = tree_a.get ("max_json_depth", max_json_depth); try { port = std::stoul (port_l); @@ -3522,460 +3526,481 @@ void rai::rpc_handler::process_request () { try { - std::stringstream istream (body); - boost::property_tree::read_json (istream, request); - std::string action (request.get ("action")); - if (action == "password_enter") - { - password_enter (); - request.erase ("password"); - reprocess_body (body, request); - } - else if (action == "password_change") - { - password_change (); - request.erase ("password"); - reprocess_body (body, request); - } - else if (action == "wallet_unlock") - { - password_enter (); - request.erase ("password"); - reprocess_body (body, request); - } - if (node.config.logging.log_rpc ()) - { - BOOST_LOG (node.log) << boost::str (boost::format ("%1% ") % request_id) << body; - } - if (action == "account_balance") - { - account_balance (); - } - else if (action == "account_block_count") - { - account_block_count (); - } - else if (action == "account_count") - { - account_count (); - } - else if (action == "account_create") - { - account_create (); - } - else if (action == "account_get") - { - account_get (); - } - else if (action == "account_history") - { - account_history (); - } - else if (action == "account_info") - { - account_info (); - } - else if (action == "account_key") - { - account_key (); - } - else if (action == "account_list") - { - account_list (); - } - else if (action == "account_move") - { - account_move (); - } - else if (action == "account_remove") - { - account_remove (); - } - else if (action == "account_representative") - { - account_representative (); - } - else if (action == "account_representative_set") - { - account_representative_set (); - } - else if (action == "account_weight") - { - account_weight (); - } - else if (action == "accounts_balances") - { - accounts_balances (); - } - else if (action == "accounts_create") - { - accounts_create (); - } - else if (action == "accounts_frontiers") - { - accounts_frontiers (); - } - else if (action == "accounts_pending") - { - accounts_pending (); - } - else if (action == "available_supply") - { - available_supply (); - } - else if (action == "block") - { - block (); - } - else if (action == "block_confirm") - { - block_confirm (); - } - else if (action == "blocks") - { - blocks (); - } - else if (action == "blocks_info") - { - blocks_info (); - } - else if (action == "block_account") - { - block_account (); - } - else if (action == "block_count") - { - block_count (); - } - else if (action == "block_count_type") - { - block_count_type (); - } - else if (action == "block_create") - { - block_create (); - } - else if (action == "block_hash") - { - block_hash (); - } - else if (action == "successors") - { - chain (true); - } - else if (action == "bootstrap") - { - bootstrap (); - } - else if (action == "bootstrap_any") - { - bootstrap_any (); - } - else if (action == "chain") - { - chain (); - } - else if (action == "delegators") - { - delegators (); - } - else if (action == "delegators_count") - { - delegators_count (); - } - else if (action == "deterministic_key") - { - deterministic_key (); - } - else if (action == "confirmation_history") - { - confirmation_history (); - } - else if (action == "frontiers") - { - frontiers (); - } - else if (action == "frontier_count") - { - account_count (); - } - else if (action == "history") - { - request.put ("head", request.get ("hash")); - account_history (); - } - else if (action == "keepalive") - { - keepalive (); - } - else if (action == "key_create") - { - key_create (); - } - else if (action == "key_expand") - { - key_expand (); - } - else if (action == "krai_from_raw") - { - mrai_from_raw (rai::kxrb_ratio); - } - else if (action == "krai_to_raw") - { - mrai_to_raw (rai::kxrb_ratio); - } - else if (action == "ledger") - { - ledger (); - } - else if (action == "mrai_from_raw") - { - mrai_from_raw (); - } - else if (action == "mrai_to_raw") - { - mrai_to_raw (); - } - else if (action == "password_change") - { - // Processed before logging - } - else if (action == "password_enter") - { - // Processed before logging - } - else if (action == "password_valid") - { - password_valid (); - } - else if (action == "payment_begin") - { - payment_begin (); - } - else if (action == "payment_init") - { - payment_init (); - } - else if (action == "payment_end") - { - payment_end (); - } - else if (action == "payment_wait") - { - payment_wait (); - } - else if (action == "peers") - { - peers (); - } - else if (action == "pending") - { - pending (); - } - else if (action == "pending_exists") - { - pending_exists (); - } - else if (action == "process") - { - process (); - } - else if (action == "rai_from_raw") - { - mrai_from_raw (rai::xrb_ratio); - } - else if (action == "rai_to_raw") - { - mrai_to_raw (rai::xrb_ratio); - } - else if (action == "receive") - { - receive (); - } - else if (action == "receive_minimum") - { - receive_minimum (); - } - else if (action == "receive_minimum_set") - { - receive_minimum_set (); - } - else if (action == "representatives") - { - representatives (); - } - else if (action == "representatives_online") - { - representatives_online (); - } - else if (action == "republish") - { - republish (); - } - else if (action == "search_pending") - { - search_pending (); - } - else if (action == "search_pending_all") - { - search_pending_all (); - } - else if (action == "send") - { - send (); - } - else if (action == "stats") - { - stats (); - } - else if (action == "stop") - { - stop (); - } - else if (action == "unchecked") - { - unchecked (); - } - else if (action == "unchecked_clear") - { - unchecked_clear (); - } - else if (action == "unchecked_get") - { - unchecked_get (); - } - else if (action == "unchecked_keys") - { - unchecked_keys (); - } - else if (action == "validate_account_number") - { - validate_account_number (); - } - else if (action == "version") - { - version (); - } - else if (action == "wallet_add") - { - wallet_add (); - } - else if (action == "wallet_add_watch") - { - wallet_add_watch (); - } - // Obsolete - else if (action == "wallet_balance_total") - { - wallet_info (); - } - else if (action == "wallet_balances") - { - wallet_balances (); - } - else if (action == "wallet_change_seed") - { - wallet_change_seed (); - } - else if (action == "wallet_contains") - { - wallet_contains (); - } - else if (action == "wallet_create") - { - wallet_create (); - } - else if (action == "wallet_destroy") - { - wallet_destroy (); - } - else if (action == "wallet_export") - { - wallet_export (); - } - else if (action == "wallet_frontiers") - { - wallet_frontiers (); - } - else if (action == "wallet_info") - { - wallet_info (); - } - else if (action == "wallet_key_valid") - { - wallet_key_valid (); - } - else if (action == "wallet_ledger") - { - wallet_ledger (); - } - else if (action == "wallet_lock") - { - wallet_lock (); - } - else if (action == "wallet_locked") - { - password_valid (true); - } - else if (action == "wallet_pending") - { - wallet_pending (); - } - else if (action == "wallet_representative") - { - wallet_representative (); - } - else if (action == "wallet_representative_set") - { - wallet_representative_set (); - } - else if (action == "wallet_republish") - { - wallet_republish (); - } - else if (action == "wallet_unlock") - { - // Processed before logging - } - else if (action == "wallet_work_get") - { - wallet_work_get (); - } - else if (action == "work_generate") - { - work_generate (); - } - else if (action == "work_cancel") - { - work_cancel (); - } - else if (action == "work_get") - { - work_get (); - } - else if (action == "work_set") - { - work_set (); - } - else if (action == "work_validate") - { - work_validate (); - } - else if (action == "work_peer_add") - { - work_peer_add (); - } - else if (action == "work_peers") - { - work_peers (); - } - else if (action == "work_peers_clear") - { - work_peers_clear (); + auto max_depth_exceeded (false); + auto max_depth_possible (0); + for (auto ch : body) + { + if (ch == '[' || ch == '{') + { + if (max_depth_possible >= rpc.config.max_json_depth) + { + max_depth_exceeded = true; + break; + } + ++max_depth_possible; + } + } + if (max_depth_exceeded) + { + error_response (response, "Max JSON depth exceeded"); } else { - error_response (response, "Unknown command"); + std::stringstream istream (body); + boost::property_tree::read_json (istream, request); + std::string action (request.get ("action")); + if (action == "password_enter") + { + password_enter (); + request.erase ("password"); + reprocess_body (body, request); + } + else if (action == "password_change") + { + password_change (); + request.erase ("password"); + reprocess_body (body, request); + } + else if (action == "wallet_unlock") + { + password_enter (); + request.erase ("password"); + reprocess_body (body, request); + } + if (node.config.logging.log_rpc ()) + { + BOOST_LOG (node.log) << boost::str (boost::format ("%1% ") % request_id) << body; + } + if (action == "account_balance") + { + account_balance (); + } + else if (action == "account_block_count") + { + account_block_count (); + } + else if (action == "account_count") + { + account_count (); + } + else if (action == "account_create") + { + account_create (); + } + else if (action == "account_get") + { + account_get (); + } + else if (action == "account_history") + { + account_history (); + } + else if (action == "account_info") + { + account_info (); + } + else if (action == "account_key") + { + account_key (); + } + else if (action == "account_list") + { + account_list (); + } + else if (action == "account_move") + { + account_move (); + } + else if (action == "account_remove") + { + account_remove (); + } + else if (action == "account_representative") + { + account_representative (); + } + else if (action == "account_representative_set") + { + account_representative_set (); + } + else if (action == "account_weight") + { + account_weight (); + } + else if (action == "accounts_balances") + { + accounts_balances (); + } + else if (action == "accounts_create") + { + accounts_create (); + } + else if (action == "accounts_frontiers") + { + accounts_frontiers (); + } + else if (action == "accounts_pending") + { + accounts_pending (); + } + else if (action == "available_supply") + { + available_supply (); + } + else if (action == "block") + { + block (); + } + else if (action == "block_confirm") + { + block_confirm (); + } + else if (action == "blocks") + { + blocks (); + } + else if (action == "blocks_info") + { + blocks_info (); + } + else if (action == "block_account") + { + block_account (); + } + else if (action == "block_count") + { + block_count (); + } + else if (action == "block_count_type") + { + block_count_type (); + } + else if (action == "block_create") + { + block_create (); + } + else if (action == "block_hash") + { + block_hash (); + } + else if (action == "successors") + { + chain (true); + } + else if (action == "bootstrap") + { + bootstrap (); + } + else if (action == "bootstrap_any") + { + bootstrap_any (); + } + else if (action == "chain") + { + chain (); + } + else if (action == "delegators") + { + delegators (); + } + else if (action == "delegators_count") + { + delegators_count (); + } + else if (action == "deterministic_key") + { + deterministic_key (); + } + else if (action == "confirmation_history") + { + confirmation_history (); + } + else if (action == "frontiers") + { + frontiers (); + } + else if (action == "frontier_count") + { + account_count (); + } + else if (action == "history") + { + request.put ("head", request.get ("hash")); + account_history (); + } + else if (action == "keepalive") + { + keepalive (); + } + else if (action == "key_create") + { + key_create (); + } + else if (action == "key_expand") + { + key_expand (); + } + else if (action == "krai_from_raw") + { + mrai_from_raw (rai::kxrb_ratio); + } + else if (action == "krai_to_raw") + { + mrai_to_raw (rai::kxrb_ratio); + } + else if (action == "ledger") + { + ledger (); + } + else if (action == "mrai_from_raw") + { + mrai_from_raw (); + } + else if (action == "mrai_to_raw") + { + mrai_to_raw (); + } + else if (action == "password_change") + { + // Processed before logging + } + else if (action == "password_enter") + { + // Processed before logging + } + else if (action == "password_valid") + { + password_valid (); + } + else if (action == "payment_begin") + { + payment_begin (); + } + else if (action == "payment_init") + { + payment_init (); + } + else if (action == "payment_end") + { + payment_end (); + } + else if (action == "payment_wait") + { + payment_wait (); + } + else if (action == "peers") + { + peers (); + } + else if (action == "pending") + { + pending (); + } + else if (action == "pending_exists") + { + pending_exists (); + } + else if (action == "process") + { + process (); + } + else if (action == "rai_from_raw") + { + mrai_from_raw (rai::xrb_ratio); + } + else if (action == "rai_to_raw") + { + mrai_to_raw (rai::xrb_ratio); + } + else if (action == "receive") + { + receive (); + } + else if (action == "receive_minimum") + { + receive_minimum (); + } + else if (action == "receive_minimum_set") + { + receive_minimum_set (); + } + else if (action == "representatives") + { + representatives (); + } + else if (action == "representatives_online") + { + representatives_online (); + } + else if (action == "republish") + { + republish (); + } + else if (action == "search_pending") + { + search_pending (); + } + else if (action == "search_pending_all") + { + search_pending_all (); + } + else if (action == "send") + { + send (); + } + else if (action == "stats") + { + stats (); + } + else if (action == "stop") + { + stop (); + } + else if (action == "unchecked") + { + unchecked (); + } + else if (action == "unchecked_clear") + { + unchecked_clear (); + } + else if (action == "unchecked_get") + { + unchecked_get (); + } + else if (action == "unchecked_keys") + { + unchecked_keys (); + } + else if (action == "validate_account_number") + { + validate_account_number (); + } + else if (action == "version") + { + version (); + } + else if (action == "wallet_add") + { + wallet_add (); + } + else if (action == "wallet_add_watch") + { + wallet_add_watch (); + } + // Obsolete + else if (action == "wallet_balance_total") + { + wallet_info (); + } + else if (action == "wallet_balances") + { + wallet_balances (); + } + else if (action == "wallet_change_seed") + { + wallet_change_seed (); + } + else if (action == "wallet_contains") + { + wallet_contains (); + } + else if (action == "wallet_create") + { + wallet_create (); + } + else if (action == "wallet_destroy") + { + wallet_destroy (); + } + else if (action == "wallet_export") + { + wallet_export (); + } + else if (action == "wallet_frontiers") + { + wallet_frontiers (); + } + else if (action == "wallet_info") + { + wallet_info (); + } + else if (action == "wallet_key_valid") + { + wallet_key_valid (); + } + else if (action == "wallet_ledger") + { + wallet_ledger (); + } + else if (action == "wallet_lock") + { + wallet_lock (); + } + else if (action == "wallet_locked") + { + password_valid (true); + } + else if (action == "wallet_pending") + { + wallet_pending (); + } + else if (action == "wallet_representative") + { + wallet_representative (); + } + else if (action == "wallet_representative_set") + { + wallet_representative_set (); + } + else if (action == "wallet_republish") + { + wallet_republish (); + } + else if (action == "wallet_unlock") + { + // Processed before logging + } + else if (action == "wallet_work_get") + { + wallet_work_get (); + } + else if (action == "work_generate") + { + work_generate (); + } + else if (action == "work_cancel") + { + work_cancel (); + } + else if (action == "work_get") + { + work_get (); + } + else if (action == "work_set") + { + work_set (); + } + else if (action == "work_validate") + { + work_validate (); + } + else if (action == "work_peer_add") + { + work_peer_add (); + } + else if (action == "work_peers") + { + work_peers (); + } + else if (action == "work_peers_clear") + { + work_peers_clear (); + } + else + { + error_response (response, "Unknown command"); + } } } catch (std::runtime_error const & err) diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index 49189c78..5b2bfe86 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -48,6 +48,7 @@ public: uint64_t frontier_request_limit; uint64_t chain_request_limit; rpc_secure_config secure; + uint8_t max_json_depth; }; enum class payment_status { diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index 096305fe..a4bc2341 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -40,7 +40,7 @@ void rai::wallet_store::seed (rai::raw_key & prv_a, MDB_txn * transaction_a) rai::wallet_value value (entry_get_raw (transaction_a, rai::wallet_store::seed_special)); rai::raw_key password_l; wallet_key (password_l, transaction_a); - prv_a.decrypt (value.key, password_l, salt (transaction_a).owords[0]); + prv_a.decrypt (value.key, password_l, salt (transaction_a).owords[seed_iv_index]); } void rai::wallet_store::seed_set (MDB_txn * transaction_a, rai::raw_key const & prv_a) @@ -48,7 +48,7 @@ void rai::wallet_store::seed_set (MDB_txn * transaction_a, rai::raw_key const & rai::raw_key password_l; wallet_key (password_l, transaction_a); rai::uint256_union ciphertext; - ciphertext.encrypt (prv_a, password_l, salt (transaction_a).owords[0]); + ciphertext.encrypt (prv_a, password_l, salt (transaction_a).owords[seed_iv_index]); entry_put_raw (transaction_a, rai::wallet_store::seed_special, rai::wallet_value (ciphertext, 0)); deterministic_clear (transaction_a); } @@ -126,7 +126,7 @@ bool rai::wallet_store::valid_password (MDB_txn * transaction_a) rai::raw_key wallet_key_l; wallet_key (wallet_key_l, transaction_a); rai::uint256_union check_l; - check_l.encrypt (zero, wallet_key_l, salt (transaction_a).owords[0]); + check_l.encrypt (zero, wallet_key_l, salt (transaction_a).owords[check_iv_index]); bool ok = check (transaction_a) == check_l; return ok; } @@ -143,13 +143,18 @@ bool rai::wallet_store::attempt_password (MDB_txn * transaction_a, std::string c } if (!result) { - if (version (transaction_a) == version_1) + switch (version (transaction_a)) { - upgrade_v1_v2 (); - } - if (version (transaction_a) == version_2) - { - upgrade_v2_v3 (); + case version_1: + upgrade_v1_v2 (); + case version_2: + upgrade_v2_v3 (); + case version_3: + upgrade_v3_v4 (); + case version_4: + break; + default: + assert (false); } } return result; @@ -245,10 +250,6 @@ rai::mdb_val rai::wallet_value::val () const return rai::mdb_val (sizeof (*this), const_cast (this)); } -unsigned const rai::wallet_store::version_1 (1); -unsigned const rai::wallet_store::version_2 (2); -unsigned const rai::wallet_store::version_3 (3); -unsigned const rai::wallet_store::version_current (version_3); // Wallet version number rai::uint256_union const rai::wallet_store::version_special (0); // Random number used to salt private key encryption @@ -264,6 +265,8 @@ rai::uint256_union const rai::wallet_store::seed_special (5); // Current key index for deterministic keys rai::uint256_union const rai::wallet_store::deterministic_index_special (6); int const rai::wallet_store::special_count (7); +size_t const rai::wallet_store::check_iv_index (0); +size_t const rai::wallet_store::seed_iv_index (1); rai::wallet_store::wallet_store (bool & init_a, rai::kdf & kdf_a, rai::transaction & transaction_a, rai::account representative_a, unsigned fanout_a, std::string const & wallet_a, std::string const & json_a) : password (0, fanout_a), @@ -357,7 +360,7 @@ environment (transaction_a.environment) wallet_key_enc.data = encrypted; wallet_key_mem.value_set (wallet_key_enc); rai::uint256_union check; - check.encrypt (zero, wallet_key, salt_l.owords[0]); + check.encrypt (zero, wallet_key, salt_l.owords[check_iv_index]); entry_put_raw (transaction_a, rai::wallet_store::check_special, rai::wallet_value (check, 0)); entry_put_raw (transaction_a, rai::wallet_store::representative_special, rai::wallet_value (representative_a, 0)); rai::raw_key seed; @@ -413,7 +416,7 @@ rai::public_key rai::wallet_store::insert_adhoc (MDB_txn * transaction_a, rai::r rai::raw_key password_l; wallet_key (password_l, transaction_a); rai::uint256_union ciphertext; - ciphertext.encrypt (prv, password_l, salt (transaction_a).owords[0]); + ciphertext.encrypt (prv, password_l, pub.owords[0].number ()); entry_put_raw (transaction_a, pub, rai::wallet_value (ciphertext, 0)); return pub; } @@ -498,7 +501,7 @@ bool rai::wallet_store::fetch (MDB_txn * transaction_a, rai::public_key const & // Ad-hoc keys rai::raw_key password_l; wallet_key (password_l, transaction_a); - prv.decrypt (value.key, password_l, salt (transaction_a).owords[0]); + prv.decrypt (value.key, password_l, pub.owords[0].number ()); break; } default: @@ -691,6 +694,49 @@ void rai::wallet_store::upgrade_v2_v3 () version_put (transaction, 3); } +void rai::wallet_store::upgrade_v3_v4 () +{ + rai::transaction transaction (environment, nullptr, true); + assert (version (transaction) == 3); + version_put (transaction, 4); + assert (valid_password (transaction)); + rai::raw_key seed; + rai::wallet_value value (entry_get_raw (transaction, rai::wallet_store::seed_special)); + rai::raw_key password_l; + wallet_key (password_l, transaction); + seed.decrypt (value.key, password_l, salt (transaction).owords[0]); + rai::uint256_union ciphertext; + ciphertext.encrypt (seed, password_l, salt (transaction).owords[seed_iv_index]); + entry_put_raw (transaction, rai::wallet_store::seed_special, rai::wallet_value (ciphertext, 0)); + for (auto i (begin (transaction)), n (end ()); i != n; ++i) + { + rai::wallet_value value (i->second); + if (!value.key.is_zero ()) + { + switch (key_type (i->second)) + { + case rai::key_type::adhoc: + { + rai::raw_key key; + if (fetch (transaction, i->first.uint256 (), key)) + { + // Key failed to decrypt despite valid password + key.decrypt (value.key, password_l, salt (transaction).owords[0]); + rai::uint256_union new_key_ciphertext; + new_key_ciphertext.encrypt (key, password_l, i->first.uint256 ().owords[0].number ()); + rai::wallet_value new_value (new_key_ciphertext, value.work); + mdb_cursor_put (i.cursor, i->first, new_value.val (), MDB_CURRENT); + } + } + case rai::key_type::deterministic: + break; + default: + assert (false); + } + } + } +} + void rai::kdf::phs (rai::raw_key & result_a, std::string const & password_a, rai::uint256_union const & salt_a) { std::lock_guard lock (mutex); diff --git a/rai/node/wallet.hpp b/rai/node/wallet.hpp index d2c842a2..ef661a25 100644 --- a/rai/node/wallet.hpp +++ b/rai/node/wallet.hpp @@ -96,12 +96,14 @@ public: void version_put (MDB_txn *, unsigned); void upgrade_v1_v2 (); void upgrade_v2_v3 (); + void upgrade_v3_v4 (); rai::fan password; rai::fan wallet_key_mem; - static unsigned const version_1; - static unsigned const version_2; - static unsigned const version_3; - static unsigned const version_current; + static unsigned const version_1 = 1; + static unsigned const version_2 = 2; + static unsigned const version_3 = 3; + static unsigned const version_4 = 4; + unsigned const version_current = version_4; static rai::uint256_union const version_special; static rai::uint256_union const wallet_key_special; static rai::uint256_union const salt_special; @@ -109,6 +111,8 @@ public: static rai::uint256_union const representative_special; static rai::uint256_union const seed_special; static rai::uint256_union const deterministic_index_special; + static size_t const check_iv_index; + static size_t const seed_iv_index; static int const special_count; static unsigned const kdf_full_work = 64 * 1024; static unsigned const kdf_test_work = 8;