void TranslateAccountTypeToString(OTAccount::AccountType theType, OTString & strAcctType) { switch (theType) { case OTAccount::simple: strAcctType.Set("simple"); break; case OTAccount::issuer: strAcctType.Set("issuer"); break; case OTAccount::basket: strAcctType.Set("basket"); break; case OTAccount::basketsub: strAcctType.Set("basketsub"); break; case OTAccount::mint: strAcctType.Set("mint"); break; case OTAccount::voucher: strAcctType.Set("voucher"); break; case OTAccount::stash: strAcctType.Set("stash"); break; default: strAcctType.Set("err_acct"); break; } }
void OTSocket::Listen(const OTString &strBind) { if (NULL != m_pSocket) delete m_pSocket; // m_pSocket = NULL; m_pSocket = new zmq::socket_t(*m_pContext, ZMQ_REP); // RESPONSE socket (Request / Response.) OT_ASSERT_MSG(NULL != m_pSocket, "OTSocket::Listen: new zmq::socket(context, ZMQ_REP)"); OTString strTemp(strBind); // In case m_strBindPath is what was passed in. (It happens.) m_strBindPath.Set(strTemp); // In case we have to close/reopen the socket to finish a send/receive. // ------------------------ // Configure socket to not wait at close time // const int linger = 0; // close immediately m_pSocket->setsockopt (ZMQ_LINGER, &linger, sizeof (linger)); /* int zmq_setsockopt (void *socket, int option_name, const void *option_value, size_t option_len); Caution: All options, with the exception of ZMQ_SUBSCRIBE, ZMQ_UNSUBSCRIBE and ZMQ_LINGER, only take effect for subsequent socket bind/connects. */ // ------------------------ m_pSocket->bind(strBind.Get()); }
const bool OTPaths::Win_GetInstallFolderFromRegistry(OTString & out_InstallFolderPath) { WindowsRegistryTools windowsRegistryTools; HKEY hKey=0; LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Open-Transactions", 0, KEY_READ, &hKey); bool bExistsAndSuccess (lRes == ERROR_SUCCESS); bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND); std::wstring strValueOfBinDir; windowsRegistryTools.GetStringRegKey(hKey, L"Path", strValueOfBinDir, L"bad"); if (bExistsAndSuccess) { std::string strInstallPath(OTString::ws2s(strValueOfBinDir)); out_InstallFolderPath.Set(strInstallPath.c_str()); return true; } return false; }
// static // Changes ~/blah to /Users/au/blah // void OTLog::TransformFilePath(const char * szInput, OTString & strOutput) { if (NULL == szInput) return; #ifndef _WIN32 // if UNIX (NOT windows) wordexp_t exp_result; wordexp(szInput, &exp_result, 0); strOutput.Set(exp_result.we_wordv[0]); wordfree(&exp_result); #else strOutput.Set(szInput); #endif }
// *********************************************************************** // // INI FILE // bool GetOTAppDataFolderLocation(OTString strIniFileDefault, OTString & strOTServerDataLocation) { CSimpleIniA ini; SI_Error rc = ini.LoadFile(strIniFileDefault.Get()); if (rc >=0) { { const char * pVal = ini.GetValue("paths", "server_path", SERVER_PATH_DEFAULT); // todo stop hardcoding. if (NULL != pVal) { strOTServerDataLocation.Set(pVal); OTLog::vOutput(0, "Reading ini file (%s). \n Found Server data_folder path: %s \n", strIniFileDefault.Get(), strOTServerDataLocation.Get()); return true; } OTLog::vOutput(0, "Reading ini file (%s) \n", strIniFileDefault.Get()); return false; } } else { OTLog::vOutput(0, "Unable to load ini file (%s) to find data_folder path \n", strIniFileDefault.Get()); return false; } }
// --------------------------------------- bool MTRecord::FormatShortMailDescription(std::string & str_output) { OTString strDescription; if (IsMail()) { if (!HasContents()) strDescription.Set("(empty message)"); else { std::string str_contents = GetContents(); if (str_contents.compare(0,8,"Subject:") == 0) { // Make the replacement. str_contents.replace(0, 8, ""); } // ----------------------------------- bool bTruncated = false; if (str_contents.size() > 30) { str_contents.erase(30, std::string::npos); bTruncated = true; } // ----------------------------------- strDescription.Format("\"%s%s\"", OTString::trim(str_contents).c_str(), bTruncated ? "..." : ""); } } // ----------------------------- str_output = strDescription.Get(); // ----------------------------- return (!str_output.empty()); }
void OTString::Truncate(uint32_t lAt) { OTString strTruncated; strTruncated.Set(this->Get(), lAt); this->Set(strTruncated); }
/// if we pack, compress, encode on the way in, that means, therefore, we /// need to decode, uncompress, then unpack on our way out. Right? /// /// This function will base64-DECODE the string contents, then uncompress them using /// zlib, and then unpack the result using whatever is the default packer (MsgPack, Protobuf, etc). /// /// I originally added compression because message sizes were too big. Now I'm adding packing, /// to solve any issues of binary compatibility across various platforms. // bool OTASCIIArmor::GetAndUnpackString(OTString & strData, bool bLineBreaks) const //bLineBreaks=true { size_t outSize = 0; uint8_t * pData = NULL; strData.Release(); if (GetLength() < 1) { return true; } // -------------------------------------------------------------- pData = OTCrypto::It()->Base64Decode(this->Get(), &outSize, bLineBreaks); // pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0)); if (pData) { std::string str_decoded( pData, pData+outSize ); delete [] pData; pData=NULL; std::string str_uncompressed = decompress_string( str_decoded ); // --------------------------------------- // PUT THE PACKED BUFFER HERE, AND UNPACK INTO strData // -------------------------------------------------------- OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either. OTDB::PackedBuffer * pBuffer = pPacker->CreateBuffer(); // Need to clean this up. OT_ASSERT(NULL != pBuffer); OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // This will make sure buffer is deleted later. pBuffer->SetData(reinterpret_cast<const uint8_t *>(str_uncompressed.data()), str_uncompressed.size()); // ----------------------------- OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING)); OT_ASSERT(NULL != pOTDBString); OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // clean up this string. bool bUnpacked = pPacker->Unpack(*pBuffer, *pOTDBString); // ---------------------- if (false == bUnpacked) { OTLog::Error("Failed unpacking string in OTASCIIArmor::GetAndUnpackString.\n"); return false; } // -------------------------------------------------------- // This enforces the null termination. (using the 2nd parameter as nEnforcedMaxLength) strData.Set(pOTDBString->m_string.c_str(), static_cast<uint32_t> (pOTDBString->m_string.length())); return true; } else { OTLog::Error("OTASCIIArmor::GetAndUnpackString: NULL pData while base64-decoding pData.\n"); return false; } }
const bool GetExecutable(OTString & strExecutablePath) { #ifdef TARGET_OS_MAC char bufPath[PATH_MAX + 1]=""; uint32_t size = sizeof(bufPath); int bufsize = sizeof(bufPath); if (_NSGetExecutablePath(bufPath, &size) == 0) strExecutablePath.Set(bufPath); else return false; #elif defined __linux__ char buff[4096]=""; ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); if (len != -1) { // good buff[len] = '\0'; strExecutablePath.Set(buff); } else { // bad strExecutablePath.Set(""); return false; } #elif defined _WIN32 #ifdef _UNICODE TCHAR bufPath[ _MAX_PATH+1 ] = L""; #else TCHAR bufPath[ _MAX_PATH+1 ] = ""; #endif GetModuleFileName( NULL , bufPath , sizeof(bufPath)/sizeof(TCHAR) ) ; #ifdef UNICODE strExecutablePath.Set(utf8util::UTF8FromUTF16(bufPath)); #else strExecutablePath.Set(bufPath); #endif #else return false; #endif return true; }
const bool OTPaths::FixPath(const OTString & strPath, OTString & out_strFixedPath, const bool & bIsFolder) { if (!strPath.Exists()) { OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strPath" ); OT_ASSERT(false); } std::string l_strPath(strPath.Get()); // first change all back-slashes to forward slashes: std::string l_strPath_noBackslash(OTString::replace_chars(l_strPath,"\\",'/')); // now we make sure we have the correct trailing "/". if ('/' == *l_strPath_noBackslash.rbegin()) { if (bIsFolder) { out_strFixedPath.Set(l_strPath_noBackslash.c_str()); return true; } else { out_strFixedPath.Set(l_strPath_noBackslash.substr(0, l_strPath_noBackslash.size()-1).c_str()); return true; } } else { if (bIsFolder) { l_strPath_noBackslash += "/"; out_strFixedPath.Set(l_strPath_noBackslash.c_str()); return true; } else { out_strFixedPath.Set(l_strPath_noBackslash.c_str()); return true; } } }
// This code reads up the file, discards the bookends, and saves only the gibberish itself. bool OTASCIIArmor::LoadFrom_ifstream(std::ifstream & fin) { std::stringstream buffer; buffer << fin.rdbuf(); std::string contents(buffer.str()); OTString theString; theString.Set(contents.c_str()); return LoadFromString(theString); }
// static // Changes ~/blah to /Users/au/blah // void OTLog::TransformFilePath(const char * szInput, OTString & strOutput) { OT_ASSERT(NULL != szInput); #ifndef _WIN32 // if UNIX (NOT windows) wordexp_t exp_result; if (wordexp(szInput, &exp_result, 0)) { OTLog::Error("OTLog::TransformFilePath: Error calling wordexp() to expand path.\n"); wordfree(&exp_result); strOutput.Set(szInput); return; } // ---------------------------- std::string str_Output(""); // wordexp tokenizes by space (as well as expands, which is why I'm using it.) // Therefore we need to iterate through the tokens, and create a single string // with spaces between the tokens. // for (int i = 0; exp_result.we_wordv[i] != NULL; i++) { str_Output += exp_result.we_wordv[i]; if (exp_result.we_wordv[i+1] != NULL) str_Output += " "; } wordfree(&exp_result); if (str_Output.size() > 0) strOutput.Set(str_Output.c_str()); else strOutput.Set(szInput); #else strOutput.Set(szInput); #endif }
// *********************************************************************** // // INI FILE // bool GetOTAppDataFolderLocation(const OTString & strIniFileDefault, OTString & strOTServerDataLocation) { CSimpleIniA ini; SI_Error rc = ini.LoadFile(strIniFileDefault.Get()); if (rc >=0) { { const char * pVal = ini.GetValue("paths", "prefix_path", OT_PREFIX_DEFAULT); // todo stop hardcoding. if (NULL != pVal) { OTLog::SetPrefixPath(pVal); OTLog::vOutput(0, "server main: Reading ini file (%s). \n Found prefix_path: %s \n", strIniFileDefault.Get(), OTLog::PrefixPath()); } else OTLog::vOutput(0, "server main:Ini file: %s: Failed to find prefix_path. \n", strIniFileDefault.Get()); } { const char * pVal = ini.GetValue("paths", "init_path", OT_FOLDER_DEFAULT); // todo stop hardcoding. if (NULL != pVal) { OTLog::SetConfigPath(pVal); OTLog::vOutput(0, "server main: Reading ini file (%s). \n Found Server init_path: %s \n", strIniFileDefault.Get(), OTLog::ConfigPath()); } else OTLog::vOutput(0, "server main:Ini file: %s: Failed to find init_path. \n", strIniFileDefault.Get()); } { const char * pVal = ini.GetValue("paths", "server_path", SERVER_PATH_DEFAULT); // todo stop hardcoding. if (NULL != pVal) { strOTServerDataLocation.Set(pVal); OTLog::vOutput(0, "server main: Reading ini file (%s). \n Found Server data_folder path: %s \n", strIniFileDefault.Get(), strOTServerDataLocation.Get()); return true; } OTLog::vOutput(0, "server main: Reading ini file (%s) \n", strIniFileDefault.Get()); return false; } } else { OTLog::vOutput(0, "server main: Unable to load ini file (%s) to find data_folder path \n", strIniFileDefault.Get()); return false; } }
const bool OTPaths::GetHomeFromSystem(OTString & out_strHomeFolder) { #ifdef _WIN32 #ifdef _UNICODE TCHAR szPath[MAX_PATH]=L""; #else TCHAR szPath[MAX_PATH]=""; #endif if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, NULL, 0, szPath))) { #ifdef UNICODE out_strHomeFolder.Set(utf8util::UTF8FromUTF16(szPath)); #else out_strHomeFolder.Set(szPath); #endif } else { out_strHomeFolder.Set(""); return false; } #else out_strHomeFolder.Set(getenv("HOME")); #endif return true; }
const bool GetCurrentWorking(OTString & strCurrentWorkingPath) { #ifdef _WIN32 // Windows Common TCHAR * szPath = NULL; #ifdef _UNICODE // Windows Unicode #define GetCurrentDir _wgetcwd #else // Windows No-Unicode #define GetCurrentDir _getcwd #endif #else // Unix #define GetCurrentDir getcwd char * szPath = NULL; #endif // All bool r = ((szPath = GetCurrentDir(NULL,0)) == 0); OT_ASSERT(0 != r); OTString result; #ifdef _WIN32 #ifdef _UNICODE // Windows Unicode strCurrentWorkingPath.Set(utf8util::UTF8FromUTF16(szPath)); #endif #else // Unix strCurrentWorkingPath.Set(szPath); #endif // All return true; }
// --------------------------------------- bool MTRecord::FormatShortMailDescription(std::string & str_output) { OTString strDescription; if (IsMail()) { if (!HasContents()) strDescription.Set("(empty message)"); else { std::string str_temp_contents = GetContents(); std::string str_contents = OTString::trim(str_temp_contents); if (str_contents.compare(0,8,"Subject:") == 0) { // Make the replacement. str_contents.replace(0, 8, ""); } // ----------------------------------- bool bTruncated = false; if (str_contents.size() > 30) { str_contents.erase(30, std::string::npos); bTruncated = true; } // ----------------------------------- // Replace any newlines with spaces... // std::replace( str_contents.begin(), str_contents.end(), '\r', ' '); std::replace( str_contents.begin(), str_contents.end(), '\n', ' '); // str_contents.erase(std::remove(str_contents.begin(), str_contents.end(), '\n'), str_contents.end()); // str_contents.erase(std::remove(str_contents.begin(), str_contents.end(), '\r'), str_contents.end()); // ----------------------------------- strDescription.Format("%s%s", OTString::trim(str_contents).c_str(), bTruncated ? "..." : ""); } } // ----------------------------- str_output = strDescription.Get(); // ----------------------------- return (!str_output.empty()); }
// The Trade always stores the original, signed version of its Offer. // This method allows you to grab a copy of it. inline bool GetOfferString(OTString & strOffer) { strOffer.Set(m_strOffer); return m_strOffer.Exists() ? true : false; }
// Lucre step 3: the mint signs the token // bool OTMint_Lucre::SignToken(OTPseudonym & theNotary, OTToken & theToken, OTString & theOutput, int32_t nTokenIndex) { bool bReturnValue = false; //OTLog::Error("%s <bank file> <coin request> <coin signature> [<signature repeats>]\n", _OT_Lucre_Dumper setDumper; // OTLog::vError("OTMint::SignToken!!\nnTokenIndex: %d\n Denomination: %lld\n", nTokenIndex, theToken.GetDenomination()); OpenSSL_BIO bioBank = BIO_new(BIO_s_mem()); // input OpenSSL_BIO bioRequest = BIO_new(BIO_s_mem()); // input OpenSSL_BIO bioSignature = BIO_new(BIO_s_mem()); // output OTASCIIArmor thePrivate; GetPrivate(thePrivate, theToken.GetDenomination()); // The Mint private info is encrypted in m_mapPrivates[theToken.GetDenomination()]. // So I need to extract that first before I can use it. OTEnvelope theEnvelope(thePrivate); OTString strContents; // output from opening the envelope. // Decrypt the Envelope into strContents if (!theEnvelope.Open(theNotary, strContents)) return false; // copy strContents to a BIO BIO_puts(bioBank, strContents.Get()); // OTLog::vError("BANK CONTENTS:\n%s--------------------------------------\n", strContents.Get()); // Instantiate the Bank with its private key Bank bank(bioBank); // OTLog::vError("BANK INSTANTIATED.--------------------------------------\n"); // I need the request. the prototoken. OTASCIIArmor ascPrototoken; bool bFoundToken = theToken.GetPrototoken(ascPrototoken, nTokenIndex); if (bFoundToken) { // base64-Decode the prototoken OTString strPrototoken(ascPrototoken); // OTLog::vError("\n--------------------------------------\nDEBUG: PROTOTOKEN CONTENTS:\n" // "-----------------%s---------------------\n", strPrototoken.Get() ); // copy strPrototoken to a BIO BIO_puts(bioRequest, strPrototoken.Get()); // Load up the coin request from the bio (the prototoken) PublicCoinRequest req(bioRequest); // OTLog::Error("PROTOTOKEN INSTANTIATED.--------------------------------------\n"); // Sign it with the bank we previously instantiated. // results will be in bnSignature (BIGNUM) BIGNUM * bnSignature = bank.SignRequest(req); if (NULL == bnSignature) { OTLog::Error("MAJOR ERROR!: Bank.SignRequest failed in OTMint_Lucre::SignToken\n"); } else { // OTLog::Error("BANK.SIGNREQUEST SUCCESSFUL.--------------------------------------\n"); // Write the request contents, followed by the signature contents, // to the Signature bio. Then free the BIGNUM. req.WriteBIO(bioSignature); // the original request contents DumpNumber(bioSignature,"signature=", bnSignature); // the new signature contents BN_free(bnSignature); // Read the signature bio into a C-style buffer... char sig_buf[1024]; // todo stop hardcoding these string lengths // memset(sig_buf, 0, 1024); // zero it out. (I had this commented out, but the size was 2048, so maybe it's safe now at 1024.) int32_t sig_len = BIO_read(bioSignature, sig_buf, 1000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. // Add the null terminator by hand (just in case.) sig_buf[sig_len] = '\0'; if (sig_len) { // *********************************************** // OTLog::vError("\n--------------------------------------\n" // "*** Siglen is %d. sig_str_len is %d.\nsig buf:\n------------%s------------\nLAST " // "CHARACTER IS '%c' SECOND TO LAST CHARACTER IS '%c'\n", // sig_len, sig_str_len, sig_buf, sig_buf[sig_str_len-1], sig_buf[sig_str_len-2]); // Copy the original coin request into the spendable field of the token object. // (It won't actually be spendable until the client processes it, though.) theToken.SetSpendable(ascPrototoken); // OTLog::vError("*** SPENDABLE:\n-----------%s---------------------\n", ascPrototoken.Get()); // Base64-encode the signature contents into theToken.m_Signature. OTString strSignature(sig_buf); // strSignature.Set(sig_buf, sig_len-1); // sig_len includes null terminator, whereas Set() adds 1 for it. // OTLog::vError("SIGNATURE:\n--------------------%s" // "------------------\n", strSignature.Get()); // Here we pass the signature back to the caller. // He will probably set it onto the token. theOutput.Set(sig_buf, sig_len); bReturnValue = true; // This is also where we set the expiration date on the token. // The client should have already done this, but we are explicitly // setting the values here to prevent any funny business. theToken.SetSeriesAndExpiration(m_nSeries, m_VALID_FROM, m_VALID_TO); } } } return bReturnValue; }
// The mint has a different key pair for each denomination. // Pass the actual denomination such as 5, 10, 20, 50, 100... bool OTMint_Lucre::AddDenomination(OTPseudonym & theNotary, int64_t lDenomination, int32_t nPrimeLength/*=1024*/) { OT_ASSERT(NULL != m_pKeyPublic); bool bReturnValue = false; // Let's make sure it doesn't already exist OTASCIIArmor theArmor; if (GetPublic(theArmor, lDenomination)) { // it already exists. OTLog::Error("Error: Denomination public already exists in OTMint::AddDenomination\n"); return false; } if (GetPrivate(theArmor, lDenomination)) { // it already exists. OTLog::Error("Error: Denomination private already exists in OTMint::AddDenomination\n"); return false; } // OTLog::Error("%s <size of bank prime in bits> <bank data file> <bank public data file>\n", if ((nPrimeLength/8) < (MIN_COIN_LENGTH+DIGEST_LENGTH)) { OTLog::vError("Prime must be at least %d bits\n", (MIN_COIN_LENGTH+DIGEST_LENGTH)*8); return false; } if (nPrimeLength%8) { OTLog::Error("Prime length must be a multiple of 8\n"); return false; } #ifdef _WIN32 SetMonitor("openssl.dump"); #else SetMonitor(stderr); #endif OpenSSL_BIO bio = BIO_new(BIO_s_mem()); OpenSSL_BIO bioPublic = BIO_new(BIO_s_mem()); // Generate the mint private key information Bank bank(nPrimeLength/8); bank.WriteBIO(bio); // Generate the mint public key information PublicBank pbank(bank); pbank.WriteBIO(bioPublic); // Copy from BIO back to a normal OTString or Ascii-Armor char privateBankBuffer[4096], publicBankBuffer[4096]; // todo stop hardcoding these string lengths int32_t privatebankLen = BIO_read(bio, privateBankBuffer, 4000); // cutting it a little short on purpose, with the buffer. int32_t publicbankLen = BIO_read(bioPublic, publicBankBuffer, 4000); // Just makes me feel more comfortable for some reason. if (privatebankLen && publicbankLen) { // With this, we have the Lucre public and private bank info converted to OTStrings OTString strPublicBank; strPublicBank.Set(publicBankBuffer, publicbankLen); OTString strPrivateBank; strPrivateBank.Set(privateBankBuffer, privatebankLen); OTASCIIArmor * pPublic = new OTASCIIArmor(); OTASCIIArmor * pPrivate = new OTASCIIArmor(); OT_ASSERT(NULL != pPublic); OT_ASSERT(NULL != pPrivate); // Set the public bank info onto pPublic pPublic->SetString(strPublicBank, true); // linebreaks = true // Seal the private bank info up into an encrypted Envelope // and set it onto pPrivate OTEnvelope theEnvelope; theEnvelope.Seal(theNotary, strPrivateBank); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(*pPrivate); // Add the new key pair to the maps, using denomination as the key m_mapPublic[lDenomination] = pPublic; m_mapPrivate[lDenomination] = pPrivate; // Grab the Server Nym ID and save it with this Mint theNotary.GetIdentifier(m_ServerNymID); // --------------------------- // Grab the Server's public key and save it with this Mint // const OTAsymmetricKey & theNotaryPubKey = theNotary.GetPublicSignKey(); delete m_pKeyPublic; m_pKeyPublic = theNotaryPubKey.ClonePubKey(); // --------------------------- m_nDenominationCount++; // --------------------------- // Success! bReturnValue = true; OTLog::vOutput(1, "Successfully added denomination: %lld\n", lDenomination); } return bReturnValue; }
// Lucre step 4: client unblinds token -- now it's ready for use. bool OTToken::ProcessToken(const OTPseudonym & theNym, OTMint & theMint, OTToken & theRequest) { // OTLog::vError("%s <bank public info> <private coin request> <signed coin request> <coin>\n", bool bReturnValue = false; // When the Mint has signed a token and sent it back to the client, // the client must unblind the token and set it as spendable. Thus, // this function is only performed on tokens in the signedToken state. if (OTToken::signedToken != m_State) { OTLog::Error("Signed token expected in OTToken::ProcessToken\n"); return false; } // Lucre SetDumper(stderr); BIO *bioBank = BIO_new(BIO_s_mem()); // input BIO *bioSignature = BIO_new(BIO_s_mem()); // input BIO *bioPrivateRequest = BIO_new(BIO_s_mem()); // input BIO *bioCoin = BIO_new(BIO_s_mem()); // output // Get the bank's public key (decoded into strPublicMint) // and put it into bioBank so we can use it with Lucre. OTASCIIArmor ascPublicMint; theMint.GetPublic(ascPublicMint, GetDenomination()); OTString strPublicMint(ascPublicMint); BIO_puts(bioBank, strPublicMint.Get()); // Get the existing signature into a bio. // OTLog::vError("DEBUGGING, m_Signature: -------------%s--------------\n", m_Signature.Get()); OTString strSignature(m_Signature); BIO_puts(bioSignature, strSignature.Get()); // I need the Private coin request also. (Only the client has this private coin request data.) OTASCIIArmor thePrototoken; // The server sets m_nChosenIndex when it signs the token. bool bFoundToken = theRequest.GetPrivatePrototoken(thePrototoken, m_nChosenIndex); if (bFoundToken) { // OTLog::vError("THE PRIVATE REQUEST ARMORED CONTENTS:\n------------------>%s<-----------------------\n", // thePrototoken.Get()); // Decrypt the prototoken OTString strPrototoken; OTEnvelope theEnvelope(thePrototoken); theEnvelope.Open(theNym, strPrototoken); // todo check return value. // OTLog::vError("THE PRIVATE REQUEST CONTENTS:\n------------------>%s<-----------------------\n", // strPrototoken.Get()); // copy strPrototoken to a BIO BIO_puts(bioPrivateRequest, strPrototoken.Get()); // ------- Okay, the BIOs are all loaded.... let's process... PublicBank bank(bioBank); CoinRequest req(bioPrivateRequest); // TODO make sure I'm not leaking memory with these ReadNumbers // Probably need to be calling some free function for each one. // Apparently reading the request id here and then just discarding it... ReadNumber(bioSignature,"request="); // Versus the signature data, which is read into bnSignature apparently. BIGNUM * bnSignature = ReadNumber(bioSignature,"signature="); DumpNumber("signature=", bnSignature); // Produce the final unblinded token in Coin coin, and write it to bioCoin... Coin coin; // Coin Request, processes into Coin, with Bank and Signature passed in. req.ProcessResponse(&coin, bank, bnSignature); // Notice still apparently "request" info is discarded. coin.WriteBIO(bioCoin); // convert bioCoin to a C-style string... char CoinBuffer[1024]; // todo stop hardcoding these string lengths int coinLen = BIO_read(bioCoin, CoinBuffer, 1000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. if (coinLen) { // ...to OTString... OTString strCoin; strCoin.Set(CoinBuffer, coinLen); // OTLog::vError("Processing token...\n%s\n", strCoin.Get()); // ...to Envelope stored in m_ascSpendable (encrypted and base64-encoded) OTEnvelope theEnvelope; theEnvelope.Seal(theNym, strCoin); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(m_ascSpendable); // Here's the final product. // OTLog::vError("NEW SPENDABLE token...\n--------->%s<----------------\n", m_ascSpendable.Get()); // Now the coin is encrypted from here on out, and otherwise ready-to-spend. m_State = OTToken::spendableToken; bReturnValue = true; // Lastly, we free the signature data, which is no longer needed, and which could be // otherwise used to trace the token. (Which we don't want.) m_Signature.Release(); } } // Todo log error here if the private prototoken is not found. (Very strange if so!!) // else {} // Cleanup openssl resources. BIO_free_all(bioBank); BIO_free_all(bioSignature); BIO_free_all(bioPrivateRequest); BIO_free_all(bioCoin); return bReturnValue; }
bool OTEnvelope::Open(const OTPseudonym & theRecipient, OTString & theContents) { bool retval = false; EVP_CIPHER_CTX ctx; unsigned char buffer[4096]; unsigned char buffer_out[4096 + EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH]; size_t len = 0; int len_out = 0; unsigned char * ek = NULL; int eklen = 0; uint32_t eklen_n = 0; memset(buffer, 0, 4096); memset(buffer_out, 0, 4096 + EVP_MAX_IV_LENGTH); memset(iv, 0, EVP_MAX_IV_LENGTH); OTAsymmetricKey & privateKey = (OTAsymmetricKey &)theRecipient.GetPrivateKey(); EVP_PKEY * pkey = (EVP_PKEY *)privateKey.GetKey(); if (NULL == pkey) { OTLog::Error("Null private key in OTEnvelope::Open\n"); return false; } EVP_CIPHER_CTX_init(&ctx); ek = (unsigned char*)malloc(EVP_PKEY_size(pkey)); // I assume this is for the AES key OT_ASSERT(NULL != ek); memset(ek, 0, EVP_PKEY_size(pkey)); eklen = EVP_PKEY_size(pkey); //int EVP_OpenInit(EVP_CIPHER_CTX *ctx, //EVP_CIPHER *type, //unsigned char *ek, //int ekl, //unsigned char *iv, //EVP_PKEY *priv); //EVP_OpenInit() initializes a cipher context ctx for decryption with cipher type. It decrypts the encrypted // symmetric key of length ekl bytes passed in the ek parameter using the private key priv. The IV is supplied // in the iv parameter. theContents.Release(); // This is where we'll put the decrypted data. m_dataContents.reset(); // reset the fread position on this object. int nReadLength = 0; int nReadKey = 0; int nReadIV = 0; // First we read the encrypted key size. if (0 == (nReadLength = m_dataContents.OTfread((char*)&eklen_n, sizeof(eklen_n)))) { OTLog::Error("Error reading encrypted key size in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } // convert it from network to host endian. eklen = ntohl(eklen_n); // Next we read the encrypted key itself. if (0 == (nReadKey = m_dataContents.OTfread((char*)ek, eklen))) { OTLog::Error("Error reading encrypted key size in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } // Next we read the initialization vector. if (0 == (nReadIV = m_dataContents.OTfread((char*)iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc())))) { OTLog::Error("Error reading initialization vector in OTEnvelope::Open\n"); free(ek); ek = NULL; return false; } OTData ciphertext((const void*)((unsigned char *)m_dataContents.GetPointer() + nReadLength + nReadKey + nReadIV), m_dataContents.GetSize() - nReadLength - nReadKey - nReadIV); // Now we process ciphertext and write the decrypted data to plaintext. OTData plaintext; if (!EVP_OpenInit(&ctx, EVP_aes_128_cbc(), ek, eklen, iv, pkey)) { OTLog::Error("EVP_OpenInit: failed.\n"); free(ek); ek = NULL; return false; } while ((len = ciphertext.OTfread((char*)buffer, sizeof(buffer))) > 0) { if (!EVP_OpenUpdate(&ctx, buffer_out, &len_out, buffer, len)) { OTLog::Error("EVP_OpenUpdate: failed.\n"); free(ek); ek = NULL; return false; } OTData dataOpenUpdate(buffer_out, len_out); plaintext += dataOpenUpdate; } if (!EVP_OpenFinal(&ctx, buffer_out, &len_out)) { OTLog::Error("EVP_OpenFinal: failed.\n"); free(ek); ek = NULL; return false; } OTData dataOpenFinal(buffer_out, len_out); plaintext += dataOpenFinal; // Make sure it's null terminated int nIndex = plaintext.GetSize()-1; ((unsigned char*)plaintext.GetPointer())[nIndex] = 0; // Set it into theContents (to return the plaintext to the caller) theContents.Set((const char *)plaintext.GetPointer()); retval = true; free(ek); ek = NULL; return retval; }
const bool OTPaths::ToReal(const OTString & strExactPath, OTString & out_strCanonicalPath) { if (!strExactPath.Exists()) { OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strExactPath"); OT_ASSERT(false); } #ifdef _WIN32 #ifdef _UNICODE const char * szPath = strExactPath.Get(); size_t newsize = strlen(szPath) + 1; wchar_t * wzPath = new wchar_t[newsize]; size_t convertedChars = 0; mbstowcs_s(&convertedChars, wzPath, newsize, szPath,4096); wchar_t szBuf[4096]= L""; if(GetFullPathName(wzPath,4096,szBuf,NULL)) { out_strCanonicalPath.Set(utf8util::UTF8FromUTF16(szBuf)); return true; } else { out_strCanonicalPath.Set(""); return false; } #else char_t szBuf[4096]=""; char_t const * szPath = strRealPath.Get(); if(GetFullPathName(szPath,4096,szBuf,NULL)) { out_strCanonicalPath.Set(szBuf); return true; } else { out_strCanonicalPath.Set(""); return false; } #endif #else long path_max=0; #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf("/", _PC_PATH_MAX); if (path_max <= 0) path_max = 4096; #endif char actualpath [path_max+1]; actualpath[0] = '\0'; char *ptr=NULL; if (NULL == realpath(strExactPath.Get(), actualpath)) { if (errno == ENOTDIR) { OTLog::vOutput(1,"Input value to RealPath is not a directory: (Realpath: skipping)\n"); out_strCanonicalPath.Set(strExactPath); return true; } if (errno == ENOENT) { OTLog::vOutput(1,"File doesn't exist: (Realpath: skipping)\n"); out_strCanonicalPath.Set(strExactPath); return true; } OT_ASSERT_MSG((errno != EACCES),"Error (Realpath: EACCES): Unable to build RealPath: access denied"); OT_ASSERT_MSG((errno != EINVAL),"Error (RealPath: EINVAL): Input value into RealPath was NULL"); OT_ASSERT_MSG((errno != ELOOP),"Error (RealPath: ELOOP): Resloving links resulted in a loop."); OT_ASSERT_MSG((errno != ENAMETOOLONG),"Error (RealPath: ENAMETOOLONG): Name too long."); OT_ASSERT_MSG((errno != ERANGE),"Error (RealPath: ERANGE): Resulting path is too long for the buffer"); OT_ASSERT_MSG((errno != EIO),"Error (RealPath: EIO): Unable to access path."); OT_ASSERT_MSG((false),"Error (RealPath: OTHER): Something bad Happend with 'realpath'."); } out_strCanonicalPath.Set(actualpath); return true; #endif }
//static std::string OTAssetContract::formatLongAmount(int64_t & lOriginalValue, int32_t nFactor/*=100*/, int32_t nPower/*=2*/, const char * szSymbol/*=""*/, const char * szSeparator/*=","*/, const char * szDecimalPoint/*="."*/) { std::stringstream sss; OTString strRemainder; // -------------------------------------------------- // If the original value is 0, we still want to format the // string properly for a 0 value. (And then return.) // if (0 == lOriginalValue) { sss << szSymbol << " "; // Currency symbol if (!(nFactor < 2)) { sss << szDecimalPoint; strRemainder.Format("%0*ld", nPower, 0); } else strRemainder.Format("%lld", 0); sss << strRemainder.Get(); return sss.str(); } // -------------------------------------------------- int64_t lAbsoluteValue = (lOriginalValue > 0) ? lOriginalValue : (lOriginalValue * (-1)); // -------------------------------------------------- int64_t lValue = lAbsoluteValue / nFactor; // For example, if 506 is supposed to be $5.06, then dividing 506 by factor of 100 results in 5 dollars. int64_t lRemainder = lAbsoluteValue % nFactor; // For example, if 506 is supposed to be $5.06, then 506 mod 100 results in 6 cents. if (nFactor < 2) // Basically, if nFactor is 1. strRemainder.Set(""); else strRemainder.Format("%0*ld", nPower, lRemainder); // If remainder is 6 (cents) and nPower is 2, strRemainder gets set here to 06. // ------------------------------------------------------ // Here we add the negative sign, if the value itself is negative. // if (lOriginalValue < 0) { // const std::moneypunct<char, false> &mp = std::use_facet< std::moneypunct<char, false> >(std::locale ()); // sss << mp.negative_sign(); // For some reason the above code isn't working, so I've got the negative sign // hardcoded here to '-'. // sss << "-"; } // ------------------------------------------------------ // Here we add the currency symbol. // sss << szSymbol << " "; // Currency symbol // ------------------------------------------------------ OTString strValue; strValue.Format("%lld", lValue); // --------------------------------- char cTemp = '\0'; uint32_t uValueStrLength = strValue.GetLength(); // --------------------------------- // Here we add the main body of the amount, including separators (commas.) // while (uValueStrLength > 0) { cTemp = strValue.sgetc(); sss << cTemp; --uValueStrLength; if ((uValueStrLength > 0) && (0 == (uValueStrLength % 3))) sss << szSeparator; } // ------------------------------------------------------ // Here we deal with the decimal point, etc. // if (!(nFactor < 2)) { sss << szDecimalPoint; // ----------------------------- sss << strRemainder.Get(); } // ----------------------------- return sss.str(); }
void OTToken::UpdateContents() { if (m_State == OTToken::spendableToken) m_strContractType.Set("CASH"); OTString ASSET_TYPE_ID(m_AssetTypeID), SERVER_ID(m_ServerID); OTString strState; switch (m_State) { case OTToken::blankToken: strState.Set("blankToken"); break; case OTToken::protoToken: strState.Set("protoToken"); break; case OTToken::signedToken: strState.Set("signedToken"); break; case OTToken::spendableToken: strState.Set("spendableToken"); break; case OTToken::verifiedToken: strState.Set("verifiedToken"); break; default: strState.Set("errorToken"); break; } long lFrom = m_VALID_FROM, lTo = m_VALID_TO; // I release this because I'm about to repopulate it. m_xmlUnsigned.Release(); m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n\n", "1.0"); m_xmlUnsigned.Concatenate("<token\n version=\"%s\"\n state=\"%s\"\n denomination=\"%ld\"\n" " assetTypeID=\"%s\"\n" " serverID=\"%s\"\n" " series=\"%d\"\n" " validFrom=\"%ld\"\n" " validTo=\"%ld\"" " >\n\n", m_strVersion.Get(), strState.Get(), GetDenomination(), ASSET_TYPE_ID.Get(), SERVER_ID.Get(), m_nSeries, lFrom, lTo ); // signed tokens, as well as spendable tokens, both carry a TokenID // (The spendable token contains the unblinded version.) if (OTToken::signedToken == m_State || OTToken::spendableToken == m_State) { m_xmlUnsigned.Concatenate("<tokenID>\n%s</tokenID>\n\n", m_ascSpendable.Get()); } // Only signedTokens carry the signature, which is discarded in spendable tokens. // (Because it is not used past the unblinding stage anyway, and because it could // be used to track the token.) if (OTToken::signedToken == m_State) { m_xmlUnsigned.Concatenate("<tokenSignature>\n%s</tokenSignature>\n\n", m_Signature.Get()); } if ((OTToken::protoToken == m_State || OTToken::signedToken == m_State) && m_nTokenCount) { m_xmlUnsigned.Concatenate("<protopurse count=\"%d\" chosenIndex=\"%d\">\n\n", m_nTokenCount, m_nChosenIndex); OTASCIIArmor * pPrototoken = NULL; for (mapOfPrototokens::iterator ii = m_mapPublic.begin(); ii != m_mapPublic.end(); ++ii) { pPrototoken = (*ii).second; OT_ASSERT(NULL != pPrototoken); m_xmlUnsigned.Concatenate("<prototoken>\n%s</prototoken>\n\n", pPrototoken->Get()); } m_xmlUnsigned.Concatenate("</protopurse>\n\n"); } if (m_bSavePrivateKeys) { m_bSavePrivateKeys = false; // set it back to false; m_xmlUnsigned.Concatenate("<privateProtopurse>\n\n"); OTASCIIArmor * pPrototoken = NULL; for (mapOfPrototokens::iterator ii = m_mapPrivate.begin(); ii != m_mapPrivate.end(); ++ii) { pPrototoken = (*ii).second; OT_ASSERT(NULL != pPrototoken); m_xmlUnsigned.Concatenate("<privatePrototoken>\n%s</privatePrototoken>\n\n", pPrototoken->Get()); } m_xmlUnsigned.Concatenate("</privateProtopurse>\n\n"); } m_xmlUnsigned.Concatenate("</token>\n"); }
bool OTASCIIArmor::GetString(OTString & theData, bool bLineBreaks) const //bLineBreaks=true { return GetAndUnpackString(theData, bLineBreaks); size_t outSize = 0; uint8_t * pData = NULL; theData.Release(); if (GetLength() < 1) { return true; } pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0)); if (pData) { long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.) unsigned char* pDest = new unsigned char [nDestLen+10]; // For safety. OT_ASSERT(NULL != pDest); int nErr = ezuncompress( pDest, &nDestLen, pData, outSize ); if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = new unsigned char [nDestLen]; // enough room now OT_ASSERT(NULL != pDest); nErr = ezuncompress( pDest, &nDestLen, pData, outSize ); } // Now we're done with this memory, let's free it. delete [] pData; pData=NULL; // ---------------------------------------- if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Buffer error in OTASCIIArmor::GetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_STREAM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "pDest is NULL in OTASCIIArmor::GetString\n"); return false; // not really necessary but just making sure. } else if ( nErr == EZ_DATA_ERROR ) { delete [] pDest; pDest = NULL; OTLog::vError("corrupted pSrc passed to ezuncompress OTASCIIArmor::GetString, size: %d\n", outSize); OT_ASSERT(false); return false; // not really necessary but just making sure. } else if ( nErr == EZ_MEM_ERROR ) { delete [] pDest; pDest = NULL; OT_ASSERT_MSG(false, "Out of memory in OTASCIIArmor::GetString\n"); return false; // not really necessary but just making sure. } // This enforces the null termination. (using the extra parameter nDestLen as nEnforcedMaxLength) theData.Set((const char*)pDest, nDestLen); delete [] pDest; pDest=NULL; return true; } else { OTLog::Error("NULL pData while base64_decodeing pData.\n"); return false; } }
// Lucre step 2 (client generates coin request) // nDenomination must be one of the denominations supported by the mint. // sets m_nTokenCount and populates the maps with prototokens (in ASCII-armored format.) bool OTToken::GenerateTokenRequest(const OTPseudonym & theNym, OTMint & theMint, long lDenomination, int nTokenCount/*=OTToken::nMinimumPrototokenCount*/) { // OTLog::vError("%s <bank public info> <coin request private output file> <coin request public output file>\n", argv[0]); if (OTToken::blankToken != m_State) { OTLog::Error("Blank token expected in OTToken::GenerateTokenRequest\n"); return false; } // We are supposed to set these values here. // The server actually sets them again, for security reasons. // But we should still set them since server may choose to reject the request. SetSeriesAndExpiration(theMint.GetSeries(), theMint.GetValidFrom(), theMint.GetValidTo()); SetDumper(stderr); BIO *bioBank = BIO_new(BIO_s_mem()); // Input. We must supply the bank's public lucre info BIO *bioCoin = BIO_new(BIO_s_mem()); // These two are output. We must write these bios, after BIO *bioPublicCoin = BIO_new(BIO_s_mem()); // the operation, back into some form we can use // This version base64-DECODES the ascii-armored string passed in, // and then sets the decoded plaintext string onto the string. //OTString::OTString(const OTASCIIArmor & strValue) OTASCIIArmor ascPublicMint; theMint.GetPublic(ascPublicMint, lDenomination); // OTLog::vError("DEBUG: OTToken public asc: \n%s\n", ascPublicMint.Get()); OTString strPublicMint(ascPublicMint); // OTLog::vError("DEBUG: OTToken public str: \n%s\n", strPublicMint.Get()); // Get the bank's public key (now decoded in strPublicMint) // and put it into bioBank so we can use it with Lucre. BIO_puts(bioBank, strPublicMint.Get()); // Instantiate a PublicBank (Lucre) object. // We will use it to generate all the prototokens in the loop below. PublicBank bank; bank.ReadBIO(bioBank); Release(); const int nFinalTokenCount = (nTokenCount < OTToken::nMinimumPrototokenCount) ? OTToken::nMinimumPrototokenCount : nTokenCount; // Token count is actually 1 (always) with Lucre, although this lib has potential to work with // multiple proto-tokens, you can see this loop as though it always executes just once. for (int i = 0; i < nFinalTokenCount; i++) { CoinRequest req(bank); // write the private coin request to BIO req.WriteBIO(bioCoin); // write the public coin request to BIO ((PublicCoinRequest *)&req)->WriteBIO(bioPublicCoin); // Convert the two bios to our format char privateCoinBuffer[4096], publicCoinBuffer[4096]; // todo stop hardcoding these string lengths int privatecoinLen = BIO_read(bioCoin, privateCoinBuffer, 4000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. int publiccoinLen = BIO_read(bioPublicCoin, publicCoinBuffer, 4000); if (privatecoinLen && publiccoinLen) { // With this, we have the Lucre public and private bank info converted to OTStrings OTString strPublicCoin; strPublicCoin.Set(publicCoinBuffer, publiccoinLen); OTString strPrivateCoin; strPrivateCoin.Set(privateCoinBuffer, privatecoinLen); OTASCIIArmor * pArmoredPublic = new OTASCIIArmor(strPublicCoin); OTASCIIArmor * pArmoredPrivate = new OTASCIIArmor(); OT_ASSERT_MSG(((NULL != pArmoredPublic) && (NULL != pArmoredPrivate)), "ERROR: Unable to allocate memory in OTToken::GenerateTokenRequest\n"); // Change the state. It's no longer a blank token, but a prototoken. m_State = OTToken::protoToken; // Seal the private coin info up into an encrypted Envelope // and set it onto pArmoredPrivate (which was just added to our internal map, above.) OTEnvelope theEnvelope; theEnvelope.Seal(theNym, strPrivateCoin); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(*pArmoredPrivate); m_mapPublic[i] = pArmoredPublic; m_mapPrivate[i] = pArmoredPrivate; m_nTokenCount = nFinalTokenCount; SetDenomination(lDenomination); } else { // Error condition } // Free the Private and Public coins and allocate them fresh, for the next iteration of the loop. BIO_free_all(bioCoin); BIO_free_all(bioPublicCoin); bioCoin = BIO_new(BIO_s_mem()); bioPublicCoin = BIO_new(BIO_s_mem()); } // Cleanup openssl resources. BIO_free_all(bioBank); BIO_free_all(bioCoin); BIO_free_all(bioPublicCoin); return true; }
/// if we pack, compress, encode on the way in, that means, therefore, we /// need to decode, uncompress, then unpack on our way out. Right? /// /// This function will base64-DECODE the string contents, then uncompress them using /// zlib, and then unpack the result using whatever is the default packer (MsgPack, Protobuf, etc). /// /// I originally added compression because message sizes were too big. Now I'm adding packing, /// to solve any issues of binary compatibility across various platforms. // bool OTASCIIArmor::GetAndUnpackString(OTString & strData, bool bLineBreaks) const //bLineBreaks=true { size_t outSize = 0; uint8_t * pData = NULL; strData.Release(); if (GetLength() < 1) { return true; } // -------------------------------------------------------------- pData = OTCrypto::It()->Base64Decode(this->Get(), &outSize, bLineBreaks); // pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0)); if (pData) { // ------------------------------------------- // EASY ZLIB // long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.) unsigned char* pDest = new unsigned char [nDestLen+10]; // For safety. OT_ASSERT(NULL != pDest); int nErr = ezuncompress( pDest, &nDestLen, pData, static_cast<long> (outSize) ); if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = new unsigned char [nDestLen]; // enough room now OT_ASSERT(NULL != pDest); nErr = ezuncompress( pDest, &nDestLen, pData, static_cast<long> (outSize) ); } // Now we're done with this memory, let's free it. delete [] pData; pData=NULL; // ---------------------------------------- if ( nErr == EZ_BUF_ERROR ) { delete [] pDest; pDest = NULL; OT_FAIL_MSG("Buffer error in OTASCIIArmor::GetAndUnpackString\n"); } else if ( nErr == EZ_STREAM_ERROR ) { delete [] pDest; pDest = NULL; OT_FAIL_MSG("pDest is NULL in OTASCIIArmor::GetAndUnpackString\n"); } else if ( nErr == EZ_DATA_ERROR ) { delete [] pDest; pDest = NULL; OTLog::vError("corrupted pSrc passed to ezuncompress OTASCIIArmor::GetAndUnpackString, size: %d\n", outSize); OT_FAIL; } else if ( nErr == EZ_MEM_ERROR ) { delete [] pDest; pDest = NULL; OT_FAIL_MSG("Out of memory in OTASCIIArmor::GetAndUnpackString\n"); } // --------------------------------------- // PUT THE PACKED BUFFER HERE, AND UNPACK INTO strData // -------------------------------------------------------- OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either. OTDB::PackedBuffer * pBuffer = pPacker->CreateBuffer(); // Need to clean this up. OT_ASSERT(NULL != pBuffer); OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // This will make sure buffer is deleted later. const size_t theDestLen = nDestLen; pBuffer->SetData(pDest, // const unsigned char * theDestLen); delete [] pDest; pDest=NULL; // ----------------------------- OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING)); OT_ASSERT(NULL != pOTDBString); OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // clean up this string. bool bUnpacked = pPacker->Unpack(*pBuffer, *pOTDBString); // ---------------------- if (false == bUnpacked) { OTLog::Error("Failed unpacking string in OTASCIIArmor::GetAndUnpackString.\n"); return false; } // -------------------------------------------------------- // This enforces the null termination. (using the 2nd parameter as nEnforcedMaxLength) strData.Set(pOTDBString->m_string.c_str(), static_cast<uint32_t> (pOTDBString->m_string.length())); return true; } else { OTLog::Error("OTASCIIArmor::GetAndUnpackString: NULL pData while base64-decoding pData.\n"); return false; } }
int main (int argc, char **argv) { OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Client -- version %s\n" "(transport build: OTMessage -> TCP -> SSL)\n" "IF YOU PREFER TO USE ZMQ (message based), then rebuild from main folder like this:\n" "cd ..; make clean; make\n\n", OTLog::Version()); OT_API::InitOTAPI(); // ----------------------------------------------------------------------- // The beginnings of an INI file!! OTString strPath; { CSimpleIniA ini; // We're assuming this file is on the path. SI_Error rc = ini.LoadFile("./.ot_ini"); // todo: stop hardcoding. if (rc >=0) { const char * pVal = ini.GetValue("paths", "client_path", SERVER_PATH_DEFAULT); // todo stop hardcoding. if (NULL != pVal) strPath.Set(pVal); else strPath.Set(SERVER_PATH_DEFAULT); } else { strPath.Set(SERVER_PATH_DEFAULT); } } // ----------------------------------------------------------------------- OTString strCAFile, strKeyFile, strSSLPassword; if (argc < 2) { OTLog::vOutput(0, "\n==> USAGE: %s <SSL-password> <absolute_path_to_data_folder>\n\n" #if defined (FELLOW_TRAVELER) "(Password defaults to '%s' if left blank.)\n" "(Folder defaults to '%s' if left blank.)\n" #else "(The test password is always 'test'.\n'cd data_folder' then 'pwd' to see the absolute path.)\n" #endif "\n\n", argv[0] #if defined (FELLOW_TRAVELER) , KEY_PASSWORD, strPath.Get() #endif ); #if defined (FELLOW_TRAVELER) strSSLPassword.Set(KEY_PASSWORD); OTString strClientPath(strPath.Get()); g_OT_API.Init(strClientPath); // SSL gets initialized in here, before any keys are loaded. #else exit(1); #endif } else if (argc < 3) { OTLog::vOutput(0, "\n==> USAGE: %s <SSL-password> <absolute_path_to_data_folder>\n\n" #if defined (FELLOW_TRAVELER) "(Folder defaults to '%s' if left blank.)\n" #endif "\n\n", argv[0] #if defined (FELLOW_TRAVELER) , strPath.Get() #endif ); #if defined (FELLOW_TRAVELER) strSSLPassword.Set(argv[1]); OTString strClientPath(strPath.Get()); g_OT_API.Init(strClientPath); // SSL gets initialized in here, before any keys are loaded. #else exit(1); #endif } else { strSSLPassword.Set(argv[1]); OTString strClientPath(argv[2]); g_OT_API.Init(strClientPath); // SSL gets initialized in here, before any keys are loaded. } OTLog::vOutput::(0, "Using as path to data folder: %s\n", OTLog::Path()); strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE); strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE); // ------------------------------------------------------------------------------ // // Basically, loop: // // 1) Present a prompt, and get a user string of input. Wait for that. // // 2) Process it out as an OTMessage to the server. It goes down the pipe. // // 3) Sleep for 1 second. // // 4) Awake and check for messages to be read in response from the server. // Loop. As long as there are any responses there, then process and handle // them all. // Then continue back up to the prompt at step (1). char buf[200] = ""; int retVal = 0; int nExpectResponse = 0; OTLog::Output(0, "You may wish to 'load' then 'connect' then 'stat'.\n"); OTLog::vOutput(4, "Starting client loop. u_header size in C code is %d.\n", OT_CMD_HEADER_SIZE); for(;;) { buf[0] = 0; // Making it fresh again. nExpectResponse = 0; // 1) Present a prompt, and get a user string of input. Wait for that. OTLog::Output(0, "\nWallet> "); if (NULL == fgets(buf, sizeof(buf)-10, stdin)) // Leaving myself 10 extra bytes at the end for safety's sake. break; OTLog::Output(0, ".\n..\n...\n....\n.....\n......\n.......\n........\n.........\n..........\n" "...........\n............\n.............\n"); // so we can process the user input std::string strLine = buf; // 1.5 The one command that doesn't involve a message to the server (so far) // is the command to load the wallet from disk (which we do before we can // do anything else.) That and maybe the message to CONNECT to the server. // Load wallet.xml if (strLine.compare(0,4,"load") == 0) { OTLog::Output(0, "User has instructed to load wallet.xml...\n"); g_OT_API.GetWallet()->LoadWallet("wallet.xml"); // g_OT_API.GetWallet()->SaveWallet("NEWwallet.xml"); // todo remove this test code. continue; } else if (strLine.compare(0,5,"clear") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available. Try 'load'.\n"); continue; } g_pTemporaryNym->RemoveAllNumbers(); g_pTemporaryNym->SaveSignedNymfile(*g_pTemporaryNym); OTLog::Output(0, "Successfully removed all issued and transaction numbers. Saving nym...\n"); continue; } else if (strLine.compare(0,7,"payment") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to sign the payment plan with. Try 'load'.\n"); continue; } OTLog::Output(0, "Enter your Asset Account ID that the payments will come from: "); OTString strTemp; strTemp.OTfgets(std::cin); const OTIdentifier ACCOUNT_ID(strTemp), USER_ID(*g_pTemporaryNym); OTAccount * pAccount = g_OT_API.GetWallet()->GetAccount(ACCOUNT_ID); if (NULL == pAccount) { OTLog::Output(0, "That account isn't loaded right now. Try 'load'.\n"); continue; } // To write a payment plan, like a cheque, we need to burn one of our transaction numbers. (Presumably // the wallet is also storing a couple of these, since they are needed to perform any transaction.) // // I don't have to contact the server to write a payment plan -- as long as I already have a transaction // number I can use to write it. Otherwise I'd have to ask the server to send me one first. OTString strServerID(pAccount->GetRealServerID()); long lTransactionNumber=0; if (false == g_pTemporaryNym->GetNextTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber)) { OTLog::Output(0, "Payment Plans are written offline, but you still need a transaction number\n" "(and you have none, currently.) Try using 'n' to request another transaction number.\n"); continue; } // ----------------------------------------------------------------------- OTString str_RECIPIENT_USER_ID, str_RECIPIENT_ACCT_ID, strConsideration; // Get the Recipient Nym ID OTLog::Output(0, "Enter the Recipient's User ID (NymID): "); str_RECIPIENT_USER_ID.OTfgets(std::cin); // THEN GET AN ACCOUNT ID in that same asset type OTLog::Output(0, "Enter the Recipient's ACCOUNT ID (of the same asset type as your account): "); str_RECIPIENT_ACCT_ID.OTfgets(std::cin); OTLog::Output(0, "Enter a memo describing consideration for the payment plan: "); strConsideration.OTfgets(std::cin); const OTIdentifier RECIPIENT_USER_ID(str_RECIPIENT_USER_ID), RECIPIENT_ACCT_ID(str_RECIPIENT_ACCT_ID); OTPaymentPlan thePlan(pAccount->GetRealServerID(), pAccount->GetAssetTypeID(), pAccount->GetRealAccountID(), pAccount->GetUserID(), RECIPIENT_ACCT_ID, RECIPIENT_USER_ID); // ----------------------------------------------------------------------- // Valid date range (in seconds) OTLog::Output(0, " 6 minutes == 360 Seconds\n" "10 minutes == 600 Seconds\n" "1 hour == 3600 Seconds\n" "1 day == 86400 Seconds\n" "30 days == 2592000 Seconds\n" "3 months == 7776000 Seconds\n" "6 months == 15552000 Seconds\n\n" ); long lExpirationInSeconds = 86400; OTLog::vOutput(0, "How many seconds before payment plan expires? (defaults to 1 day: %ld): ", lExpirationInSeconds); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 1) lExpirationInSeconds = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t VALID_FROM = time(NULL); // This time is set to TODAY NOW OTLog::vOutput(0, "Payment plan becomes valid for processing STARTING date\n" "(defaults to now, in seconds) [%ld]: ", VALID_FROM); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 2) VALID_FROM = atol(strTemp.Get()); const time_t VALID_TO = VALID_FROM + lExpirationInSeconds; // now + 86400 // ----------------------------------------------------------------------- bool bSuccessSetAgreement = thePlan.SetAgreement(lTransactionNumber, strConsideration, VALID_FROM, VALID_TO); if (!bSuccessSetAgreement) { OTLog::Output(0, "Failed trying to set the agreement!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true continue; } bool bSuccessSetInitialPayment = true; // the default, in case user chooses not to even have this payment. bool bSuccessSetPaymentPlan = true; // the default, in case user chooses not to have a payment plan // ----------------------------------------------------------------------- OTLog::Output(0, "What is the Initial Payment Amount, if any? [0]: "); strTemp.Release(); strTemp.OTfgets(std::cin); long lInitialPayment = atol(strTemp.Get()); if (lInitialPayment > 0) { time_t PAYMENT_DELAY = 60; // 60 seconds. OTLog::vOutput(0, "From the Start Date forward, how long until the Initial Payment should charge?\n" "(defaults to one minute, in seconds) [%d]: ", PAYMENT_DELAY); strTemp.Release(); strTemp.OTfgets(std::cin); if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0) PAYMENT_DELAY = atol(strTemp.Get()); // ----------------------------------------------------------------------- bSuccessSetInitialPayment = thePlan.SetInitialPayment(lInitialPayment, PAYMENT_DELAY); } if (!bSuccessSetInitialPayment) { OTLog::Output(0, "Failed trying to set the initial payment!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true continue; } // ----------------------------------------------------------------------- OTLog::Output(0, "What is the regular payment amount, if any? [0]: "); strTemp.Release(); strTemp.OTfgets(std::cin); long lRegularPayment = atol(strTemp.Get()); if (lRegularPayment > 0) // If there are regular payments. { // ----------------------------------------------------------------------- time_t PAYMENT_DELAY = 120; // 120 seconds. OTLog::vOutput(0, "From the Start Date forward, how long until the Regular Payments start?\n" "(defaults to two minutes, in seconds) [%d]: ", PAYMENT_DELAY); strTemp.Release(); strTemp.OTfgets(std::cin); if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0) PAYMENT_DELAY = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t PAYMENT_PERIOD = 30; // 30 seconds. OTLog::vOutput(0, "Once payments begin, how much time should elapse between each payment?\n" "(defaults to thirty seconds) [%d]: ", PAYMENT_PERIOD); strTemp.Release(); strTemp.OTfgets(std::cin); if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0) PAYMENT_PERIOD = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t PLAN_LENGTH = 0; // 0 seconds (for no max length). OTLog::vOutput(0, "From start date, do you want the plan to expire after a certain maximum time?\n" "(defaults to 0 for no) [%d]: ", PLAN_LENGTH); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 1) PLAN_LENGTH = atol(strTemp.Get()); // ----------------------------------------------------------------------- OTLog::Output(0, "Should there be some maximum number of payments? (Zero for no maximum.) [0]: "); strTemp.Release(); strTemp.OTfgets(std::cin); int nMaxPayments = atoi(strTemp.Get()); bSuccessSetPaymentPlan = thePlan.SetPaymentPlan(lRegularPayment, PAYMENT_DELAY, PAYMENT_PERIOD, PLAN_LENGTH, nMaxPayments); } if (!bSuccessSetPaymentPlan) { OTLog::Output(0, "Failed trying to set the payment plan!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true continue; } thePlan.SignContract(*g_pTemporaryNym); thePlan.SaveContract(); OTString strPlan(thePlan); OTLog::vOutput(0, "\n\n(Make sure Both Parties sign the payment plan before submitting to server):\n\n\n%s\n", strPlan.Get()); continue; } else if (strLine.compare(0,6,"cheque") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to sign the cheque with. Try 'load'.\n"); continue; } OTLog::Output(0, "Enter the ID for your Asset Account that the cheque will be drawn on: "); OTString strTemp; strTemp.OTfgets(std::cin); const OTIdentifier ACCOUNT_ID(strTemp), USER_ID(*g_pTemporaryNym); OTAccount * pAccount = g_OT_API.GetWallet()->GetAccount(ACCOUNT_ID); if (NULL == pAccount) { OTLog::Output(0, "That account isn't loaded right now. Try 'load'.\n"); continue; } // To write a cheque, we need to burn one of our transaction numbers. (Presumably the wallet // is also storing a couple of these, since they are needed to perform any transaction.) // // I don't have to contact the server to write a cheque -- as long as I already have a transaction // number I can use to write it. Otherwise I'd have to ask the server to send me one first. OTString strServerID(pAccount->GetRealServerID()); long lTransactionNumber=0; if (false == g_pTemporaryNym->GetNextTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber)) { OTLog::Output(0, "Cheques are written offline, but you still need a transaction number\n" "(and you have none, currently.) Try using 'n' to request another transaction number.\n"); continue; } OTCheque theCheque(pAccount->GetRealServerID(), pAccount->GetAssetTypeID()); // Recipient OTLog::Output(0, "Enter a User ID for the recipient of this cheque (defaults to blank): "); OTString strRecipientUserID; strRecipientUserID.OTfgets(std::cin); const OTIdentifier RECIPIENT_USER_ID(strRecipientUserID.Get()); // Amount OTLog::Output(0, "Enter an amount: "); strTemp.Release(); strTemp.OTfgets(std::cin); const long lAmount = atol(strTemp.Get()); // ----------------------------------------------------------------------- // Memo OTLog::Output(0, "Enter a memo for your check: "); OTString strChequeMemo; strChequeMemo.OTfgets(std::cin); // ----------------------------------------------------------------------- // Valid date range (in seconds) OTLog::Output(0, " 6 minutes == 360 Seconds\n" "10 minutes == 600 Seconds\n" "1 hour == 3600 Seconds\n" "1 day == 86400 Seconds\n" "30 days == 2592000 Seconds\n" "3 months == 7776000 Seconds\n" "6 months == 15552000 Seconds\n\n" ); long lExpirationInSeconds = 3600; OTLog::vOutput(0, "How many seconds before cheque expires? (defaults to 1 hour: %ld): ", lExpirationInSeconds); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 1) lExpirationInSeconds = atol(strTemp.Get()); // ----------------------------------------------------------------------- time_t VALID_FROM = time(NULL); // This time is set to TODAY NOW OTLog::vOutput(0, "Cheque may be cashed STARTING date (defaults to now, in seconds) [%ld]: ", VALID_FROM); strTemp.Release(); strTemp.OTfgets(std::cin); if (strTemp.GetLength() > 2) VALID_FROM = atol(strTemp.Get()); const time_t VALID_TO = VALID_FROM + lExpirationInSeconds; // now + 3600 // ----------------------------------------------------------------------- bool bIssueCheque = theCheque.IssueCheque(lAmount, lTransactionNumber, VALID_FROM, VALID_TO, ACCOUNT_ID, USER_ID, strChequeMemo, (strRecipientUserID.GetLength() > 2) ? &(RECIPIENT_USER_ID) : NULL); if (bIssueCheque) { theCheque.SignContract(*g_pTemporaryNym); theCheque.SaveContract(); OTString strCheque(theCheque); OTLog::vOutput(0, "\n\nOUTPUT:\n\n\n%s\n", strCheque.Get()); } else { OTLog::Output(0, "Failed trying to issue the cheque!\n"); // IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS. g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true } continue; } else if (strLine.compare(0,7,"decrypt") == 0) { if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to decrypt with.\n"); continue; } OTLog::Output(0, "Enter text to be decrypted:\n> "); OTASCIIArmor theArmoredText; char decode_buffer[200]; // Safe since we only read sizeof - 1 do { decode_buffer[0] = 0; if (NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) { theArmoredText.Concatenate("%s\n", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (strlen(decode_buffer)>1); OTEnvelope theEnvelope(theArmoredText); OTString strDecodedText; theEnvelope.Open(*g_pTemporaryNym, strDecodedText); OTLog::vOutput(0, "\n\nDECRYPTED TEXT:\n\n%s\n\n", strDecodedText.Get()); continue; } else if (strLine.compare(0,6,"decode") == 0) { OTLog::Output(0, "Enter text to be decoded:\n> "); OTASCIIArmor theArmoredText; char decode_buffer[200]; // Safe since we only read sizeof - 1. do { decode_buffer[0] = 0; if (NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) { theArmoredText.Concatenate("%s\n", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (strlen(decode_buffer)>1); OTString strDecodedText(theArmoredText); OTLog::vOutput(0, "\n\nDECODED TEXT:\n\n%s\n\n", strDecodedText.Get()); continue; } else if (strLine.compare(0,6,"encode") == 0) { OTLog::Output(0, "Enter text to be ascii-encoded (terminate with ~ on a new line):\n> "); OTString strDecodedText; char decode_buffer[200]; // Safe since we only read sizeof - 1. do { decode_buffer[0] = 0; if ((NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) && (decode_buffer[0] != '~')) { strDecodedText.Concatenate("%s", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (decode_buffer[0] != '~'); OTASCIIArmor theArmoredText(strDecodedText); OTLog::vOutput(0, "\n\nENCODED TEXT:\n\n%s\n\n", theArmoredText.Get()); continue; } else if (strLine.compare(0,4,"hash") == 0) { OTLog::Output(0, "Enter text to be hashed (terminate with ~ on a new line):\n> "); OTString strDecodedText; char decode_buffer[200]; // Safe since we only read sizeof - 1. do { decode_buffer[0] = 0; if ((NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) && (decode_buffer[0] != '~')) { strDecodedText.Concatenate("%s\n", decode_buffer); OTLog::Output(0, "> "); } else { break; } } while (decode_buffer[0] != '~'); OTIdentifier theIdentifier; theIdentifier.CalculateDigest(strDecodedText); OTString strHash(theIdentifier); OTLog::vOutput(0, "\n\nMESSAGE DIGEST:\n\n%s\n\n", strHash.Get()); continue; } else if (strLine.compare(0,4,"stat") == 0) { OTLog::Output(0, "User has instructed to display wallet contents...\n"); OTString strStat; g_OT_API.GetWallet()->DisplayStatistics(strStat); OTLog::vOutput(0, "%s\n", strStat.Get()); continue; } else if (strLine.compare(0,4,"help") == 0) { OTLog::Output(0, "User has instructed to display the help file...\n"); system("more ../docs/CLIENT-COMMANDS.txt"); continue; } else if (strLine.compare(0,4,"quit") == 0) { OTLog::Output(0, "User has instructed to exit the wallet...\n"); break; } // 1.6 Connect to the first server in the wallet. (assuming it loaded a server contract.) else if (strLine.compare(0,7,"connect") == 0) { OTLog::Output(0, "User has instructed to connect to the first server available in the wallet.\n"); if (NULL == g_pTemporaryNym) { OTLog::Output(0, "No Nym yet available to connect with. Try 'load'.\n"); continue; } // Wallet, after loading, should contain a list of server // contracts. Let's pull the hostname and port out of // the first contract, and connect to that server. bool bConnected = g_OT_API.GetClient()->ConnectToTheFirstServerOnList(*g_pTemporaryNym, strCAFile, strKeyFile, strSSLPassword); if (bConnected) OTLog::Output(0, "Success. (Connected to the first notary server on your wallet's list.)\n"); else { OTLog::Output(0, "Either the wallet is not loaded, or there was an error connecting to server.\n"); } continue; } if (!g_OT_API.GetClient()->IsConnected()) { OTLog::Output(0, "(You are not connected to a notary server--you cannot send commands.)\n"); continue; } // 2) Process it out as an OTMessage to the server. It goes down the pipe. g_OT_API.GetClient()->ProcessMessageOut(buf, &nExpectResponse); // 3) Sleep for 1 second. #ifdef _WIN32 OT_Sleep(1000); #else sleep (1); #endif bool bFoundMessage = false; // 4) While there are messages to be read in response from the server, // then process and handle them all. do { OTMessage * pMsg = new OTMessage; OT_ASSERT(NULL != pMsg); // If this returns true, that means a Message was // received and processed into an OTMessage object (theMsg) bFoundMessage = g_OT_API.GetClient()->ProcessInBuffer(*pMsg); if (true == bFoundMessage) { // OTString strReply; // theMsg.SaveContract(strReply); // OTLog::vOutput(0, "\n\n**********************************************\n" // "Successfully in-processed server response.\n\n%s\n", strReply.Get()); g_OT_API.GetClient()->ProcessServerReply(*pMsg); // the Client takes ownership and will handle cleanup. } else { delete pMsg; pMsg = NULL; } } while (true == bFoundMessage); } // for OTLog::Output(0, "Finished running client.\n"); #ifdef _WIN32 WSACleanup(); #endif return retVal; }
bool OTEnvelope::Decrypt(OTString & theOutput, const OTSymmetricKey & theKey, const OTPassword & thePassword) { const char * szFunc = "OTEnvelope::Decrypt"; // ------------------------------------------------ OT_ASSERT((thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0))); OT_ASSERT(theKey.IsGenerated()); // ----------------------------------------------- OTPassword theRawSymmetricKey; if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey)) { OTLog::vError("%s: Failed trying to retrieve raw symmetric key using password. (Wrong password?)\n", szFunc); return false; } // ----------------------------------------------- // uint32_t nRead = 0; uint32_t nRunningTotal = 0; m_dataContents.reset(); // Reset the fread position on this object to 0. // **************************************************************************** // // Read the ENVELOPE TYPE (as network order version -- and convert to host version.) // // 0 == Error // 1 == Asymmetric Key (this function -- Seal / Open) // 2 == Symmetric Key (other functions -- Encrypt / Decrypt use this.) // Anything else: error. // uint16_t env_type_n = 0; if (0 == (nRead = m_dataContents.OTfread(reinterpret_cast<uint8_t*>(&env_type_n), static_cast<uint32_t>(sizeof(env_type_n))))) { OTLog::vError("%s: Error reading Envelope Type. Expected asymmetric(1) or symmetric (2).\n", szFunc); return false; } nRunningTotal += nRead; OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(env_type_n))); // ---------------------------------------------------------------------------- // convert that envelope type from network to HOST endian. // const uint16_t env_type = static_cast<uint16_t>(ntohs(static_cast<uint16_t>(env_type_n))); // nRunningTotal += env_type; // NOPE! Just because envelope type is 1 or 2, doesn't mean we add 1 or 2 extra bytes to the length here. Nope! if (2 != env_type) { const uint32_t l_env_type = static_cast<uint32_t>(env_type); OTLog::vError("%s: Error: Expected Envelope for Symmetric key (type 2) but instead found type: %ld.\n", szFunc, l_env_type); return false; } // **************************************************************************** // // Read network-order IV size (and convert to host version) // const uint32_t max_iv_length = OTCryptoConfig::SymmetricIvSize(); // I believe this is a max length, so it may not match the actual length of the IV. // Read the IV SIZE (network order version -- convert to host version.) // uint32_t iv_size_n = 0; if (0 == (nRead = m_dataContents.OTfread(reinterpret_cast<uint8_t*>(&iv_size_n), static_cast<uint32_t>(sizeof(iv_size_n))))) { OTLog::vError("%s: Error reading IV Size.\n", szFunc); return false; } nRunningTotal += nRead; OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(iv_size_n))); // ---------------------------------------------------------------------------- // convert that iv size from network to HOST endian. // const uint32_t iv_size_host_order = ntohl(iv_size_n); if (iv_size_host_order > max_iv_length) { OTLog::vError("%s: Error: iv_size (%ld) is larger than max_iv_length (%ld).\n", szFunc, static_cast<long>(iv_size_host_order), static_cast<long>(max_iv_length)); return false; } // nRunningTotal += iv_size_host_order; // Nope! // **************************************************************************** // // Then read the IV (initialization vector) itself. // OTPayload theIV; theIV.SetPayloadSize(iv_size_host_order); if (0 == (nRead = m_dataContents.OTfread(static_cast<uint8_t*>(const_cast<void *>(theIV.GetPayloadPointer())), static_cast<uint32_t>(iv_size_host_order)))) { OTLog::vError("%s: Error reading initialization vector.\n", szFunc); return false; } nRunningTotal += nRead; OT_ASSERT(nRead == static_cast<uint32_t>(iv_size_host_order)); OT_ASSERT(nRead <= max_iv_length); // ---------------------------------------------------------------------------- // We create an OTPayload object to store the ciphertext itself, which begins AFTER the end of the IV. // So we see pointer + nRunningTotal as the starting point for the ciphertext. // the size of the ciphertext, meanwhile, is the size of the entire thing, MINUS nRunningTotal. // OTPayload theCipherText(static_cast<const void*>( static_cast<const uint8_t *>(m_dataContents.GetPointer()) + nRunningTotal ), m_dataContents.GetSize() - nRunningTotal); // ---------------------------------------------------------------------------- // Now we've got all the pieces together, let's try to decrypt it... // OTPayload thePlaintext; // for output. const bool bDecrypted = OTCrypto::It()->Decrypt(theRawSymmetricKey, // The symmetric key, in clear form. // ------------------------------- static_cast<const char *>(theCipherText.GetPayloadPointer()), // This is the Ciphertext. theCipherText.GetSize(), // ------------------------------- theIV, // ------------------------------- thePlaintext); // OUTPUT. (Recovered plaintext.) You can pass OTPassword& OR OTPayload& here (either will work.) // ----------------------------------------------- // theOutput is where we'll put the decrypted data. // theOutput.Release(); if (bDecrypted) { // ----------------------------------------------------- // Make sure it's null-terminated... // uint32_t nIndex = thePlaintext.GetSize()-1; (static_cast<uint8_t*>(const_cast<void *>(thePlaintext.GetPointer())))[nIndex] = '\0'; // ----------------------------------------------------- // Set it into theOutput (to return the plaintext to the caller) // theOutput.Set(static_cast<const char *>(thePlaintext.GetPointer())); // ---------------- } return bDecrypted; }