Merge #957: Refactor CKeePassIntegrator

d4f5d7c Refactor CKeePassIntegrator
This commit is contained in:
UdjinM6 2016-08-23 15:27:04 +04:00 committed by Holger Schinzel
parent a1d2c938de
commit 83f4e57087
4 changed files with 172 additions and 171 deletions

View File

@ -30,11 +30,12 @@
#include <openssl/buffer.h> #include <openssl/buffer.h>
#include "support/cleanse.h" // for OPENSSL_cleanse() #include "support/cleanse.h" // for OPENSSL_cleanse()
const char* CKeePassIntegrator::KEEPASS_HTTP_HOST = "localhost";
CKeePassIntegrator keePassInt; CKeePassIntegrator keePassInt;
// Base64 decoding with secure memory allocation // Base64 decoding with secure memory allocation
SecureString DecodeBase64Secure(const SecureString& input) SecureString DecodeBase64Secure(const SecureString& sInput)
{ {
SecureString output; SecureString output;
@ -42,19 +43,19 @@ SecureString DecodeBase64Secure(const SecureString& input)
BIO *b64, *mem; BIO *b64, *mem;
b64 = BIO_new(BIO_f_base64()); b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
mem = BIO_new_mem_buf((void *) &input[0], input.size()); mem = BIO_new_mem_buf((void *) &sInput[0], sInput.size());
BIO_push(b64, mem); BIO_push(b64, mem);
// Prepare buffer to receive decoded data // Prepare buffer to receive decoded data
if(input.size() % 4 != 0) { if(sInput.size() % 4 != 0) {
throw std::runtime_error("Input length should be a multiple of 4"); throw std::runtime_error("Input length should be a multiple of 4");
} }
size_t nMaxLen = input.size() / 4 * 3; // upper bound, guaranteed divisible by 4 size_t nMaxLen = sInput.size() / 4 * 3; // upper bound, guaranteed divisible by 4
output.resize(nMaxLen); output.resize(nMaxLen);
// Decode the string // Decode the string
size_t nLen; size_t nLen;
nLen = BIO_read(b64, (void *) &output[0], input.size()); nLen = BIO_read(b64, (void *) &output[0], sInput.size());
output.resize(nLen); output.resize(nLen);
// Free memory // Free memory
@ -63,7 +64,7 @@ SecureString DecodeBase64Secure(const SecureString& input)
} }
// Base64 encoding with secure memory allocation // Base64 encoding with secure memory allocation
SecureString EncodeBase64Secure(const SecureString& input) SecureString EncodeBase64Secure(const SecureString& sInput)
{ {
// Init openssl BIO with base64 filter and memory output // Init openssl BIO with base64 filter and memory output
BIO *b64, *mem; BIO *b64, *mem;
@ -73,7 +74,7 @@ SecureString EncodeBase64Secure(const SecureString& input)
BIO_push(b64, mem); BIO_push(b64, mem);
// Decode the string // Decode the string
BIO_write(b64, &input[0], input.size()); BIO_write(b64, &sInput[0], sInput.size());
(void) BIO_flush(b64); (void) BIO_flush(b64);
// Create output variable from buffer mem ptr // Create output variable from buffer mem ptr
@ -105,39 +106,39 @@ void CKeePassIntegrator::init()
bIsActive = GetBoolArg("-keepass", false); bIsActive = GetBoolArg("-keepass", false);
nPort = GetArg("-keepassport", DEFAULT_KEEPASS_HTTP_PORT); nPort = GetArg("-keepassport", DEFAULT_KEEPASS_HTTP_PORT);
sKeyBase64 = SecureString(GetArg("-keepasskey", "").c_str()); sKeyBase64 = SecureString(GetArg("-keepasskey", "").c_str());
sKeePassId = GetArg("-keepassid", ""); strKeePassId = GetArg("-keepassid", "");
sKeePassEntryName = GetArg("-keepassname", ""); strKeePassEntryName = GetArg("-keepassname", "");
// Convert key if available // Convert key if available
if(sKeyBase64.size() > 0) if(sKeyBase64.size() > 0)
{ {
sKey = DecodeBase64Secure(sKeyBase64); sKey = DecodeBase64Secure(sKeyBase64);
} }
// Construct url if available // Construct url if available
if(sKeePassEntryName.size() > 0) if(strKeePassEntryName.size() > 0)
{ {
sUrl = SecureString("http://"); sUrl = SecureString("http://");
sUrl += SecureString(sKeePassEntryName.c_str()); sUrl += SecureString(strKeePassEntryName.c_str());
sUrl += SecureString("/"); sUrl += SecureString("/");
//sSubmitUrl = "http://"; //sSubmitUrl = "http://";
//sSubmitUrl += SecureString(sKeePassEntryName.c_str()); //sSubmitUrl += SecureString(strKeePassEntryName.c_str());
} }
} }
void CKeePassIntegrator::CKeePassRequest::addStrParameter(std::string sName, std::string sValue) void CKeePassIntegrator::CKeePassRequest::addStrParameter(std::string strName, std::string strValue)
{ {
requestObj.push_back(Pair(sName, sValue)); requestObj.push_back(Pair(strName, strValue));
} }
void CKeePassIntegrator::CKeePassRequest::addStrParameter(std::string sName, SecureString sValue) void CKeePassIntegrator::CKeePassRequest::addStrParameter(std::string strName, SecureString sValue)
{ {
std::string sCipherValue; std::string sCipherValue;
if(!EncryptAES256(sKey, sValue, sIV, sCipherValue)) if(!EncryptAES256(sKey, sValue, strIV, sCipherValue))
{ {
throw std::runtime_error("Unable to encrypt Verifier"); throw std::runtime_error("Unable to encrypt Verifier");
} }
addStrParameter(sName, EncodeBase64(sCipherValue)); addStrParameter(strName, EncodeBase64(sCipherValue));
} }
std::string CKeePassIntegrator::CKeePassRequest::getJson() std::string CKeePassIntegrator::CKeePassRequest::getJson()
@ -148,18 +149,18 @@ std::string CKeePassIntegrator::CKeePassRequest::getJson()
void CKeePassIntegrator::CKeePassRequest::init() void CKeePassIntegrator::CKeePassRequest::init()
{ {
SecureString sIVSecure = generateRandomKey(KEEPASS_CRYPTO_BLOCK_SIZE); SecureString sIVSecure = generateRandomKey(KEEPASS_CRYPTO_BLOCK_SIZE);
sIV = std::string(&sIVSecure[0], sIVSecure.size()); strIV = std::string(&sIVSecure[0], sIVSecure.size());
// Generate Nonce, Verifier and RequestType // Generate Nonce, Verifier and RequestType
SecureString sNonceBase64Secure = EncodeBase64Secure(sIVSecure); SecureString sNonceBase64Secure = EncodeBase64Secure(sIVSecure);
addStrParameter("Nonce", std::string(&sNonceBase64Secure[0], sNonceBase64Secure.size())); // Plain addStrParameter("Nonce", std::string(&sNonceBase64Secure[0], sNonceBase64Secure.size())); // Plain
addStrParameter("Verifier", sNonceBase64Secure); // Encoded addStrParameter("Verifier", sNonceBase64Secure); // Encoded
addStrParameter("RequestType", sType); addStrParameter("RequestType", strType);
} }
void CKeePassIntegrator::CKeePassResponse::parseResponse(std::string sResponse) void CKeePassIntegrator::CKeePassResponse::parseResponse(std::string strResponse)
{ {
UniValue responseValue; UniValue responseValue;
if(!responseValue.read(sResponse)) if(!responseValue.read(strResponse))
{ {
throw std::runtime_error("Unable to parse KeePassHttp response"); throw std::runtime_error("Unable to parse KeePassHttp response");
} }
@ -168,37 +169,37 @@ void CKeePassIntegrator::CKeePassResponse::parseResponse(std::string sResponse)
// retrieve main values // retrieve main values
bSuccess = responseObj["Success"].get_bool(); bSuccess = responseObj["Success"].get_bool();
sType = getStr("RequestType"); strType = getStr("RequestType");
sIV = DecodeBase64(getStr("Nonce")); strIV = DecodeBase64(getStr("Nonce"));
} }
std::string CKeePassIntegrator::CKeePassResponse::getStr(std::string sName) std::string CKeePassIntegrator::CKeePassResponse::getStr(std::string strName)
{ {
return responseObj[sName].get_str(); return responseObj[strName].get_str();
} }
SecureString CKeePassIntegrator::CKeePassResponse::getSecureStr(std::string sName) SecureString CKeePassIntegrator::CKeePassResponse::getSecureStr(std::string strName)
{ {
std::string sValueBase64Encrypted(responseObj[sName].get_str()); std::string strValueBase64Encrypted(responseObj[strName].get_str());
SecureString sValue; SecureString sValue;
try try
{ {
sValue = decrypt(sValueBase64Encrypted); sValue = decrypt(strValueBase64Encrypted);
} }
catch (std::exception &e) catch (std::exception &e)
{ {
std::string sErrorMessage = "Exception occured while decrypting "; std::string strError = "Exception occured while decrypting ";
sErrorMessage += sName + ": " + e.what(); strError += strName + ": " + e.what();
throw std::runtime_error(sErrorMessage); throw std::runtime_error(strError);
} }
return sValue; return sValue;
} }
SecureString CKeePassIntegrator::CKeePassResponse::decrypt(std::string sValueBase64Encrypted) SecureString CKeePassIntegrator::CKeePassResponse::decrypt(std::string strValueBase64Encrypted)
{ {
std::string sValueEncrypted = DecodeBase64(sValueBase64Encrypted); std::string strValueEncrypted = DecodeBase64(strValueBase64Encrypted);
SecureString sValue; SecureString sValue;
if(!DecryptAES256(sKey, sValueEncrypted, sIV, sValue)) if(!DecryptAES256(sKey, strValueEncrypted, strIV, sValue))
{ {
throw std::runtime_error("Unable to decrypt value."); throw std::runtime_error("Unable to decrypt value.");
} }
@ -228,20 +229,20 @@ std::vector<CKeePassIntegrator::CKeePassEntry> CKeePassIntegrator::CKeePassRespo
SecureString CKeePassIntegrator::generateRandomKey(size_t nSize) SecureString CKeePassIntegrator::generateRandomKey(size_t nSize)
{ {
// Generates random key // Generates random key
SecureString key; SecureString sKey;
key.resize(nSize); sKey.resize(nSize);
RandAddSeedPerfmon(); RandAddSeedPerfmon();
GetRandBytes((unsigned char *) &key[0], nSize); GetRandBytes((unsigned char *) &sKey[0], nSize);
return key; return sKey;
} }
// Construct POST body for RPC JSON call // Construct POST body for RPC JSON call
std::string CKeePassIntegrator::constructHTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders) std::string CKeePassIntegrator::constructHTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders)
{ {
std::ostringstream s; std::ostringstream streamOut;
s << "POST / HTTP/1.1\r\n" streamOut << "POST / HTTP/1.1\r\n"
<< "User-Agent: dash-json-rpc/" << FormatFullVersion() << "\r\n" << "User-Agent: dash-json-rpc/" << FormatFullVersion() << "\r\n"
<< "Host: localhost\r\n" << "Host: localhost\r\n"
<< "Content-Type: application/json\r\n" << "Content-Type: application/json\r\n"
@ -249,17 +250,17 @@ std::string CKeePassIntegrator::constructHTTPPost(const std::string& strMsg, con
<< "Connection: close\r\n" << "Connection: close\r\n"
<< "Accept: application/json\r\n"; << "Accept: application/json\r\n";
BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, mapRequestHeaders) BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item, mapRequestHeaders)
s << item.first << ": " << item.second << "\r\n"; streamOut << item.first << ": " << item.second << "\r\n";
s << "\r\n" << strMsg; streamOut << "\r\n" << strMsg;
return s.str(); return streamOut.str();
} }
/** Reply structure for request_done to fill in */ /** Reply structure for request_done to fill in */
struct HTTPReply struct HTTPReply
{ {
int status; int nStatus;
std::string body; std::string strBody;
}; };
static void http_request_done(struct evhttp_request *req, void *ctx) static void http_request_done(struct evhttp_request *req, void *ctx)
@ -270,11 +271,11 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
/* If req is NULL, it means an error occurred while connecting, but /* If req is NULL, it means an error occurred while connecting, but
* I'm not sure how to find out which one. We also don't really care. * I'm not sure how to find out which one. We also don't really care.
*/ */
reply->status = 0; reply->nStatus = 0;
return; return;
} }
reply->status = evhttp_request_get_response_code(req); reply->nStatus = evhttp_request_get_response_code(req);
struct evbuffer *buf = evhttp_request_get_input_buffer(req); struct evbuffer *buf = evhttp_request_get_input_buffer(req);
if (buf) if (buf)
@ -282,13 +283,13 @@ static void http_request_done(struct evhttp_request *req, void *ctx)
size_t size = evbuffer_get_length(buf); size_t size = evbuffer_get_length(buf);
const char *data = (const char*)evbuffer_pullup(buf, size); const char *data = (const char*)evbuffer_pullup(buf, size);
if (data) if (data)
reply->body = std::string(data, size); reply->strBody = std::string(data, size);
evbuffer_drain(buf, size); evbuffer_drain(buf, size);
} }
} }
// Send RPC message to KeePassHttp // Send RPC message to KeePassHttp
void CKeePassIntegrator::doHTTPPost(const std::string& sRequest, int& nStatus, std::string& sResponse) void CKeePassIntegrator::doHTTPPost(const std::string& sRequest, int& nStatus, std::string& strResponse)
{ {
// // Prepare communication // // Prepare communication
// boost::asio::io_service io_service; // boost::asio::io_service io_service;
@ -401,26 +402,26 @@ void CKeePassIntegrator::doHTTPPost(const std::string& sRequest, int& nStatus, s
// //
// // Receive HTTP reply message headers and body // // Receive HTTP reply message headers and body
// std::map<std::string, std::string> mapHeaders; // std::map<std::string, std::string> mapHeaders;
// ReadHTTPMessage(response_stream, mapHeaders, sResponse, nProto, std::numeric_limits<size_t>::max()); // ReadHTTPMessage(response_stream, mapHeaders, strResponse, nProto, std::numeric_limits<size_t>::max());
// LogPrint("keepass", "CKeePassIntegrator::doHTTPPost -- Processed body\n"); // LogPrint("keepass", "CKeePassIntegrator::doHTTPPost -- Processed body\n");
nStatus = response.status; nStatus = response.nStatus;
if (response.status == 0) if (response.nStatus == 0)
throw std::runtime_error("couldn't connect to server"); throw std::runtime_error("couldn't connect to server");
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) else if (response.nStatus >= 400 && response.nStatus != HTTP_BAD_REQUEST && response.nStatus != HTTP_NOT_FOUND && response.nStatus != HTTP_INTERNAL_SERVER_ERROR)
throw std::runtime_error(strprintf("server returned HTTP error %d", response.status)); throw std::runtime_error(strprintf("server returned HTTP error %d", response.nStatus));
else if (response.body.empty()) else if (response.strBody.empty())
throw std::runtime_error("no response from server"); throw std::runtime_error("no response from server");
// Parse reply // Parse reply
UniValue valReply(UniValue::VSTR); UniValue valReply(UniValue::VSTR);
if (!valReply.read(response.body)) if (!valReply.read(response.strBody))
throw std::runtime_error("couldn't parse reply from server"); throw std::runtime_error("couldn't parse reply from server");
const UniValue& reply = valReply.get_obj(); const UniValue& reply = valReply.get_obj();
if (reply.empty()) if (reply.empty())
throw std::runtime_error("expected reply to have result, error and id properties"); throw std::runtime_error("expected reply to have result, error and id properties");
sResponse = valReply.get_str(); strResponse = valReply.get_str();
} }
void CKeePassIntegrator::rpcTestAssociation(bool bTriggerUnlock) void CKeePassIntegrator::rpcTestAssociation(bool bTriggerUnlock)
@ -429,11 +430,11 @@ void CKeePassIntegrator::rpcTestAssociation(bool bTriggerUnlock)
request.addStrParameter("TriggerUnlock", std::string(bTriggerUnlock ? "true" : "false")); request.addStrParameter("TriggerUnlock", std::string(bTriggerUnlock ? "true" : "false"));
int nStatus; int nStatus;
std::string sResponse; std::string strResponse;
doHTTPPost(request.getJson(), nStatus, sResponse); doHTTPPost(request.getJson(), nStatus, strResponse);
LogPrint("keepass", "CKeePassIntegrator::rpcTestAssociation -- send result: status: %d response: %s\n", nStatus, sResponse); LogPrint("keepass", "CKeePassIntegrator::rpcTestAssociation -- send result: status: %d response: %s\n", nStatus, strResponse);
} }
std::vector<CKeePassIntegrator::CKeePassEntry> CKeePassIntegrator::rpcGetLogins() std::vector<CKeePassIntegrator::CKeePassEntry> CKeePassIntegrator::rpcGetLogins()
@ -445,82 +446,82 @@ std::vector<CKeePassIntegrator::CKeePassEntry> CKeePassIntegrator::rpcGetLogins(
CKeePassRequest request(sKey, "get-logins"); CKeePassRequest request(sKey, "get-logins");
request.addStrParameter("addStrParameter", std::string("true")); request.addStrParameter("addStrParameter", std::string("true"));
request.addStrParameter("TriggerUnlock", std::string("true")); request.addStrParameter("TriggerUnlock", std::string("true"));
request.addStrParameter("Id", sKeePassId); request.addStrParameter("Id", strKeePassId);
request.addStrParameter("Url", sUrl); request.addStrParameter("Url", sUrl);
int nStatus; int nStatus;
std::string sResponse; std::string strResponse;
doHTTPPost(request.getJson(), nStatus, sResponse); doHTTPPost(request.getJson(), nStatus, strResponse);
// Logging of actual response data disabled as to not write passphrase in debug.log. Only enable temporarily when needed // Logging of actual response data disabled as to not write passphrase in debug.log. Only enable temporarily when needed
//LogPrint("keepass", "CKeePassIntegrator::rpcGetLogins -- send result: status: %d response: %s\n", nStatus, sResponse); //LogPrint("keepass", "CKeePassIntegrator::rpcGetLogins -- send result: status: %d response: %s\n", nStatus, strResponse);
LogPrint("keepass", "CKeePassIntegrator::rpcGetLogins -- send result: status: %d\n", nStatus); LogPrint("keepass", "CKeePassIntegrator::rpcGetLogins -- send result: status: %d\n", nStatus);
if(nStatus != 200) if(nStatus != 200)
{ {
std::string sErrorMessage = "Error returned by KeePassHttp: HTTP code "; std::string strError = "Error returned by KeePassHttp: HTTP code ";
sErrorMessage += itostr(nStatus); strError += itostr(nStatus);
sErrorMessage += " - Response: "; strError += " - Response: ";
sErrorMessage += " response: ["; strError += " response: [";
sErrorMessage += sResponse; strError += strResponse;
sErrorMessage += "]"; strError += "]";
throw std::runtime_error(sErrorMessage); throw std::runtime_error(strError);
} }
// Parse the response // Parse the response
CKeePassResponse response(sKey, sResponse); CKeePassResponse response(sKey, strResponse);
if(!response.getSuccess()) if(!response.getSuccess())
{ {
std::string sErrorMessage = "KeePassHttp returned failure status"; std::string strError = "KeePassHttp returned failure status";
throw std::runtime_error(sErrorMessage); throw std::runtime_error(strError);
} }
return response.getEntries(); return response.getEntries();
} }
void CKeePassIntegrator::rpcSetLogin(const SecureString& strWalletPass, const SecureString& sEntryId) void CKeePassIntegrator::rpcSetLogin(const SecureString& sWalletPass, const SecureString& sEntryId)
{ {
// Convert key format // Convert key format
SecureString sKey = DecodeBase64Secure(sKeyBase64); SecureString sKey = DecodeBase64Secure(sKeyBase64);
CKeePassRequest request(sKey, "set-login"); CKeePassRequest request(sKey, "set-login");
request.addStrParameter("Id", sKeePassId); request.addStrParameter("Id", strKeePassId);
request.addStrParameter("Url", sUrl); request.addStrParameter("Url", sUrl);
LogPrint("keepass", "CKeePassIntegrator::rpcSetLogin -- send Url: %s\n", sUrl); LogPrint("keepass", "CKeePassIntegrator::rpcSetLogin -- send Url: %s\n", sUrl);
//request.addStrParameter("SubmitUrl", sSubmitUrl); // Is used to construct the entry title //request.addStrParameter("SubmitUrl", sSubmitUrl); // Is used to construct the entry title
request.addStrParameter("Login", SecureString("dash")); request.addStrParameter("Login", SecureString("dash"));
request.addStrParameter("Password", strWalletPass); request.addStrParameter("Password", sWalletPass);
if(sEntryId.size() != 0) if(sEntryId.size() != 0)
{ {
request.addStrParameter("Uuid", sEntryId); // Update existing request.addStrParameter("Uuid", sEntryId); // Update existing
} }
int nStatus; int nStatus;
std::string sResponse; std::string strResponse;
doHTTPPost(request.getJson(), nStatus, sResponse); doHTTPPost(request.getJson(), nStatus, strResponse);
LogPrint("keepass", "CKeePassIntegrator::rpcSetLogin -- send result: status: %d response: %s\n", nStatus, sResponse); LogPrint("keepass", "CKeePassIntegrator::rpcSetLogin -- send result: status: %d response: %s\n", nStatus, strResponse);
if(nStatus != 200) if(nStatus != 200)
{ {
std::string sErrorMessage = "Error returned: HTTP code "; std::string strError = "Error returned: HTTP code ";
sErrorMessage += itostr(nStatus); strError += itostr(nStatus);
sErrorMessage += " - Response: "; strError += " - Response: ";
sErrorMessage += " response: ["; strError += " response: [";
sErrorMessage += sResponse; strError += strResponse;
sErrorMessage += "]"; strError += "]";
throw std::runtime_error(sErrorMessage); throw std::runtime_error(strError);
} }
// Parse the response // Parse the response
CKeePassResponse response(sKey, sResponse); CKeePassResponse response(sKey, strResponse);
if(!response.getSuccess()) if(!response.getSuccess())
{ {
@ -536,7 +537,7 @@ SecureString CKeePassIntegrator::generateKeePassKey()
return sKeyBase64; return sKeyBase64;
} }
void CKeePassIntegrator::rpcAssociate(std::string& sId, SecureString& sKeyBase64) void CKeePassIntegrator::rpcAssociate(std::string& strId, SecureString& sKeyBase64)
{ {
sKey = generateRandomKey(KEEPASS_CRYPTO_KEY_SIZE); sKey = generateRandomKey(KEEPASS_CRYPTO_KEY_SIZE);
CKeePassRequest request(sKey, "associate"); CKeePassRequest request(sKey, "associate");
@ -545,25 +546,25 @@ void CKeePassIntegrator::rpcAssociate(std::string& sId, SecureString& sKeyBase64
request.addStrParameter("Key", std::string(&sKeyBase64[0], sKeyBase64.size())); request.addStrParameter("Key", std::string(&sKeyBase64[0], sKeyBase64.size()));
int nStatus; int nStatus;
std::string sResponse; std::string strResponse;
doHTTPPost(request.getJson(), nStatus, sResponse); doHTTPPost(request.getJson(), nStatus, strResponse);
LogPrint("keepass", "CKeePassIntegrator::rpcAssociate -- send result: status: %d response: %s\n", nStatus, sResponse); LogPrint("keepass", "CKeePassIntegrator::rpcAssociate -- send result: status: %d response: %s\n", nStatus, strResponse);
if(nStatus != 200) if(nStatus != 200)
{ {
std::string sErrorMessage = "Error returned: HTTP code "; std::string strError = "Error returned: HTTP code ";
sErrorMessage += itostr(nStatus); strError += itostr(nStatus);
sErrorMessage += " - Response: "; strError += " - Response: ";
sErrorMessage += " response: ["; strError += " response: [";
sErrorMessage += sResponse; strError += strResponse;
sErrorMessage += "]"; strError += "]";
throw std::runtime_error(sErrorMessage); throw std::runtime_error(strError);
} }
// Parse the response // Parse the response
CKeePassResponse response(sKey, sResponse); CKeePassResponse response(sKey, strResponse);
if(!response.getSuccess()) if(!response.getSuccess())
{ {
@ -571,7 +572,7 @@ void CKeePassIntegrator::rpcAssociate(std::string& sId, SecureString& sKeyBase64
} }
// If we got here, we were successful. Return the information // If we got here, we were successful. Return the information
sId = response.getStr("Id"); strId = response.getStr("Id");
} }
// Retrieve wallet passphrase from KeePass // Retrieve wallet passphrase from KeePass
@ -583,29 +584,29 @@ SecureString CKeePassIntegrator::retrievePassphrase()
{ {
throw std::runtime_error("keepasskey parameter is not defined. Please specify the configuration parameter."); throw std::runtime_error("keepasskey parameter is not defined. Please specify the configuration parameter.");
} }
if(sKeePassId.size() == 0) if(strKeePassId.size() == 0)
{ {
throw std::runtime_error("keepassid parameter is not defined. Please specify the configuration parameter."); throw std::runtime_error("keepassid parameter is not defined. Please specify the configuration parameter.");
} }
if(sKeePassEntryName == "") if(strKeePassEntryName == "")
{ {
throw std::runtime_error("keepassname parameter is not defined. Please specify the configuration parameter."); throw std::runtime_error("keepassname parameter is not defined. Please specify the configuration parameter.");
} }
// Retrieve matching logins from KeePass // Retrieve matching logins from KeePass
std::vector<CKeePassIntegrator::CKeePassEntry> entries = rpcGetLogins(); std::vector<CKeePassIntegrator::CKeePassEntry> vecEntries = rpcGetLogins();
// Only accept one unique match // Only accept one unique match
if(entries.size() == 0) if(vecEntries.size() == 0)
{ {
throw std::runtime_error("KeePassHttp returned 0 matches, please verify the keepassurl setting."); throw std::runtime_error("KeePassHttp returned 0 matches, please verify the keepassurl setting.");
} }
if(entries.size() > 1) if(vecEntries.size() > 1)
{ {
throw std::runtime_error("KeePassHttp returned multiple matches, bailing out."); throw std::runtime_error("KeePassHttp returned multiple matches, bailing out.");
} }
return entries[0].getPassword(); return vecEntries[0].getPassword();
} }
// Update wallet passphrase in keepass // Update wallet passphrase in keepass
@ -616,30 +617,30 @@ void CKeePassIntegrator::updatePassphrase(const SecureString& sWalletPassphrase)
{ {
throw std::runtime_error("keepasskey parameter is not defined. Please specify the configuration parameter."); throw std::runtime_error("keepasskey parameter is not defined. Please specify the configuration parameter.");
} }
if(sKeePassId.size() == 0) if(strKeePassId.size() == 0)
{ {
throw std::runtime_error("keepassid parameter is not defined. Please specify the configuration parameter."); throw std::runtime_error("keepassid parameter is not defined. Please specify the configuration parameter.");
} }
if(sKeePassEntryName == "") if(strKeePassEntryName == "")
{ {
throw std::runtime_error("keepassname parameter is not defined. Please specify the configuration parameter."); throw std::runtime_error("keepassname parameter is not defined. Please specify the configuration parameter.");
} }
SecureString sEntryId(""); SecureString sEntryId("");
std::string sErrorMessage; std::string strError;
// Lookup existing entry // Lookup existing entry
std::vector<CKeePassIntegrator::CKeePassEntry> vEntries = rpcGetLogins(); std::vector<CKeePassIntegrator::CKeePassEntry> vecEntries = rpcGetLogins();
if(vEntries.size() > 1) if(vecEntries.size() > 1)
{ {
throw std::runtime_error("KeePassHttp returned multiple matches, bailing out."); throw std::runtime_error("KeePassHttp returned multiple matches, bailing out.");
} }
if(vEntries.size() == 1) if(vecEntries.size() == 1)
{ {
sEntryId = vEntries[0].getUuid(); sEntryId = vecEntries[0].getUuid();
} }
// Update wallet passphrase in KeePass // Update wallet passphrase in KeePass

View File

@ -9,13 +9,18 @@
#include <univalue.h> #include <univalue.h>
static const int KEEPASS_CRYPTO_KEY_SIZE = 32; class CKeePassIntegrator;
static const int KEEPASS_CRYPTO_BLOCK_SIZE = 16;
static const int KEEPASS_HTTP_CONNECT_TIMEOUT = 30;
static const unsigned int DEFAULT_KEEPASS_HTTP_PORT = 19455; static const unsigned int DEFAULT_KEEPASS_HTTP_PORT = 19455;
static const char* KEEPASS_HTTP_HOST = "localhost";
extern CKeePassIntegrator keePassInt;
class CKeePassIntegrator { class CKeePassIntegrator {
private:
static const int KEEPASS_CRYPTO_KEY_SIZE = 32;
static const int KEEPASS_CRYPTO_BLOCK_SIZE = 16;
static const int KEEPASS_HTTP_CONNECT_TIMEOUT = 30;
static const char* KEEPASS_HTTP_HOST;
bool bIsActive; bool bIsActive;
unsigned int nPort; unsigned int nPort;
@ -23,27 +28,27 @@ class CKeePassIntegrator {
SecureString sKey; SecureString sKey;
SecureString sUrl; SecureString sUrl;
//SecureString sSubmitUrl; //SecureString sSubmitUrl;
std::string sKeePassId; std::string strKeePassId;
std::string sKeePassEntryName; std::string strKeePassEntryName;
class CKeePassRequest { class CKeePassRequest {
UniValue requestObj; UniValue requestObj;
std::string sType; std::string strType;
std::string sIV; std::string strIV;
SecureString sKey; SecureString sKey;
void init(); void init();
public: public:
void addStrParameter(std::string sName, std::string sValue); // Regular void addStrParameter(std::string strName, std::string strValue); // Regular
void addStrParameter(std::string sName, SecureString sValue); // Encrypt void addStrParameter(std::string strName, SecureString sValue); // Encrypt
std::string getJson(); std::string getJson();
CKeePassRequest(SecureString sKey, std::string sType) CKeePassRequest(SecureString sKey, std::string strType)
{ {
this->sKey = sKey; this->sKey = sKey;
this->sType = sType; this->strType = strType;
init(); init();
}; };
}; };
@ -51,30 +56,30 @@ class CKeePassIntegrator {
class CKeePassEntry { class CKeePassEntry {
SecureString uuid; SecureString sUuid;
SecureString name; SecureString sName;
SecureString login; SecureString sLogin;
SecureString password; SecureString sPassword;
public: public:
CKeePassEntry(SecureString uuid, SecureString name, SecureString login, SecureString password) : CKeePassEntry(SecureString sUuid, SecureString sName, SecureString sLogin, SecureString sPassword) :
uuid(uuid), name(name), login(login), password(password) { sUuid(sUuid), sName(sName), sLogin(sLogin), sPassword(sPassword) {
} }
SecureString getUuid() { SecureString getUuid() {
return uuid; return sUuid;
} }
SecureString getName() { SecureString getName() {
return name; return sName;
} }
SecureString getLogin() { SecureString getLogin() {
return login; return sLogin;
} }
SecureString getPassword() { SecureString getPassword() {
return password; return sPassword;
} }
}; };
@ -83,48 +88,46 @@ class CKeePassIntegrator {
class CKeePassResponse { class CKeePassResponse {
bool bSuccess; bool bSuccess;
std::string sType; std::string strType;
std::string sIV; std::string strIV;
SecureString sKey; SecureString sKey;
void parseResponse(std::string sResponse); void parseResponse(std::string strResponse);
public: public:
UniValue responseObj; UniValue responseObj;
CKeePassResponse(SecureString sKey, std::string sResponse) { CKeePassResponse(SecureString sKey, std::string strResponse) {
this->sKey = sKey; this->sKey = sKey;
parseResponse(sResponse); parseResponse(strResponse);
} }
bool getSuccess() { bool getSuccess() {
return bSuccess; return bSuccess;
} }
SecureString getSecureStr(std::string sName); SecureString getSecureStr(std::string strName);
std::string getStr(std::string sName); std::string getStr(std::string strName);
std::vector<CKeePassEntry> getEntries(); std::vector<CKeePassEntry> getEntries();
SecureString decrypt(std::string sValue); // DecodeBase64 and decrypt arbitrary string value SecureString decrypt(std::string strValue); // DecodeBase64 and decrypt arbitrary string value
}; };
static SecureString generateRandomKey(size_t nSize); static SecureString generateRandomKey(size_t nSize);
static std::string constructHTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders); static std::string constructHTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
void doHTTPPost(const std::string& sRequest, int& nStatus, std::string& sResponse); void doHTTPPost(const std::string& strRequest, int& nStatus, std::string& strResponse);
void rpcTestAssociation(bool bTriggerUnlock); void rpcTestAssociation(bool bTriggerUnlock);
std::vector<CKeePassEntry> rpcGetLogins(); std::vector<CKeePassEntry> rpcGetLogins();
void rpcSetLogin(const SecureString& strWalletPass, const SecureString& sEntryId); void rpcSetLogin(const SecureString& sWalletPass, const SecureString& sEntryId);
public: public:
CKeePassIntegrator(); CKeePassIntegrator();
void init(); void init();
static SecureString generateKeePassKey(); static SecureString generateKeePassKey();
void rpcAssociate(std::string& sId, SecureString& sKeyBase64); void rpcAssociate(std::string& strId, SecureString& sKeyBase64);
SecureString retrievePassphrase(); SecureString retrievePassphrase();
void updatePassphrase(const SecureString& sWalletPassphrase); void updatePassphrase(const SecureString& sWalletPassphrase);
}; };
extern CKeePassIntegrator keePassInt;
#endif #endif

View File

@ -2411,28 +2411,25 @@ UniValue keepass(const UniValue& params, bool fHelp) {
if (strCommand == "genkey") if (strCommand == "genkey")
{ {
SecureString result; SecureString sResult;
// Generate RSA key // Generate RSA key
//std::string keePassKey = CKeePassIntegrator::generateKey();
//return keePassKey;
SecureString sKey = CKeePassIntegrator::generateKeePassKey(); SecureString sKey = CKeePassIntegrator::generateKeePassKey();
result = "Generated Key: "; sResult = "Generated Key: ";
result += sKey; sResult += sKey;
return result.c_str(); return sResult.c_str();
} }
else if(strCommand == "init") else if(strCommand == "init")
{ {
// Generate base64 encoded 256 bit RSA key and associate with KeePassHttp // Generate base64 encoded 256 bit RSA key and associate with KeePassHttp
SecureString result; SecureString sResult;
SecureString sKey; SecureString sKey;
std::string sId; std::string strId;
std::string sErrorMessage; keePassInt.rpcAssociate(strId, sKey);
keePassInt.rpcAssociate(sId, sKey); sResult = "Association successful. Id: ";
result = "Association successful. Id: "; sResult += strId.c_str();
result += sId.c_str(); sResult += " - Key: ";
result += " - Key: "; sResult += sKey.c_str();
result += sKey.c_str(); return sResult.c_str();
return result.c_str();
} }
else if(strCommand == "setpassphrase") else if(strCommand == "setpassphrase")
{ {

View File

@ -252,7 +252,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly
} }
// Verify KeePassIntegration // Verify KeePassIntegration
if(strWalletPassphrase == "keepass" && GetBoolArg("-keepass", false)) { if (strWalletPassphrase == "keepass" && GetBoolArg("-keepass", false)) {
try { try {
strWalletPassphraseFinal = keePassInt.retrievePassphrase(); strWalletPassphraseFinal = keePassInt.retrievePassphrase();
} catch (std::exception& e) { } catch (std::exception& e) {
@ -270,7 +270,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool anonymizeOnly
LOCK(cs_wallet); LOCK(cs_wallet);
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{ {
if(!crypter.SetKeyFromPassphrase(strWalletPassphraseFinal, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) if (!crypter.SetKeyFromPassphrase(strWalletPassphraseFinal, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false; return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
continue; // try another master key continue; // try another master key
@ -302,7 +302,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
try { try {
strOldWalletPassphraseFinal = keePassInt.retrievePassphrase(); strOldWalletPassphraseFinal = keePassInt.retrievePassphrase();
} catch (std::exception& e) { } catch (std::exception& e) {
LogPrintf("CWallet::ChangeWalletPassphrase could not retrieve passphrase from KeePass: Error: %s\n", e.what()); LogPrintf("CWallet::ChangeWalletPassphrase -- could not retrieve passphrase from KeePass: Error: %s\n", e.what());
return false; return false;
} }
} else { } else {
@ -346,11 +346,11 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
// Update KeePass if necessary // Update KeePass if necessary
if(bUseKeePass) { if(bUseKeePass) {
LogPrintf("CWallet::ChangeWalletPassphrase - Updating KeePass with new passphrase"); LogPrintf("CWallet::ChangeWalletPassphrase -- Updating KeePass with new passphrase");
try { try {
keePassInt.updatePassphrase(strNewWalletPassphrase); keePassInt.updatePassphrase(strNewWalletPassphrase);
} catch (std::exception& e) { } catch (std::exception& e) {
LogPrintf("CWallet::ChangeWalletPassphrase - could not update passphrase in KeePass: Error: %s\n", e.what()); LogPrintf("CWallet::ChangeWalletPassphrase -- could not update passphrase in KeePass: Error: %s\n", e.what());
return false; return false;
} }
} }
@ -653,11 +653,11 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
// Update KeePass if necessary // Update KeePass if necessary
if(GetBoolArg("-keepass", false)) { if(GetBoolArg("-keepass", false)) {
LogPrintf("CWallet::EncryptWallet - Updating KeePass with new passphrase"); LogPrintf("CWallet::EncryptWallet -- Updating KeePass with new passphrase");
try { try {
keePassInt.updatePassphrase(strWalletPassphrase); keePassInt.updatePassphrase(strWalletPassphrase);
} catch (std::exception& e) { } catch (std::exception& e) {
LogPrintf("CWallet::EncryptWallet - could not update passphrase in KeePass: Error: %s\n", e.what()); LogPrintf("CWallet::EncryptWallet -- could not update passphrase in KeePass: Error: %s\n", e.what());
} }
} }