Skip to content

Commit

Permalink
Restore Encrypt/Decrypt by KeyID functionality to OTWallet
Browse files Browse the repository at this point in the history
  • Loading branch information
yamamushi committed Sep 18, 2014
1 parent 601524a commit 9dcc3f4
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 24 deletions.
77 changes: 53 additions & 24 deletions include/opentxs/client/OTWallet.hpp
Expand Up @@ -170,6 +170,9 @@ class OTWallet
EXPORT OTWallet();
~OTWallet();

EXPORT bool IsNymOnCachedKey(const OTIdentifier& needle) const; // needle
// and
// haystack.
EXPORT bool ConvertNymToCachedKey(OTPseudonym& theNym);

EXPORT OTPseudonym* GetOrLoadNym(const OTIdentifier& NYM_ID,
Expand All @@ -195,6 +198,8 @@ class OTWallet
const OTIdentifier& ACCT_ID,
const OTIdentifier& SERVER_ID,
const char* szFuncName = nullptr);
// Used by high-level wrapper.

EXPORT int32_t GetNymCount();
EXPORT int32_t GetServerCount();
EXPORT int32_t GetAssetTypeCount();
Expand Down Expand Up @@ -227,64 +232,87 @@ class OTWallet
EXPORT OTAssetContract* GetAssetContract(const OTIdentifier& theContractID);
EXPORT OTAssetContract* GetAssetContractPartialMatch(
std::string PARTIAL_ID); // wallet name for asset also accepted.

bool VerifyAssetAccount(const OTPseudonym& theNym, OTAccount& theAcct,
const OTIdentifier& SERVER_ID,
const OTString& strAcctID,
const char* szFuncName = nullptr);
EXPORT OTAccount* GetAccount(const OTIdentifier& theAccountID);
EXPORT OTAccount* GetAccountPartialMatch(
std::string PARTIAL_ID); // wallet name for account also accepted.
EXPORT OTAccount* GetIssuerAccount(const OTIdentifier& theAssetTypeID);

// While waiting on server response to a withdrawal, we keep the private
// coin data here so we can unblind the response.
// coin
// data here so we can unblind the response.
// This information is so important (as important as the digital cash token
// itself, until the unblinding is done) that we need to save the file right
// away.
EXPORT void AddPendingWithdrawal(const Purse& thePurse);

void RemovePendingWithdrawal();
inline Purse* GetPendingWithdrawal() const
{
return m_pWithdrawalPurse;
}

EXPORT bool LoadWallet(const char* szFilename = nullptr);
EXPORT bool SaveWallet(const char* szFilename = nullptr);
bool SaveContract(OTString& strContract); // For saving the wallet to a
// string.

EXPORT bool SignContractWithFirstNymOnList(OTContract& theContract);

EXPORT bool SignContractWithFirstNymOnList(
OTContract& theContract); // todo : follow-up on this and see what it's
// about.
// When the wallet's master passphrase changes, the extra symmetric keys
// need to be updated to reflect that.
EXPORT bool ChangePassphrasesOnExtraKeys(const OTPassword& oldPassphrase,
const OTPassword& newPassphrase);

// These allow the client application to encrypt its own sensitive data.
// For example, let's say the client application is storing your Bitmessage
// username and password in its database. It can't store those in the clear,
// so it encrypts the DB's sensitive data using Encrypt_ByKeyID("sql_db")
// and accesses the data using Decrypt_ByKeyID("sql_db").
// The string acts as a key to look up a symmetric key which is normally
// stored in encrypted form, using the wallet's master key. Whenever the
// wallet's master key is available (until it times out) the client app will
// thus be able to use these symmetric keys without having to ask the user
// to type a passphrase.
// (We do this for Nyms already. These methods basically give us the same
// functionality for symmetric keys as we already had for the wallet's
// Nyms.)
//
EXPORT bool Encrypt_ByKeyID(const std::string& key_id,
const OTString& strPlaintext,
OTString& strOutput,
const OTString* pstrDisplay = nullptr,
bool bBookends = true);

EXPORT bool Decrypt_ByKeyID(const std::string& key_id,
const OTString& strCiphertext,
OTString& strOutput,
const OTString* pstrDisplay = nullptr);
EXPORT std::shared_ptr<OTSymmetricKey> getOrCreateExtraKey(
const std::string& str_KeyID,
const std::string* pReason = nullptr); // Use this one.
EXPORT std::shared_ptr<OTSymmetricKey> getExtraKey(
const std::string& str_id); // Low level.
EXPORT bool addExtraKey(const std::string& str_id,
std::shared_ptr<OTSymmetricKey> pKey); // Low level.
// These functions are low-level. They don't check for dependent data before
// deleting, and they don't save the wallet after they do.
// deleting,
// and they don't save the wallet after they do.
//
// (You have to handle that at a higher level.)

EXPORT bool RemoveAssetContract(const OTIdentifier& theTargetID);
EXPORT bool RemoveServerContract(const OTIdentifier& theTargetID);

// higher level version of these two will require a server message,
// in addition to removing from wallet. (To delete them on server side.)
//
EXPORT bool RemoveAccount(const OTIdentifier& theTargetID);
EXPORT bool RemoveNym(const OTIdentifier& theTargetID);

private:
void Release();

bool IsNymOnCachedKey(const OTIdentifier& needle) const; // needle
// and
// haystack.
bool addExtraKey(const std::string& str_id,
std::shared_ptr<OTSymmetricKey> pKey);

std::shared_ptr<OTSymmetricKey> getExtraKey(const std::string& str_id);

bool VerifyAssetAccount(const OTPseudonym& theNym, OTAccount& theAcct,
const OTIdentifier& SERVER_ID,
const OTString& strAcctID,
const char* szFuncName = nullptr);

