-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
remove cached password from Wallet API #9915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release-v0.18
Are you sure you want to change the base?
remove cached password from Wallet API #9915
Conversation
src/wallet/api/wallet2_api.h
Outdated
| #include <cstdint> | ||
| #include <unordered_set> | ||
|
|
||
| #include "wipeable_string.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand the desire for this change, but the is the first time that something outside of C++ standard libraries is required by the wallet2_api.h file. All alternative implementations must link against libepee for this to work.
I'm not certain this small incremental improvement is worth changing this API because all of the UIs (monero-gui, stack, cake) are likely using constructs in the GUI that aren't wiped. OTOH, I guess this will help make the GUIs more compliant in this regard? I don't know, I don't see it.
I'll do a larger view later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternative approach: using a char * instead. I think a pointer would give more flexibility to the caller to handle wiping on their end without requiring linking against something outside of C++ standard libs, and then internally the API lib could instantiate a wipeable_string from the char *.
GUI's that want to make a stronger attempt at keeping sensitive data out of memory could even use wipeable_string themselves (linking against epee themselves if they want), then call <their string>.data() and pass that in to the API (though yes, this doesn't address UI elems handling memory securely).
because all of the UIs (monero-gui, stack, cake) are likely using constructs in the GUI that aren't wiped
@SNeedlewoods has done some looking into on qt's memory handling. I think would be worth sharing what you found here sneedle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also for a mobile app, I think they can do something like this: combine the password input to the UI with a distinct constant randomly generated salt stored in the user's keystore, so even if the UI password alone is compromised, there is an extra layer of defense because the wallet password is a combo of the user-input password and easier-to-securely-handle salt. I thought I recalled that Monerujo did something like this, but the link to their paper on their password is dead and don't want to dig through the code at the moment (can get back to this).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the input.
I removed the include for wipeable_string in wallet2_api.h and did some testing, it seems monero-project/monero-gui#4437 works the same without it.
Will do more testing tomorrow and push then if nothing is messed up.
Edit:
Sorry j-berman, I missed your comment somehow, I'll try to properly respond later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, the GUI stores the text for LineEdit components as QString. To manually wipe those, I added wipeQStr() (src), which can be called from .qml files.
Did some more testing with GUI wallet with a memscanner first and then with a debugger, I could not find leaked passwords in memory with the change from epee::wipeable_string to std::string in the Wallet API.
Btw. I decided to use std::string & instead of char * to be more aligned with other methods in the API. If you still think a char * would be better I'll change it.
I'm not sure my tests are enough to confirm this behaves the same on other systems (I'm on an ubuntu like OS), so I thought about doing some extra wiping.
We could
A) do it in the Wallet API implementation,
void WalletImpl::someFunc(std::string &password)
{
m_wallet->some_func(epee::wipeable_string(password));
memwipe(&password[0], password.size());
}
but I think this isn't ideal, if the caller wants to use the password for something else. Though you could use a bool do_wipe argument as done here. I've done it that way in the GUI, because most of the time we want to wipe the password after verifying it as it is not needed anymore, but there is one case (src) where we still need the password after verifying.
Or
B) just leave it and let the clients have to do it in a similar way, e.g. the GUI
void Wallet::someFunc(const QString &password)
{
std::string password_string = password.toStdString();
m_walletImpl->someFunc(password_string);
memwipe(&password_string[0], password_string.size());
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reason I proposed using char * instead of std::string here is because it enables the caller to have a strong guarantee the memory is handled safely (by e.g. using a wipeable string themselves and then calling data()). Once the password is placed in std::string then 1) it can be placed in swap, and 2) afaik the standard lib doesn't offer any guarantees on memory safety, so it's possible it can copy the password in memory.
Some related stack overflow posts that give pause on using std::string out of the box:
https://stackoverflow.com/questions/5698002/how-does-one-securely-clear-stdstring
https://stackoverflow.com/questions/3785582/how-to-write-a-password-safe-class
998c50b to
214bbf5
Compare
214bbf5 to
00ac78b
Compare
00ac78b to
fe8eac2
Compare
Edit: Update description.
This PR is based on #9464, which is based on the
release-v0.18branch so it can be used by monero-gui. Besides removingm_passwordfromWalletImplthe following changes were made:add method
bool WalletImpl::open(const std::string &path, const epee::wipeable_string &password)AFAIU the old method
WalletImpl::open(const std::string &path, const std::string &password)is not defined insrc/wallet/api/wallet2_api.h, because it's only used byWalletManagerImpl::openWallet()(src), which is supposed to be used by Wallet API clients.bool WalletImpl::store(const std::string &path, const optional<const char *> &password /* = optional<const char *>() */)old_passwordargument to set a new password, I took this opportuninty to also changestd::stringtochar *as suggested here remove cached password from Wallet API #9915 (comment)bool WalletImpl::setPassword(const char *old_password, const char *new_password)const std::string& WalletImpl::getPassword()string WalletImpl::makeMultisig(const vector<string>& info, const uint32_t threshold, const char *password)std::string WalletImpl::exchangeMultisigKeys(const std::vector<std::string> &info, const char *password, const bool force_update_use_with_caution /*= false*/)WalletImplmethod.bool WalletImpl::verifyPassword(const char *password, std::uint64_t kdf_rounds /* = 1 */)