Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTCachedKey.hpp File Reference
#include <string>
#include <memory>
#include <map>
#include <mutex>
#include <thread>
Include dependency graph for OTCachedKey.hpp:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

class  opentxs::OTCachedKey
 

Namespaces

 opentxs
 

Macros

#define OT_MASTER_KEY_TIMEOUT   300
 

Typedefs

typedef std::map< std::string,
std::shared_ptr< OTCachedKey > > 
opentxs::mapOfCachedKeys
 

Macro Definition Documentation

#define OT_MASTER_KEY_TIMEOUT   300

OTCachedKey This class handles the functionality of caching the master key for X seconds as an OTPassword, and then deleting it. It also caches the encrypted version in an OTSymmetricKey, which can be unlocked to an OTPassword again for X more seconds (by entering the passphrase...) How does OTCachedKey work, in a nutshell?

– It's a singleton. There's only one "master key" for the application and it's available globally like this: OTCachedKey::It(). For example: OTCachedKey::It()->IsGenerated()

– m_pSymmetricKey contains a symmetric key in ENCRYPTED form, which loads up from the wallet, and which is always kept in RAM (as on the hard drive) ONLY in encrypted form.

– m_pMasterPassword is the DECRYPTED version of m_pSymmetricKey. When a user enters his password, a key derivation hash is used to transform it, and the result is used to get an unlocked copy of m_pSymmetricKey, putting the cleartext version into m_pMasterPassword.

– Why store a decrypted version in memory? So we can set a timer using another thread, and thereby return X seconds later, and destroy that decrypted version. In the meantime, until it is destroyed, it will be used automatically by OT, every time a password is needed until those X seconds are over.

– That's still not good enough: the decrypted version should still be stored in protected memory, using some standard API such as gpg-agent or Windows VirtualProtect. And whatever is stored there, should ALSO be encrypted to a session key which is re-generated for every run of the application. Furthermore, the decrypted version being stored isn't the user's actual passphrase, nor is it the key derived from it via some password hash algorithm, but instead is a random number that was generated in order to be used as the master key.

– This means that the actual password the user enters, is never stored anywhere. Neither is the key derived from that password, since both can instantly be erased after using them to unlock the master key. Furthermore the master key is encrypted to a temporary session key, which is different for every run of the application, so it is never stored cleartext in memory, either, nor is it thus available to anyone with backdoors into protected memory.

– Not only does the session key change after each run of the application, but it is possible to replace the master key without forcing a change of the password itself. Likewise it is also possible to change the password, without changing the underlying key that it opens. Adding the session key will further ensure that neither password nor master key ever appears in RAM (for very int64_t) nor on the harddrive in cleartext form.

– Adding the use of a standard protected memory API such as gpg-agent means there is no risk of swapping or core dumps revealing vital information from within OT itself. Nevertheless, the OTPassword class takes pains to prevent core dumps and swapping, and also uses tricks to zero sensitive memory after it has been used.

– The protected memory API has no access to what it is storing, due to the session key. I will make this configurable so that users can choose their own authentication mechanisms.

– Since a thread is used to implement a timer for wiping the master key after X seconds, a mutex appears in the class below, which must be locked by any functions in order to use the master key. (They do this behind the scenes automatically.)

– An OT operation will behave in this way: The user tries to withdraw cash, and thus must sign a withdrawal request. An OpenSSL call is used to sign the request, and the OT password callback is passed to the OpenSSL call, which OpenSSL will call in the event that it needs a password. When that happens, OT will, instead of popping up the password dialog to the user, will notice that the master key password has been decrypted already and is within the X seconds window, so it will use that password to unlock the master key, which it passes to OpenSSL instead of asking the user to enter his passphrase. If the timer had already been expired by that time, then the master key password would have been destroyed already, meaning OT has no way to open the master key, so OT would then pop up the passphrase dialog and ask the user to enter his passphrase, use that to derive a key, and use that to unlock the master key password, and then use that to unlock the master key and pass that back to OpenSSL via the callback function.

– OT might do several operations within a SINGLE USE CASE. For example, for a cash withdrawal, OT might sign the transaction item, sign the balance agreement item, sign the main transaction containing those items, AND sign the message containing that transaction. Perhaps OT has to use that private key 4 or 5 times in a row, all within a fraction of a second. Should the user therefore have to enter his passphrase 4 or 5 times, for a cash withdrawal? Isn't once enough? But it's not that simple, because each operation opens the master key just int64_t enough for OpenSSL to perform the requested operation, and then destroys it again immediately after the operation is completed. (Even when the timeout is active, what's being stored isn't the master key itself, but the master key password used to open it JUST LONG ENOUGH to use it, and then destroy it again.) The critical point to understand is that, especially with the introduction of the session key, EVEN though a timeout is happening, the master key itself is STILL destroyed after each operation, even 4 or 5 times in a row really fast, for some single use case transaction to occur.

– If you set your timeout to -1, then the master key passphrase will never expire. But if your timeout is set to 0, then you will have to type your password 4 or 5 times for a single transaction. Get it? If you set it to 300 (seconds) then you will only have to type your passphrase once and then your application will work for 5 minutes without having to type it again, not even once more, until that 5 minutes are up, and then you will definitely have to type that password again before doing another operation.

– This is an area where much can be gained through the study of code obfuscation, randomizing memory locations, zeroing memory after use, using protected memory APIs, using session keys, using outsourced authentication systems such as ssh-agent instead of handling it internally, stack smashing techniques such as canaries, etc etc. This is always a moving target.

Definition at line 307 of file OTCachedKey.hpp.