bool SaveContract(OTString& strContract);

private:
mapOfNyms m_mapNyms;
mapOfContracts m_mapContracts;
Expand Down Expand Up @@ -330,6 +358,7 @@ class OTWallet
// store private coin data here for unblinding
Purse* m_pWithdrawalPurse;

public:
OTString m_strFilename;
OTString m_strDataFolder;
};
Expand Down
117 changes: 117 additions & 0 deletions src/client/OTWallet.cpp
Expand Up @@ -241,6 +241,13 @@ void OTWallet::AddPendingWithdrawal(const Purse& thePurse)
// the user will be unable to unblind his tokens and make them spendable.
// So this data MUST be SAVED until the successful withdrawal is verified!

void OTWallet::RemovePendingWithdrawal()
{
if (m_pWithdrawalPurse) delete m_pWithdrawalPurse;

m_pWithdrawalPurse = nullptr;
}

bool OTWallet::SignContractWithFirstNymOnList(OTContract& theContract)
{
if (GetNymCount() > 0) {
Expand Down Expand Up @@ -1349,6 +1356,68 @@ bool OTWallet::SaveContract(OTString& strContract)
return true;
}

// Let's say you have client-app data that you want to keep in encrypted form.
// Well, use this function to create/retrieve a symmetric key based on an ID.
// For example, "mc_sql_lite" might be the name of the symmetric key that I use
// to encrypt sensitive contents in the sql*lite DB.
// This function will find or create the key and return it to you. The key is
// encrypted to the master key in the wallet, so you never actually have to type
// a password to use it, except when the master key itself has expired.
//
std::shared_ptr<OTSymmetricKey> OTWallet::getOrCreateExtraKey(
const std::string& str_KeyID, const std::string* pReason)
{
// const std::string str_KeyID("mc_sql_lite");

// Get the appropriate symmetric key from the wallet.
// (Which we will decrypt using pMaster.)
// Once it's decrypted, we'll use this key for encrypting/decrypting
// the sql*lite DB data on the client side.
//
std::shared_ptr<OTSymmetricKey> pExtraKey = getExtraKey(str_KeyID);

// (If it doesn't exist, let's just create it here.)
//
if (!pExtraKey) {
// The extra keys, like the Nyms, are all encrypted to the master key
// for the wallet.
// Thus, to create a new extra symmetrical key, we need to get the
// master key from OTCachedKey...
//
std::shared_ptr<OTCachedKey> pMasterKey(OTCachedKey::It());

if (pMasterKey) {
OTPassword master_password;
const bool bGotMasterPW = pMasterKey->GetMasterPassword(
pMasterKey, master_password,
(nullptr == pReason) ? "" : pReason->c_str());
OTString strNewKeyOutput;

if (bGotMasterPW &&
OTSymmetricKey::CreateNewKey(strNewKeyOutput, nullptr,
&master_password)) {
std::shared_ptr<OTSymmetricKey> pNewExtraKey(
new OTSymmetricKey);

if (pNewExtraKey &&
pNewExtraKey->SerializeFrom(strNewKeyOutput) &&
addExtraKey(str_KeyID, pNewExtraKey)) {

pExtraKey = pNewExtraKey;

SaveWallet();
}
} // if (bGotMasterPW)
} // if (pMasterKey)
}

// Then:
//
if (pExtraKey) return pExtraKey; // <======== SUCCESS.

return std::shared_ptr<OTSymmetricKey>();
}

// The "extra" symmetric keys in the wallet are all, like the Nyms, encrypted
// to the wallet's master key. So whenever the wallet's master key is changed,
// this method needs to be called as well, to update those extra symmetric keys
Expand Down Expand Up @@ -1409,6 +1478,54 @@ bool OTWallet::ChangePassphrasesOnExtraKeys(const OTPassword& oldPassphrase,
return true;
}

bool OTWallet::Encrypt_ByKeyID(const std::string& key_id,
const OTString& strPlaintext,
OTString& strOutput, const OTString* pstrDisplay,
bool bBookends)
{
if (key_id.empty() || !strPlaintext.Exists()) return false;

std::string str_Reason((nullptr != pstrDisplay) ? pstrDisplay->Get() : "");

std::shared_ptr<OTSymmetricKey> pKey =
OTWallet::getOrCreateExtraKey(key_id, &str_Reason);

if (pKey) {
std::shared_ptr<OTCachedKey> pMasterKey(OTCachedKey::It());

if (pMasterKey) {
OTPassword master_password;

if (pMasterKey->GetMasterPassword(pMasterKey, master_password))
return OTSymmetricKey::Encrypt(*pKey, strPlaintext, strOutput,
pstrDisplay, bBookends,
&master_password);
}
}
return false;
}
bool OTWallet::Decrypt_ByKeyID(const std::string& key_id,
const OTString& strCiphertext,
OTString& strOutput, const OTString* pstrDisplay)
{
if (key_id.empty() || !strCiphertext.Exists()) return false;

std::shared_ptr<OTSymmetricKey> pKey = OTWallet::getExtraKey(key_id);

if (pKey) {
std::shared_ptr<OTCachedKey> pMasterKey(OTCachedKey::It());

if (pMasterKey) {
OTPassword master_password;

if (pMasterKey->GetMasterPassword(pMasterKey, master_password))
return OTSymmetricKey::Decrypt(*pKey, strCiphertext, strOutput,
pstrDisplay, &master_password);
}
}
return false;
}

std::shared_ptr<OTSymmetricKey> OTWallet::getExtraKey(const std::string& str_id)
{
if (str_id.empty()) return std::shared_ptr<OTSymmetricKey>();
Expand Down

0 comments on commit 9dcc3f4

Please sign in to comment.