Example #1
0
// getPassword returns "" if empty, otherwise returns the password.
//
const uint8_t* OTPassword::getPassword_uint8() const
{
    OT_ASSERT(isText_);
    return (size_ <= 0) ? reinterpret_cast<const uint8_t*>("") : &(data_[0]);
}
// This function will base64 ENCODE theData,
// and then Set() that as the string contents.
// Additionally it will pack and compress the data!
//
bool OTASCIIArmor::SetAndPackData(const OTData & theData, bool bLineBreaks/*=true*/)
{
	char *	pString	= NULL;
	
	Release();
	
	if (theData.GetSize() < 1)
		return true;
	
	// --------------------------------------------------------
	
	OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either.
	
	// Here I use the default storage context to create the object (the blob.)
	// I also originally created OTASCIIArmor::GetPacker() using OTDB_DEFAULT_PACKER,
	// so I know everything is compatible.
	//
	OTDB::Blob * pBlob = dynamic_cast<OTDB::Blob *>(OTDB::CreateObject(OTDB::STORED_OBJ_BLOB));
	
	OT_ASSERT(NULL != pBlob); // Beyond this point, responsible to delete pBlob.
	OTCleanup<OTDB::Blob> theBlobAngel(*pBlob); // make sure memory is cleaned up.

	// -----------------------------
	
	pBlob->m_memBuffer.assign(static_cast<const unsigned char *>(theData.GetPointer()), 
							  static_cast<const unsigned char *>(theData.GetPointer())+theData.GetSize());
		
	OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pBlob); // Now we PACK our data before compressing/encoding it.
	
	if (NULL == pBuffer)
	{
		OTLog::Error("Failed packing data in OTASCIIArmor::SetAndPackData. \n");
		return false;
	}
	
	OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up.
	
	// --------------------------------------------------------
	
	const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData());
	const size_t theSize = pBuffer->GetSize();
	
	if (NULL != pUint)
		pString = OT_base64_encode(pUint, static_cast<int> (theSize), (bLineBreaks ? 1 : 0));
	else 
	{
		OTLog::Error("Error while base64_encoding in OTASCIIArmor::SetAndPackData.\n");
		return false;
	}
	
	// -------------------------------------
	
	if (NULL != pString)
	{
		Set(pString);
		delete [] pString; pString=NULL;
		return true;
	}
	else 
	{
		OTLog::Error("Error while base64_encoding in OTASCIIArmor::SetAndPackData.\n");
		return false;
	}
}
bool OTEnvelope::Seal(const OTAsymmetricKey & RecipPubKey, const 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 &	publicKey	= (OTAsymmetricKey &)RecipPubKey;
	EVP_PKEY *			pkey		= (EVP_PKEY *)publicKey.GetKey();
	
	if (NULL == pkey)
	{
		OTLog::Error("Null public key in OTEnvelope::Seal\n");
		return false;
	}
	
	// This is where the envelope final contents will be placed.
	m_dataContents.Release();
	
	
	EVP_CIPHER_CTX_init(&ctx);
    ek = (unsigned char*)malloc(EVP_PKEY_size(pkey));
	
	OT_ASSERT(NULL != ek);
	
	memset(ek, 0, EVP_PKEY_size(pkey));
	
    if (!EVP_SealInit(&ctx, EVP_aes_128_cbc(), &ek, &eklen, iv, &pkey, 1))
    {
        OTLog::Error("EVP_SealInit: failed.\n");
		free(ek); ek = NULL;
		return false;
    }
	
    // First we write out the encrypted key length, then the encrypted key,
	// then the iv (the IV length is fixed by the cipher we have chosen).
	
    eklen_n = htonl(eklen);
	
	OTData dataEKSize(&eklen_n, sizeof(eklen_n)); // Encrypted Key size. (EK). Bytes are in network order.
	OTData dataEK(ek, eklen); // Encrypted Key
	OTData dataIV(iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc())); // Initialization Vector
	
	// Concatenate (to the envelope result buffer) the three pieces of final data we have so far.
	m_dataContents += dataEKSize;
	m_dataContents += dataEK;
	m_dataContents += dataIV;
	
	// Next we put the plaintext into a data object so we can process it.
	OTData plaintext((const void*)theContents.Get(), theContents.GetLength()+1); // +1 for null terminator
	
    // Now we process the input and write the encrypted data to the
	// output.
	
    while (0 < (len = plaintext.OTfread((char*)buffer, sizeof(buffer))))
    {
        if (!EVP_SealUpdate(&ctx, buffer_out, &len_out, buffer, len))
        {
            OTLog::Error("EVP_SealUpdate: failed.\n");
			free(ek); ek = NULL;
			return false;
        }
		
		OTData dataSealUpdate(buffer_out, len_out);
		m_dataContents += dataSealUpdate;
	}
	
    if (!EVP_SealFinal(&ctx, buffer_out, &len_out))
    {
        OTLog::Error("EVP_SealFinal: failed.\n");
		free(ek); ek = NULL;
		return false;
    }
	
	OTData dataSealFinal(buffer_out, len_out);
	m_dataContents += dataSealFinal;
	
	retval = true;
	
    free(ek); ek = NULL;
	
    return retval;
}
/// This function first Packs the incoming string, using whatever is the default packer. (MsgPack or Protobuf).
/// Then it Compresses the packed binary data using zlib. (ezcompress.)
/// Then it Base64-Encodes the compressed binary and sets it as a string on THIS OBJECT.
/// 
/// I added these pieces 1-by-1 over time. At first the messages were too long, so I started compressing them.
/// Then they were not binary compatible across various platforms, so I added the packing.
//
bool OTASCIIArmor::SetAndPackString(const OTString & strData, bool bLineBreaks) //=true
{
//	OTLog::vError("DEBUGGING OTASCIIARMOR::SETSTRING, INPUT:  --------->%s<---------", strData.Get());
	
	Release();
	
	if (strData.GetLength() < 1)
		return true;
	
	// --------------------------------------------------------
	
	OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either.
	
	// Here I use the default storage context to create the object (the blob.)
	// I also originally created OTASCIIArmor::GetPacker() using OTDB_DEFAULT_PACKER,
	// so I know everything is compatible.
	//
	OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING));
	
	OT_ASSERT(NULL != pOTDBString); // Beyond this point, responsible to delete pString.
	OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // make sure memory is cleaned up.
	
	// -----------------------------
	
	const uint32_t	theStringSize32	= strData.GetLength();
	const size_t	theStringSize	= theStringSize32; // might need a cast here. // todo make sure this will handle sizes as big as I need.
	
	pOTDBString->m_string.assign(strData.Get(), // const char * 
								 theStringSize);
	
	OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pOTDBString); // Now we PACK our string before compressing/encoding it.
	
	if (NULL == pBuffer)
	{
		OTLog::Error("Failed packing string in OTASCIIArmor::SetAndPackString. \n");
		return false;
	}
	
	OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up.
	
	// --------------------------------------------------------	
	
	const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData());
	const size_t theSize = pBuffer->GetSize();

	// --------------------------------------------------------

	char *	pString	= NULL;
	
	// Set up source buffer and destination buffer
	long nDestLen	= DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.)
	const long lSourcelen	= static_cast<long> (theSize);
	
	unsigned char* pSource	= new unsigned char[lSourcelen+10]; // for safety
	unsigned char* pDest	= new unsigned char[nDestLen  +10]; // for safety
	
	OT_ASSERT(NULL != pSource);
	OT_ASSERT(NULL != pDest);
	
    OTPassword::zeroMemory(pSource, lSourcelen+10);
    OTPassword::zeroMemory(pDest,   nDestLen  +10);
    
//    void * OTPassword::safe_memcpy(void   * dest,
//                                   uint32_t dest_size,
//                                   const
//                                   void   * src,
//                                   uint32_t src_length,
//                                   bool     bZeroSource/*=false*/) // if true, sets the source buffer to zero after copying is done.

    OTPassword::safe_memcpy(pSource, lSourcelen, pUint, theSize);
//	memcpy(pSource, static_cast<const unsigned char*>(pUint), theSize );
	
	// Now we are compressing first before base64-encoding (for strings, anyway)	
	int nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	
	// If the destination buffer wasn't the right size the first time around,
	// then we re-allocate it to the right size (which we now know) and try again...
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = new unsigned char [nDestLen+10]; // enough room now
		OT_ASSERT(NULL != pDest);
        
        OTPassword::zeroMemory(pDest, nDestLen+10);
		
		nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	}
	
	// Clean this up...
	delete [] pSource;
	pSource = NULL;
	
	// Still errors?
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "Error allocating memory in OTASCIIArmor::SetAndPackString\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::SetAndPackString\n");
		return false; // not really necessary but just making sure.
	}
	else if ( nErr == EZ_DATA_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "corrupted pSrc passed to ezuncompress OTASCIIArmor::SetAndPackString\n");
		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::SetAndPackString\n");
		return false; // not really necessary but just making sure.
	}
	
	OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetAndPackString\n");
	
	// Success
	if (0 < nDestLen)
	{
		// Now let's base-64 encode it...
		pString = OT_base64_encode((const uint8_t*)pDest, nDestLen, (bLineBreaks ? 1 : 0));
		
		delete [] pDest;
		pDest = NULL;
		
		if (pString)
		{
			Set(pString);
			delete [] pString; pString=NULL; 
			return true;
		}
		else 
		{
			OTLog::Error("pString NULL in OTASCIIArmor::SetAndPackString\n");
		}
	}
	else 
	{
		OTLog::Error("nDestLen 0 in OTASCIIArmor::SetAndPackString\n");
	}
	
	if (pDest)
		delete [] pDest;
	
	pDest = NULL;
	
	return false;	
}
// This code reads up the string, discards the bookends, and saves only the gibberish itself.
// the bEscaped option allows you to load a normal ASCII-Armored file if off, and allows
// you to load an escaped ASCII-armored file (such as inside the contracts when the public keys
// are escaped with a "- " before the rest of the ------- starts.)
//
bool OTASCIIArmor::LoadFromString(OTString & theStr, // input
                                  bool bEscaped/*=false*/, 
                                  const // This szOverride sub-string determines where the content starts, when loading.
                                  std::string str_override/*="-----BEGIN"*/) // Default is "-----BEGIN"
{
	if (0 > str_override.size() )	{ OTLog::vError("%s: %s size is less than 0!\n", __FUNCTION__, "str_override"	); OT_ASSERT(false); return false; }
    // Should never be 0 size, as default is "-----BEGIN"
    // But if you want to load a private key, try "-----BEGIN ENCRYPTED PRIVATE" instead.
    // *smile*
    const std::string str_end_line = "-----END"; // Someday maybe allow parameterized option for this.
    // ------------------------------------------
    const int nBufSize  = 2100; // todo: hardcoding
    const int nBufSize2 = 2048; // todo: hardcoding
    // -----------------------------
	char buffer1[2100];         // todo: hardcoding
    
    std::fill(&buffer1[0], &buffer1[(nBufSize-1)], 0); // Initializing to 0.
//	memset(buffer1, 0, 2100); // todo: hardcoding
	
	bool bContentMode            = false;  // "Currently IN content mode."
	bool bHaveEnteredContentMode = false;  // "Have NOT YET entered content mode."
	
	// Clear out whatever string might have been in there before.
	Release();
	
	// Load up the string from theStr, 
	// (bookended by "-----BEGIN ... -----" and "END-----" messages)
	bool bIsEOF = false;
	theStr.reset(); // So we can call theStr.sgets(). Making sure position is at start of string.
	
	do
	{
		bIsEOF = !(theStr.sgets(buffer1, nBufSize2)); // 2048
//		bIsEOF = fin.getline(buffer1, 2048).eof();  // todo: hardcoding.
		
		std::string line		= buffer1;	
		const char * pConstBuf	= line.c_str();
		char * pBuf				= (char *)pConstBuf;
		
		// It's not a blank line.
		if (line.length() < 2)
		{
			continue;
		}
		
		// if we're on a dashed line...
		else if (line.at(0) == '-' && 
                 line.at(2) == '-' && 
                 line.at(3) == '-' &&
				 (bEscaped ? (line.at(1) == ' ') : (line.at(1) == '-') )
                )
		{			
			// If I just hit a dash, that means there are only two options:
			
			// a. I have not yet entered content mode, and potentially just now entering it for the first time.
			if (!bHaveEnteredContentMode)
			{
                // str_override defaults to:  "-----BEGIN" (If you want to load a private key instead,
                // Try passing "-----BEGIN ENCRYPTED PRIVATE" instead of going with the default.)
                //
				if (line.find(str_override) != std::string::npos && 
                    line.at(0) == '-' && 
                    line.at(2) == '-' && 
					line.at(3) == '-' && 
                    (bEscaped ? (line.at(1) == ' ') : (line.at(1) == '-'))
                   )
				{
//					OTLog::Error("Reading ascii-armored contents...");
					bHaveEnteredContentMode = true;
					bContentMode = true;
					continue;
				}
				else
				{
					continue;
				}				
			}
			
			// b. I am now LEAVING content mode!
			else if (bContentMode &&
                     // str_end_line is "-----END"
                     (line.find(str_end_line) != std::string::npos))
			{
//				OTLog::Error("Finished reading ascii-armored contents.\n");
//				OTLog::vError("Finished reading ascii-armored contents:\n%s(END DATA)\n", Get());
				bContentMode   = false;
				continue;
			}
		}
		
		
		// Else we're on a normal line, not a dashed line.
		else
		{
			if (bHaveEnteredContentMode && bContentMode)
			{
				if (line.compare(0,8,"Version:") == 0)
				{
//					OTLog::Error("Skipping version line...\n");
					continue;
				}
				if (line.compare(0,8,"Comment:") == 0)
				{
//					OTLog::Error("Skipping comment line...\n");
					continue;
				}
			}
			
		}
		
		// Here we save the line to member variables, if appropriate
		if (bContentMode)
		{
			Concatenate("%s\n", pBuf);
		}
	}
	while(!bIsEOF && (bContentMode || !bHaveEnteredContentMode));
	
	
	// reset the string position back to 0
	theStr.reset();
	
	if (!bHaveEnteredContentMode)
	{
		OTLog::vError("Error in OTASCIIArmor::LoadFromString: EOF before ascii-armored "
                      "content found, in:\n\n%s\n\n", theStr.Get());
		return false;
	}
	else if (bContentMode)
	{
		OTLog::vError("Error in OTASCIIArmor::LoadFromString: EOF while still reading "
                      "content, in:\n\n%s\n\n", theStr.Get());
		return false;
	}
	else
		return true;
}
Example #6
0
// Used when importing/exporting a Nym to/from the wallet.
//
bool OTKeypair::ReEncrypt(const OTPassword& theExportPassword, bool bImporting)
{

    OT_ASSERT(m_pkeyPublic);
    OT_ASSERT(m_pkeyPrivate);

    OT_ASSERT(HasPublicKey());
    OT_ASSERT(HasPrivateKey());

    // If we were importing, we were in the exported format but now we're in the
    // internal format.
    // Therefore we want to use the wallet's internal cached master passphrase
    // to save. Therefore
    // strReason will be used for the import case.
    //
    // But if we were exporting, then we were in the internal format and just
    // re-encrypted to the
    // export format. So we'd want to pass the export passphrase when saving.
    //
    const String strReasonAbove(
        bImporting ? "Enter the new export passphrase. (Above "
                     "ReEncryptPrivateKey in OTKeypair::ReEncrypt)"
                   : "Enter your wallet's master passphrase. (Above "
                     "ReEncryptPrivateKey in OTKeypair::ReEncrypt)");

    const String strReasonBelow(
        bImporting ? "Enter your wallet's master passphrase. (Below "
                     "ReEncryptPrivateKey in OTKeypair::ReEncrypt)"
                   : "Enter the new export passphrase. (Below "
                     "ReEncryptPrivateKey in OTKeypair::ReEncrypt)");

    // At this point the public key was loaded from a public key, not a cert,
    // but the private key was loaded from the cert. Therefore we'll save the
    // public cert from the private key, and then use that to reload the public
    // key after ReEncrypting. (Otherwise the public key would be there, but it
    // would be missing the x509, which is only available in the cert, not the
    // pubkey alone -- and without the x509 being there, the "SaveAndReload"
    // call
    // below would fail.
    // Why don't I just stick the Cert itself into the public data, instead of
    // sticking the public key in there? Because not all key credentials will
    // use
    // certs. Some will use pubkeys from certs, and some will use pubkeys not
    // from
    // certs. But I might still just stick it in there, and code things to be
    // able to
    // load either indiscriminately. After all, that's what I'm doing already in
    // the
    // asset and server contracts. But even in those cases, there will be times
    // when
    // only a pubkey is available, not a cert, so I'll probably still find
    // myself having
    // to do this. Hmm...

    const bool bReEncrypted = m_pkeyPrivate->ReEncryptPrivateKey(
        theExportPassword, bImporting); // <==== IMPORT or EXPORT occurs here.

    if (!(bReEncrypted)) {
        otErr << __FUNCTION__ << ": Failure, either when re-encrypting, or "
                                 "when subsequently retrieving "
                                 "the public/private keys. bImporting == "
              << (bImporting ? "true" : "false") << "\n";
    }

    return (bReEncrypted);
}
Example #7
0
// Called by the password callback function.
// The password callback uses this to get the password for any individual Nym.
// This will also generate the master password, if one does not already exist.
//
bool OTCachedKey::GetMasterPassword(_SharedPtr<OTCachedKey> & mySharedPtr,
                                    OTPassword            & theOutput,
									const char            * szDisplay,
									bool bVerifyTwice/*=false*/)
{
	tthread::lock_guard<tthread::mutex> lock(m_Mutex); // Multiple threads can't get inside here at the same time.

	std::string str_display(NULL != szDisplay ? szDisplay : "(Display string was blank.)");

	const char * szFunc = "OTCachedKey::GetMasterPassword";

	//  OT_ASSERT(NULL != m_pSymmetricKey); // (This had better be set already.) // Took this out because calling Generate inside here now.
	// ----------------------------------------
	//
	if (NULL != m_pMasterPassword)
	{
		OTLog::vOutput(2, "%s: Master password was available. (Returning it now.)\n", szFunc);

		theOutput = *m_pMasterPassword;
		return true;
	}
	// --------------------------------------------
	OTLog::vOutput(2, "%s: Master password wasn't loaded. Instantiating...\n", szFunc);

	// If m_pMasterPassword is NULL, (which below this point it is) then...
	//
	// Either it hasn't been created yet, in which case we need to instantiate it,
	// OR it expired, in which case m_pMasterPassword is NULL,
	// but m_pThread isn't, and still needs cleaning up before we instantiate another one!
	//
	LowLevelReleaseThread();
	// --------------------------------------------
	m_pMasterPassword = OTCrypto::It()->InstantiateBinarySecret(); // already asserts.
	// --------------------------------------------
	/*
	How does this work?

	When trying to open a normal nym, the password callback realizes we are calling it
	in "NOT master mode", so instead of just collecting the passphrase and giving it
	back to OpenSSL, it calls this function first, which returns the master password
	(so that IT can be given to OpenSSL instead.)

	If the master wasn't already loaded (common) then we call the callback in here ourselves.
	Notice it's recursive! But this time, the callback sees we ARE in master mode, so it doesn't
	call this function again (which would be an infinite loop.) Instead, it collects the password
	as normal, only instead of passing it back to the caller via the buffer, it uses the
	passUserInput by attaching it to thePWData before the call. That way the callback function
	can set passUserInput with whatever it retrieved from the user, and then back in this function
	again we can get the passUserInput and use it to unlock the MASTER passphrase, which we set
	onto theOutput.

	When this function returns true, the callback (0th level of recursion) uses theOutput
	as the "passphrase" for all Nyms, passing it to OpenSSL.

	This way, OpenSSL gets a random key instead of a passphrase, and the passphrase is just used
	for encrypting that random key whenever its timer has run out.

	*/

	bool bReturnVal = false;

	// CALL the callback directly. (To retrieve a passphrase so I can use it in GenerateKey
	// and GetRawKey.)
	//
	//int32_t OT_OPENSSL_CALLBACK (char *buf, int32_t size, int32_t rwflag, void *userdata);
	//
	// For us, it will set passUserInput to the password from the user, and return
	// a simple 1 or 0 (instead of the length.) buf and size can be NULL / 0, and
	// rwflag should be passed in from somewhere.
	//
	// m_pSymmetricKey is the encrypted form of the master key. Therefore we want to hash
	// it, in order to get the ID for lookups on the keychain.
	//
	OTPassword * pDerivedKey = NULL;
	OTCleanup<OTPassword> theDerivedAngel;
	// ---------------------------------
	if (NULL == m_pSymmetricKey)
	{
		m_pSymmetricKey = new OTSymmetricKey;
		OT_ASSERT(NULL != m_pSymmetricKey);
	}
	// --------------------------------------------------
	if (false == m_pSymmetricKey->IsGenerated()) // doesn't already exist.
	{
		OTLog::vOutput(1, "%s: Master key didn't exist. Need to collect a passphrase from the user, "
			"so we can generate a master key...\n ", szFunc);

		bVerifyTwice = true; // we force it, in this case.
	}

	// --------------------------------------------------
	else // If the symmetric key itself ALREADY exists (which it usually will...)
	{    // then we might have also already stashed the derived key on the system
		// keychain. Let's check there first before asking the user to enter his
		// passphrase...
		//

		// -----------------------------------------------------
		const OTIdentifier idCachedKey(*m_pSymmetricKey); // Grab the ID of this symmetric key.
		const OTString     strCachedKeyHash(idCachedKey); // Same thing, in string form.
		//
		// This only happens in here where we KNOW m_pSymmetricKey was already generated.
		//
		//      OTString strCachedKeyHash;
		//      m_pSymmetricKey->GetIdentifier(strCachedKeyHash);
		// -----------------------------------------------------
		pDerivedKey = OTCrypto::It()->InstantiateBinarySecret(); // pDerivedKey is instantiated here to use as output argument below.
		// -----------------------------------------------------
		//
		// *** ATTEMPT to RETRIEVE the *Derived Key* from THE SYSTEM KEYCHAIN ***
		//
		const bool bFoundOnKeyring = this->IsUsingSystemKeyring() &&
			OTKeyring::RetrieveSecret(
			strCachedKeyHash, // HASH OF ENCRYPTED MASTER KEY
			*pDerivedKey,     // (Output) RETRIEVED PASSWORD.
			str_display);     // optional display string.
		// -----------------------------------------------------
		if (bFoundOnKeyring) // We found it -- but does it WORK?
		{
			const bool bCachedKey = m_pSymmetricKey->GetRawKeyFromDerivedKey(*pDerivedKey, *m_pMasterPassword);

			//
			// Note: What IS the secret? We don't want it to be the user's passphrase that he TYPES.
			// We also don't want it to be the eventual (random) key that unlocks the private keys.
			// Rather, we want it to be the intermediary key, generated from the user's passphrase via
			// a key-derivation algorithm, which is then used to unlock the (random) symmetric key that
			// actually unlocks the private keys.
			// This way the symmetric key itself can be kept locked at ALL times, and instead, we have the
			// derived key on the timer, use it to unlock the symmetric key EVERY TIME we use that, and
			// IMMEDIATELY throw it away afterwards, since we can still open it again (until the timeout) by
			// using the derived key.
			// This is slick because the user doesn't directly enter the derived key, and neither is it
			// directly used for unlocking private keys -- so it's preferable to store in RAM than those things.
			//
			//
			// 1. Make sure the above description is actually what we DO do now. (UPDATE: for keyring, yes. For OT internally, no.)
			// 2. Make sure the derived key, as described above, is also what is stored as the SECRET, here! (UPDATE: Yes!)
			//    (i.e. in other processes such as Mac Keychain or Gnome.)
			// 3. Done. Need to add ability for OTIdentifier to hash OTSymmetricKey, so we can use it for strUser above. DONE.
			//
			// UPDATE: the master key cached inside OT (on a timer) is not the derived key, but the master key itself
			// that's used on the private keys. However, the one we're caching in the system keyring IS the derived key,
			// and not the master key. So for example, if an attacker obtained the derived key from the system keyring,
			//

			if (bCachedKey) // It works!
			{
				OTLog::vOutput(1, "%s: Finished calling m_pSymmetricKey->GetRawKeyFromDerivedKey (Success.)\n", szFunc);
				theOutput  = *m_pMasterPassword; // Return it to the caller.
				theDerivedAngel.SetCleanupTarget(*pDerivedKey); // Set our own copy to be destroyed later. It continues below as "NOT NULL".
				bReturnVal = true; // Success.
			}
			else // It didn't unlock with the one we found.
			{
				OTLog::vOutput(0, "%s: Unable to unlock master key using derived key found on system keyring.\n", szFunc);
				delete pDerivedKey;
				pDerivedKey = NULL;  // Below, this function checks pDerivedKey for NULL.
			}
		}
		else    // NOT found on keyring.
		{
			if (this->IsUsingSystemKeyring()) // We WERE using the keying, but we DIDN'T find the derived key.
				OTLog::vOutput(1, "%s: Unable to find derived key on system keyring.\n", szFunc);
			// (Otherwise if we WEREN'T using the system keyring, then of course we didn't find any derived key cached there.)
			delete pDerivedKey;
			pDerivedKey = NULL; // Below, this function checks pDerivedKey for NULL.

		}
	}
	// --------------------------------------------------
	// NOT found on Keyring...
	//
	if (NULL == pDerivedKey) // Master key was not cached in OT, nor was it found in the system keychain.
	{                        // Therefore we HAVE to ask the user for a passphrase and decrypt it ourselves,
		// since we DO have an encrypted version of the key...

		// This time we DEFINITELY force the user input, since we already played our hand.
		// If the master key was still in memory we would have returned already, above.
		// Then we tried to find it on the keyring and we couldn't find it, so now we have
		// to actually ask the user to enter it.
		//

		std::string default_password(OT_DEFAULT_PASSWORD); // default password
		OTPassword passwordDefault; passwordDefault.zeroMemory();
        passwordDefault.setPassword(default_password.c_str(), static_cast<int32_t>(default_password.length()));

		OTPassword passUserInput;  passUserInput.zeroMemory(); // text mode.
		OTPasswordData  thePWData(str_display.c_str(), &passUserInput, mySharedPtr); // these pointers are only passed in the case where it's for a master key.
//      OTLog::vOutput(2, "*********Begin OTCachedKey::GetMasterPassword: Calling souped-up password cb...\n * *  * *  * *  * *  * ");
		// -----------------------------------------------------------------------


		// It's possible this is the first time this is happening, and the master key
		// hasn't even been generated yet. In which case, we generate it here...
		//
		bool bGenerated = m_pSymmetricKey->IsGenerated();

		if (!bGenerated) // This Symmetric Key hasn't been generated before....
		{

			if (!OTAsymmetricKey::GetPasswordCallback()(NULL, 0, bVerifyTwice ? 1 : 0, static_cast<void *>(&thePWData)))
			{
				OTLog::vError("%s: Failed to get password from user!", __FUNCTION__);
				return false;
			}


			// If the length of the user supplied password is less than 4 characters int64_t, we are going to use the default password!
			bool bUsingDefaultPassword = false;
			{
				if (4 > std::string(passUserInput.getPassword()).length())
				{
					OTLog::vOutput(0, "\n Password entered was less than 4 characters int64_t! This is NOT secure!!\n"
						"... Assuming password is for testing only... setting to default password: %s \n",
						OT_DEFAULT_PASSWORD);
					bUsingDefaultPassword = true;
				}
			}

//          OTLog::vOutput(0, "%s: Calling m_pSymmetricKey->GenerateKey()...\n", szFunc);

			bGenerated = m_pSymmetricKey->GenerateKey(bUsingDefaultPassword ? passwordDefault : passUserInput, &pDerivedKey); // derived key is optional here.
			//
			// Note: since I passed &pDerivedKey in the above call, then **I** am responsible to
			// check it for NULL, and delete it if there's something there!
			//
			if (NULL != pDerivedKey)
				theDerivedAngel.SetCleanupTarget(*pDerivedKey);
			else
				OTLog::vError("%s: FYI: Derived key is still NULL after calling OTSymmetricKey::GenerateKey.\n");

//          OTLog::vOutput(0, "%s: Finished calling m_pSymmetricKey->GenerateKey()...\n", szFunc);
		}
		else // m_pSymmetricKey->IsGenerated() == true. (Symmetric Key is already generated.)
		{
			// -------------------------------------------------------------------------------------------------
			// Generate derived key from passphrase.
			//
			// We generate the derived key here so that GetRawKeyFromPassphrase() call (below)
			// works with it being passed in. (Because the above call to GenerateKey also grabs
			// a copy of the derived key and passes it in below to the same GetRawKeyFromPassphrase.)
			//
			// So WHY are we keeping a copy of the derived key through these calls? Otherwise they
			// would all individually generate it, which is a waste of resources. Also, we want to have
			// our grubby hands on the derived key at the end so we can add it to the system keyring
			// (below), and we'd just end up having to derive it AGAIN in order to do so.
			//
			if (m_pSymmetricKey->HasHashCheck())
			{
				pDerivedKey = m_pSymmetricKey->CalculateDerivedKeyFromPassphrase(passwordDefault); // asserts already.

				if (NULL == pDerivedKey)
				{
					OTLog::vOutput(0, "\n\n%s: Please enter your password.\n\n", __FUNCTION__);

					for ( ;; )  // bad passphase (as the calculate key returned NULL)
					{
						if (!OTAsymmetricKey::GetPasswordCallback()(NULL, 0, false, static_cast<void *>(&thePWData)))
						{
							OTLog::vError("\n\n%s: Failed to get password from user!\n\n", __FUNCTION__);
							return false;
						}
						pDerivedKey = m_pSymmetricKey->CalculateDerivedKeyFromPassphrase(passUserInput); // asserts already.
						if (NULL != pDerivedKey) break; // success

						OTLog::vOutput(0, "\n\n%s: Wrong Password, Please Try Again.\n\n", __FUNCTION__);
					}
				}
			}
			else
			{
				OTLog::vOutput(0,"\n Please enter your current password twice, (not a new password!!) \n");

				if (!OTAsymmetricKey::GetPasswordCallback()(NULL, 0, true, static_cast<void *>(&thePWData)))
				{
					OTLog::vError("%s: Failed to get password from user!", __FUNCTION__);
					return false;
				}

				pDerivedKey = m_pSymmetricKey->CalculateNewDerivedKeyFromPassphrase(passUserInput); // asserts already.
				OT_ASSERT(NULL != pDerivedKey);
			}
			theDerivedAngel.SetCleanupTarget(*pDerivedKey);

			OTLog::vOutput(1, "%s: FYI, symmetric key was already generated. "
				"Proceeding to try and use it...\n", szFunc);

			// bGenerated is true, if we're even in this block in the first place.
			// (No need to set it twice.)
		}

		// -------------------------------------------------------------------------------------------------
		// Below this point, pDerivedKey could still be null.
		// (And we only clean it up later if we created it.)
		// Also, bGenerated could still be false. (Like if it wasn't
		// generated, then generation itself failed, then it's still false.)
		//
		// Also, even if it was already generated, or if it wasn't but then successfully did,
		//
		// -----------------------------------------------------

		if (bGenerated) // If SymmetricKey (*this) is already generated.
		{
			OTLog::vOutput(2, "%s: Calling m_pSymmetricKey->GetRawKeyFromPassphrase()...\n", szFunc);

			// Once we have the user's password, then we use it to GetKey from the OTSymmetricKey (which
			// is encrypted) and that retrieves the cleartext master password which we set here and also
			// return a copy of.
			//
			// Note: if pDerivedKey was derived above already, which it should have been, then it will
			// be not-NULL, and will be used here, and will be used subsequently for adding to the system
			// keychain. Otherwise, it will be NULL, and GetRawKeyFromPassphrase will thus just derive its
			// own copy of the derived key internally. It will still work, but then back up here, it will
			// NOT be added to the system keyring, since it's still NULL back up here.
			// (FYI.)
			//
			const bool bCachedKey = m_pSymmetricKey->GetRawKeyFromPassphrase(passUserInput,
				*m_pMasterPassword,
				pDerivedKey);
			if (bCachedKey)
			{
				OTLog::vOutput(2, "%s: Finished calling m_pSymmetricKey->GetRawKeyFromPassphrase (Success.)\n", szFunc);
				theOutput  = *m_pMasterPassword; // Success!
				// ------------------------------
				// Store the derived key to the system keyring.
				//
				if (this->IsUsingSystemKeyring() && (NULL != pDerivedKey))
				{
					const std::string str_display(NULL != szDisplay ? szDisplay : "(Display string was blank.)");
					// -----------------------------------------------------
					const OTIdentifier idCachedKey(*m_pSymmetricKey);
					const OTString     strCachedKeyHash(idCachedKey); // Same thing, in string form.
					// -----------------------------------------------------
					//                      const bool bStored =
					OTKeyring::StoreSecret(strCachedKeyHash, // HASH OF ENCRYPTED MASTER KEY
						*pDerivedKey,     // (Input) Derived Key BEING STORED.
						str_display);     // optional display string.
				}
				else
					OTLog::vOutput(1, "%s: Strange: Problem with either: this->IsUsingSystemKeyring (%s) "
					"or: (NULL != pDerivedKey) (%s)\n", szFunc, this->IsUsingSystemKeyring() ? "true" : "false",
					(NULL != pDerivedKey) ? "true" : "false");

				bReturnVal = true;
			}
			else
				OTLog::vOutput(0, "%s: m_pSymmetricKey->GetRawKeyFromPassphrase() failed.\n", szFunc);
		} // bGenerated
		else
			OTLog::vError("%s: bGenerated is still false, even after trying to generate it, yadda yadda yadda.\n", szFunc);

	} // NULL == pDerivedKey
	// -------------------------------------------

	if (bReturnVal) // Start the thread!
	{
//      OTLog::vOutput(4, "%s: starting up new thread, so we can expire the master key from RAM.\n", szFunc);


// ************************************************************************
#if defined(OT_CRYPTO_USING_OPENSSL)

// -------------------------------------------------
#if defined(OPENSSL_THREADS)
		// thread support enabled

		OTLog::vOutput(2, "%s: Starting thread for Master Key...\n", szFunc);

        _SharedPtr<OTCachedKey> * pthreadSharedPtr = new _SharedPtr<OTCachedKey>(mySharedPtr); // TODO: memory leak.

		m_pThread = new tthread::thread(OTCachedKey::ThreadTimeout, static_cast<void *>(pthreadSharedPtr));

#else
		// no thread support

		OTLog::vError("%s: WARNING: OpenSSL was NOT compiled with thread support. "
			"(Master Key will not expire.)\n", szFunc);

#endif
// -------------------------------------------------

// ************************************************************************
#elif defined(OT_CRYPTO_USING_GPG)

        OTLog::vError("%s: WARNING: OT was compiled for GPG, which is not yet supported. "
                      "(Master Key will not expire.)\n", szFunc);

// ************************************************************************
#else  // OT_CRYPTO_USING_ ... nothing?

        OTLog::vError("%s: WARNING: OT wasn't compiled for any crypto library "
                      "(such as OpenSSL or GPG). Which is very strange, and I doubt "
                      "things will even work, with it in this condition. (Plus, Master "
                      "Key will not expire.)\n", szFunc);

// -------------------------------------------------
#endif     //if defined(OT_CRYPTO_USING_OPENSSL),  elif defined(OT_CRYPTO_USING_GPG),  else,  endif.
// ************************************************************************


		// -------------------------------------------------

	}
	else if (m_nTimeoutSeconds != (-1))
	{
		if (NULL != m_pMasterPassword)
        {
            OTPassword * pMasterPassword = m_pMasterPassword;

            m_pMasterPassword = NULL;

			delete pMasterPassword; pMasterPassword = NULL;
        }
	}
	// Since we have set the cleartext master password, We also have to fire up the thread
	// so it can timeout and be destroyed. In the meantime, it'll be stored in an OTPassword
	// which has these security precautions:
	/*
	1. Zeros memory in a secure and cross-platform way, in its destructor.
	2. OT_Init() uses setrlimit to prevent core dumps.
	3. Uses VirtualLock and mlock to reduce/prevent swapping RAM to hard drive.
	4. (SOON) will use VirtualProtect on Windows (standard API for protected memory)
	5. (SOON) and similarly have option in config file for ssh-agent, gpg-agent, etc.
	6. Even without those things,the master password is stored in an encrypted form after it times out.
	7. While decrypted (while timer is going) it's still got the above security mechanisms,
	plus options for standard protected-memory APIs are made available wherever possible.
	8. The actual passphrase the user types is not stored in memory, except just int64_t enough to
	use it to derive another key, used to unlock the actual key (for a temporary period of time.)
	9. Meanwhile the actual key is stored in encrypted form on disk, and the derived key isn't stored anywhere.
	10. Ultimately external hardware, and smart cards, are the way to go. But OT should still do the best possible.
	*/

	return bReturnVal;
}
Example #8
0
// This adds a null terminator.
//
int32_t OTPassword::setPassword_uint8(const uint8_t* szInput,
                                      uint32_t nInputSize)
{
    OT_ASSERT(nullptr != szInput);

    // cppcheck-suppress variableScope
    const char* szFunc = "OTPassword::setPassword";

    // Wipe whatever was in there before.
    //
    if (size_ > 0) zeroMemory();

    isBinary_ = false;
    isText_ = true;

    if (0 == nInputSize) return 0;

    // Make sure no input size is larger than our block size
    //
    if (nInputSize > getBlockSize())
        nInputSize = getBlockSize(); // Truncated password beyond max size.

    // The szInput string passed into this function should never
    // be a different size than what is passed in. For example it shouldn't
    // be SMALLER than what the user claims either. If it is, we error out.
    //
    if (String::safe_strlen(reinterpret_cast<const char*>(szInput),
                            static_cast<size_t>(nInputSize)) <
        static_cast<size_t>(nInputSize)) {
        otErr
            << szFunc
            << ": ERROR: string length of szInput did not match nInputSize.\n";
        return (-1);
    }

#ifndef _WIN32

    //
    // Lock the memory page, before we copy the data over.
    // (If it's not already locked, which I doubt it will be.)
    //
    // it won't be locked already, since we just zero'd it
    // (above.) But I check this anyway...
    if (!isPageLocked_) {
        if (ot_lockPage(static_cast<void*>(&(data_[0])), getBlockSize())) {
            isPageLocked_ = true;
        }
        else {
            otErr << szFunc
                  << ": Error: Failed attempting to lock memory page.\n";
        }
    }
#endif

#ifdef _WIN32
    strncpy_s(reinterpret_cast<char*>(data_), (1 + nInputSize),
              reinterpret_cast<const char*>(szInput), nInputSize);
#else
    strncpy(reinterpret_cast<char*>(data_),
            reinterpret_cast<const char*>(szInput), nInputSize);
#endif

    // force a null terminator in the 129th byte (at index 128.)
    // (Or at the 6th byte (at index 5), if the size is 5 bytes int64_t.)
    //
    data_[nInputSize] = '\0';
    size_ = nInputSize;

    return size_;
}
OTMessageOutbuffer::OTMessageOutbuffer() : m_strDataFolder(OTDataFolder::Get())
{
	OT_ASSERT(m_strDataFolder.Exists());
}
Example #10
0
uint32_t OTPassword::getPasswordSize() const
{
    OT_ASSERT(isText_);
    return size_;
}
Example #11
0
uint32_t OTPassword::getMemorySize() const
{
    OT_ASSERT(isBinary_);
    return size_;
}
Example #12
0
// getMemoryWritable returns nullptr if empty, otherwise returns the password.
void* OTPassword::getMemoryWritable()
{
    OT_ASSERT(isBinary_);
    return (size_ <= 0) ? nullptr : static_cast<void*>(&(data_[0]));
}
Example #13
0
const uint8_t* OTPassword::getMemory_uint8() const
{
    OT_ASSERT(isBinary_);
    return (size_ <= 0) ? nullptr : &(data_[0]);
}
Example #14
0
char* OTPassword::getPasswordWritable_char()
{
    OT_ASSERT(isText_);
    return (size_ <= 0) ? nullptr
                        : static_cast<char*>(static_cast<void*>(&(data_[0])));
}
Example #15
0
// Get a public key as an opentxs::String.
// This form is used in all cases except for the NymIDSource
// of a self-signed MasterCredential
bool OTKeypair::GetPublicKey(String& strKey) const
{
    OT_ASSERT(m_pkeyPublic);

    return m_pkeyPublic->GetPublicKey(strKey);
}
void OTMessageOutbuffer::AddSentMessage(OTMessage & theMessage) // must be heap allocated.
{
    int64_t lRequestNum = 0;
    
    if (theMessage.m_strRequestNum.Exists())
        lRequestNum = atol(theMessage.m_strRequestNum.Get()); // The map index is the request number on the message itself.
    // ----------------
    // It's technically possible to have TWO messages (from two different
    // servers) that happen to have the same request number. So we verify
    // that here, before removing any old ones with the same number and IDs.
    //
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    for (; it != m_mapMessages.end(); ++it)
    {
        // -----------------------------
        const int64_t  & lTempReqNum   = it->first;
        // -----------------------
        if (lTempReqNum != lRequestNum)
        {
            continue;
        }
        // -----------------------
        OTMessage   * pMsg          = it->second;
        OT_ASSERT(NULL != pMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        //
        if (!theMessage.m_strServerID.Compare(pMsg->m_strServerID) ||
            !theMessage.m_strNymID.   Compare(pMsg->m_strNymID))
        {
            continue;
        }
        // --------
        else
        {
            delete pMsg;
            pMsg = NULL;
            m_mapMessages.erase(it);
            break;
        }
    }
    // Whatever it was, it's gone now!
    // ----------------------------------
    // Now that we KNOW there's nothing already there with that request number (for that
    // server ID and Nym ID), we go ahead and add the new message to the map. (And take ownership.)
    //
    m_mapMessages.insert(std::pair<int64_t, OTMessage *>(lRequestNum, &theMessage));
    // ----------------------------------
    //
    // Save it to local storage, in case we don't see the reply until the next run.
    //
    bool bAlreadyExists=false, bIsNewFolder=false;
    OTString strFolder, strFolder1, strFolder2;
    strFolder1.Format("%s%s%s",
                      OTFolders::Nym().Get(),               OTLog::PathSeparator(),
                      theMessage.m_strServerID.Get());
    strFolder2.Format("%s%s%s", strFolder1.Get(), OTLog::PathSeparator(),
                      "sent" /*todo hardcoding*/);
    // ----------------------------------
    strFolder.Format("%s%s%s", strFolder2.Get(), OTLog::PathSeparator(),
                     theMessage.m_strNymID.Get());
    // ----------------------------------

	OTString strFolderPath = "", strFolder1Path = "", strFolder2Path = "";

	OTPaths::AppendFolder(strFolderPath,  m_strDataFolder,strFolder );
	OTPaths::AppendFolder(strFolder1Path, m_strDataFolder,strFolder1);
	OTPaths::AppendFolder(strFolder2Path, m_strDataFolder,strFolder2);

	OTPaths::ConfirmCreateFolder(strFolderPath,bAlreadyExists,bIsNewFolder);
	OTPaths::ConfirmCreateFolder(strFolder1Path,bAlreadyExists,bIsNewFolder);
	OTPaths::ConfirmCreateFolder(strFolder2Path,bAlreadyExists,bIsNewFolder);
    
    OTString strFile;
    strFile.Format("%s.msg", theMessage.m_strRequestNum.Get());
    
    theMessage.SaveContract(strFolder.Get(), strFile.Get());
    // ----------------------------------
    // We also keep a list of the request numbers, so let's load it up, add the number
    // to that list, and then save it again.
    //
    OTNumList theNumList;
    std::string str_data_filename("sent.dat"); // todo hardcoding.
    if (OTDB::Exists(strFolder.Get(), str_data_filename))
    {
        OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
        if (strNumList.Exists())
            theNumList.Add(strNumList);
        theNumList.Add(lRequestNum); // Add the new request number to it.
    }
    else // it doesn't exist on disk, so let's just create it from the list we have in RAM so we can store it to disk.
    {
        it = m_mapMessages.begin();
        while (it != m_mapMessages.end())
        {
            // -----------------------------
            const int64_t  & lTempReqNum   = it->first;
            // -----------------------
            OTMessage   * pMsg          = it->second;
            OT_ASSERT(NULL != pMsg);
            // -----------------------------
            //
            // If a server ID was passed in, but doesn't match the server ID on this message,
            // Then skip this one. (Same with the NymID.)
            //
            if (!theMessage.m_strServerID.Compare(pMsg->m_strServerID) ||
                !theMessage.m_strNymID.   Compare(pMsg->m_strNymID))
            {
                ++it;
                continue;
            }
            // --------
            else
            {
                theNumList.Add(lTempReqNum);
            }
            ++it;
        }
    }// else
    // ----------------------------------
    // By this point, theNumList has either been loaded from local storage and had the new number added,
    // or it wasn't in local storage and thus we created it and added all the numnbers to it (including new one.)
    // Therefore nothing left to do here, but save it back again!
    //
    OTString strOutput;
    theNumList.Output(strOutput);
    
    if (!OTDB::StorePlainString(strOutput.Get(), strFolder.Get(), str_data_filename)) // todo hardcoding.
    {
        OTLog::Error("OTMessageOutbuffer::AddSentMessage: Error: failed writing list of request numbers to storage.\n");
    }
}
Example #17
0
bool OTKeypair::CalculateID(Identifier& theOutput) const
{
    OT_ASSERT(m_pkeyPublic);

    return m_pkeyPublic->CalculateID(theOutput); // Only works for public keys.
}
OTMessage * OTMessageOutbuffer::GetSentMessage(const int64_t & lRequestNum, const OTString & strServerID, const OTString & strNymID)
{
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    for ( ; it != m_mapMessages.end(); ++it)
    {
        // -----------------------------
        const int64_t  & lTempReqNum   = it->first;
        // -----------------------
        if (lTempReqNum != lRequestNum)
        {
            continue;
        }
        // -----------------------
        OTMessage   * pMsg          = it->second;
        OT_ASSERT(NULL != pMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        if (!strServerID.Compare(pMsg->m_strServerID) ||
            !strNymID.   Compare(pMsg->m_strNymID))
        {
            continue;
        }
        // --------
        else
        {
            return pMsg;
        }
    }
    // ----------------------------------
    // Didn't find it? Okay let's load it from local storage, if it's there...
    //
    OTString strFolder, strFile;
    strFolder.Format("%s%s%s%s%s%s%s",
                     OTFolders::Nym().Get(),         OTLog::PathSeparator(),
                     strServerID.Get(),          OTLog::PathSeparator(),
                     "sent", /*todo hardcoding*/ OTLog::PathSeparator(),
                     strNymID.Get());
    strFile.Format("%lld.msg", lRequestNum);
    // -----------------------------------
    // Check the existing list, if it exists.
    //
    OTNumList theNumList;
    std::string str_data_filename("sent.dat");
    if (OTDB::Exists(strFolder.Get(), str_data_filename)) // todo hardcoding.
    {
        OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
        
        if (strNumList.Exists())
            theNumList.Add(strNumList);
        
        if (theNumList.Verify(lRequestNum))
        {
            // Even if the outgoing message was stored, we still act like it
            // "doesn't exist" if it doesn't appear on the official list.
            // The list is what matters -- the message is just the contents referenced
            // by that list.
            // -----------------------------------
            OTMessage * pMsg = new OTMessage;
            OT_ASSERT(NULL != pMsg);
            OTCleanup<OTMessage> theMsgAngel(pMsg);
            
            if (OTDB::Exists(strFolder.Get(), strFile.Get()) && pMsg->LoadContract(strFolder.Get(), strFile.Get()))
            {
                // Since we had to load it from local storage, let's add it to
                // the list in RAM.
                //
                m_mapMessages.insert(std::pair<int64_t, OTMessage *>(lRequestNum, pMsg));
                theMsgAngel.SetCleanupTargetPointer(NULL);
                return pMsg;
            }
            // ----------------------------------
        }
    }
    // ----------------------------------
    // STILL didn't find it? (Failure.)
    //
	return NULL;
}
Example #19
0
int main (int argc, char **argv) 
{
	OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Server -- version %s\n"
				   "(transport build: OTMessage -> TCP -> SSL)\n"
				   "NOTE: IF YOU PREFER TO USE XmlRpc with Http transport, then rebuild using:\n"
				   "\"make -f Makefile.rpc\" (but make sure the client is built the same way.)\n\n", 
				   OTLog::Version());
	
	// -----------------------------------------------------------------------
	
	// This object handles all the actual transaction notarization details.
	// (This file you are reading is a wrapper for OTServer, which adds the transport layer.)
	OTServer theServer;

	// -----------------------------------------------------------------------
	
#ifdef _WIN32
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD( 2, 2 );
	int nWSA = WSAStartup( wVersionRequested, &wsaData );
	OT_ASSERT_MSG(0 != nWSA, "Error calling WSAStartup.\n");	
#endif

	OTLog::vOutput(0, "\n\nWelcome to Open Transactions, version %s.\n\n", OTLog::Version());
	
	// -----------------------------------------------------------------------

	OTString strCAFile, strDHFile, strKeyFile, strSSLPassword;

	if (argc < 2)
	{
		OTLog::vOutput(0, "Usage:  transaction <SSL-password> <data_folder path>\n\n"
				"(Password defaults to '%s' if left blank on the command line.)\n"
				"(Folder defaults to '%s' if left blank.)\n", KEY_PASSWORD, SERVER_PATH_DEFAULT);
		
		strSSLPassword.Set(KEY_PASSWORD);
		OTLog::SetMainPath(SERVER_PATH_DEFAULT);
	}
	else if (argc < 3)
	{
		OTLog::vOutput(0, "Usage:  transaction <SSL-password> <data_folder path>\n\n"
				"(Folder defaults to '%s' if left blank.)\n", SERVER_PATH_DEFAULT);
		
		strSSLPassword.Set(argv[1]);
		OTLog::SetMainPath(SERVER_PATH_DEFAULT);
	}
	else 
	{
		strSSLPassword.Set(argv[1]);
		OTLog::SetMainPath(argv[2]);
	}	

	strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE);
	strDHFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), DH_FILE);
	strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE);

	
	// -----------------------------------------------------------------------

	// Init loads up server's nym so it can decrypt messages sent in envelopes.
	// It also does various other initialization work.
	//
	// (Envelopes prove that ONLY someone who actually had the server contract,
	// and had loaded it into his wallet, could ever connect to the server or 
	// communicate with it. And if that person is following the contract, there
	// is only one server he can connect to, and one key he can use to talk to it.)
	
	OTLog::Output(0, 
				  "\n\nNow loading the server nym, which will also ask you for a password, to unlock\n"
				  "its private key. (Default password is \"test\".)\n");

	// Initialize SSL -- This MUST occur before any Private Keys are loaded!
    SFSocketGlobalInit(); // Any app that uses OT has to initialize SSL first.

	theServer.Init(); // Keys, etc are loaded here.

	// -----------------------------------------------------------------------

	// We're going to listen on the same port that is listed in our server contract.
	//
	//
	OTString	strHostname;	// The hostname of this server, according to its own contract.
	int			nPort=0;		// The port of this server, according to its own contract.

	OT_ASSERT_MSG(theServer.GetConnectInfo(strHostname, nPort),
				  "Unable to find my own connect info (which is in my server contract BTW.)\n");
	
	const int	nServerPort = nPort;
	
	// -----------------------------------------------------------------------
	
	
	SFSocket *socket = NULL;
	listOfConnections theConnections;
	
    // Alloc Socket
	socket = SFSocketAlloc();
	OT_ASSERT_MSG(NULL != socket, "SFSocketAlloc Failed\n");
	
    // Initialize SSL Socket
	int nSFSocketInit = SFSocketInit(socket,
					 strCAFile.Get(), 
					 strDHFile.Get(), 
					 strKeyFile.Get(),
					 strSSLPassword.Get(), 
									 NULL);
	
	OT_ASSERT_MSG(nSFSocketInit >= 0, "SFSocketInit Context Failed\n");
	
    // Listen on Address/Port
	int nSFSocketListen = SFSocketListen(socket, INADDR_ANY, nServerPort);
	
	OT_ASSERT_MSG(nSFSocketListen >= 0, "nSFSocketListen Failed\n");
	
	
	theServer.ActivateCron();
	
    do 
	{
        SFSocket * clientSocket = NULL;

        // Accept Client Connection
        if (NULL != (clientSocket = SFSocketAccept(socket)))
		{
			OTClientConnection * pClient = new OTClientConnection(*clientSocket, theServer);
			theConnections.push_back(pClient);
			OTLog::Output(0, "Accepting new connection.\n");
		}
		
		// READ THROUGH ALL CLIENTS HERE, LOOP A LIST
		// AND process in-buffer onto our list of messages.
		
		OTClientConnection * pConnection = NULL;
		
		for (listOfConnections::iterator ii = theConnections.begin(); 
			 ii != theConnections.end(); ++ii)
		{
			if (pConnection = *ii)
			{
				// Here we read the bytes from the pipe into the client's buffer
				// As necessary this function also processes those bytes into OTMessages
				// and adds them to the Input List for that client.
				pConnection->ProcessBuffer();
			}
		}
		
		
		
		// Now loop through them all again, and process their messages onto the reply list.
		
		pConnection = NULL;
		
		for (listOfConnections::iterator ii = theConnections.begin(); 
			 ii != theConnections.end(); ++ii)
		{
			if (pConnection = *ii)
			{
				OTMessage * pMsg = NULL;
				
				while (pMsg = pConnection->GetNextInputMessage())
				{
					OTMessage * pReply = new OTMessage;
					
					OT_ASSERT(NULL != pReply);
					
					if (theServer.ProcessUserCommand(*pMsg, *pReply, pConnection))
					{
						OTLog::vOutput(0, "Successfully processed user command: %s.\n", 
								pMsg->m_strCommand.Get());
						
						pConnection->AddToOutputList(*pReply);
					}
					else
					{
						OTLog::Output(0, "Unable to process user command in XML, or missing payload, in main.\n");
						delete pReply;
						pReply = NULL;
					}
					
					// I am responsible to delete this here.
					delete pMsg;
					pMsg = NULL;
				}
			}
		}
		
		
		// Now loop through them all again, and process their replies down the pipe
		
		pConnection = NULL;
		
		for (listOfConnections::iterator ii = theConnections.begin(); 
			 ii != theConnections.end(); ++ii)
		{
			if (pConnection = *ii)
			{
				OTMessage * pMsg = NULL;
				
				while (pMsg = pConnection->GetNextOutputMessage())
				{
					pConnection->ProcessReply(*pMsg);
						
					// I am responsible to delete this here.
					delete pMsg;
					pMsg = NULL;
				}
			}
		}
		
		
		
		
		
		// The Server now processes certain things on a regular basis.
		// This method call is what gives it the opportunity to do that.
	
		theServer.ProcessCron();
		
		
		
		
		// Now go to sleep for a tenth of a second.
		// (Main loop processes ten times per second, currently.)
		
		OTLog::SleepMilliseconds(100); // 100 ms == (1 second / 10)
		
		
		
		
    } while (1);

    // Close and Release Socket Resources
    SFSocketRelease(socket);

#ifdef _WIN32
	WSACleanup();
#endif

    return(0);
}
// WARNING: ONLY call this (with arguments) directly after a successful @getNymbox has been received!
// See comments below for more details.
//
void OTMessageOutbuffer::Clear(const OTString * pstrServerID/*=NULL*/, const OTString * pstrNymID/*=NULL*/, OTPseudonym * pNym/*=NULL*/,
                               const bool     * pbHarvestingForRetry/*=NULL*/)
{
//  const char * szFuncName		= "OTMessageOutbuffer::Clear";
    // -----------------------------------------------
    
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    while (it != m_mapMessages.end())
    {
        // -----------------------------
        const int64_t  & lRequestNum   = it->first;
        OTMessage   * pThisMsg      = it->second;
        OT_ASSERT(NULL != pThisMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        if (
            ((NULL != pstrServerID) && !pstrServerID->Compare(pThisMsg->m_strServerID)) ||
            ((NULL != pstrNymID)    && !pstrNymID->Compare   (pThisMsg->m_strNymID))
            )
        {
            ++it;
            continue;
        }
        // --------
        else
        {
            /*
             Sent messages are cached because some of them are so important, that
             the server drops a reply notice into the Nymbox to make sure they were
             received. This way, when we download the Nymbox we can SEE which messages
             were ACTUALLY replied to, and at that time, we removed those messages
             already from *this "sent buffer." After that loop was done, we called
             CLEAR (this function) and cleared ALL the sent messages from the buffer
             (for the appropriate server and nym IDs...clear without those IDs is
             only for the destructor.)
             
             This Clear, where we are now, HARVESTS the transaction numbers back
             from any messages left in the sent buffer. We are able to do this with
             confidence because we know that this function is only called in @getNymbox
             on client side, and only after the ones with actual replies (as evidenced
             by the Nymbox) have already been removed from *this "sent buffer."
             
             Why were they removed in advance? Because clearly: if the server HAS replied
             to them already, then there's no need to harvest anything: just let it
             process as normal, whether the transaction inside is a success or fail.
             (We KNOW the message didn't fail because otherwise there wouldn't even be
             a notice in the Nymbox. So this is about the transaction inside.)

             So we remove the ones that we DEFINITELY know the server HAS replied to.
             
             And the ones remaining? We know for those, the server definitely has NOT
             replied to them (the message must have been dropped by the network or
             something.) How do we know this? Because there would be a notice in the
             Nymbox! So at the moment of successful @getNymbox, we are able to loop through
             those receipts and know FOR SURE, WHICH ones definitely have a reply, and
             which ones definitely DO NOT.
             
             The ones where we definitely do NOT have a reply--that is, the ones that are in
             the "sent messages" buffer, but are not in the Nymbox with the same request
             number--we harvest those numbers, since the server clearly never saw them, or
             rejected the message before the transaction itself even had a chance to run.
             
             */
            if (NULL != pNym)
            {
                OT_ASSERT(NULL != pstrNymID && pstrNymID->Exists());
                const OTIdentifier MSG_NYM_ID(*pstrNymID);
                OT_ASSERT(pNym->CompareID(MSG_NYM_ID));
                // ----------------------------
                OT_ASSERT(NULL != pstrServerID && pstrServerID->Exists());
                // ----------------------------
                OT_ASSERT(NULL != pbHarvestingForRetry);
                // ----------------------------
                /*
                 getNymbox			-- client is NOT sending hash, server is NOT rejecting bad hashes, server IS SENDING HASH in the @getNymbox reply
                 getRequest			-- client is NOT sending hash, server is NOT rejecting bad hashes, server IS SENDING HASH in the @getRequest reply
                 
                 processNymbox		-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @processNymbox  reply
                 notarizeTransactions	-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @notarizeTransactions  reply
                 processInbox 		-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @processInbox  reply
                 triggerClause 		-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @triggerClause reply
                 
                 getTransactionNum 	-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @getTransactionNum reply
                 
                 Already covered in NotarizeTransaction: 
                    transfer, withdrawal, deposit, marketOffer, paymentPlan, smartContract, cancelCronItem, exchangeBasket
                 */
                
                if (pThisMsg->m_ascPayload.Exists() &&
                    (
                     pThisMsg->m_strCommand.Compare("processNymbox")        ||
                     pThisMsg->m_strCommand.Compare("processInbox")         ||
                     pThisMsg->m_strCommand.Compare("notarizeTransactions") ||
                     pThisMsg->m_strCommand.Compare("triggerClause")
                    )
                   )
                {
                    // 
                    // If we are here in the first place (i.e. after @getNymbox just removed
                    // all the messages in this sent buffer that already had a reply sitting
                    // in the nymbox) therefore we KNOW any messages in here never got a reply
                    // from the server, 
                    
                    const bool bReplyWasSuccess        = false; // If the msg had been a success, the reply (whether transaction within succeeded or failed) would have been dropped into my Nymbox, and thus removed from this "sent buffer" in @getNymbox.
                    const bool bReplyWasFailure        = true; // If the msg had been an explicit failure, the reply (without the transaction inside of it even having a chance to succeed or fail) would definitely NOT have been dropped into my Nymbox, and thus removed from this "sent buffer" in @getNymbox. However, IN THIS ONE CASE, since we DID just download the Nymbox and verify there ARE NO REPLIES for this request number (before calling this function), and since a dropped message is basically identical to a rejected message, since in either case, the transaction itself never even had a chance to run, we are able to now harvest the message AS IF the server HAD explicitly rejected the message. This is why I pass true here, where anywhere else in the code I would always pass false unless I had explicitly received a failure from the server. This place in the code, where we are now, is the failsafe endpoint for missed/dropped messages! IF they STILL haven't been found by this point, they are cleaned up as if the message was explicitly rejected by the server before the transaction even had a chance to run.

                    const bool bTransactionWasSuccess  = false; // Per above, since "the transaction never had a chance to run" then it could NOT have been an explicit success.
                    const bool bTransactionWasFailure  = false; // Per above, since "the transaction never had a chance to run" then it could NOT have been an explicit failure.
                    // -----------------------------------------------------
                    pThisMsg->HarvestTransactionNumbers(*pNym,      // Actually it's pNym who is "harvesting" the numbers in this call.   <========= HARVEST
                                                        *pbHarvestingForRetry,
                                                        bReplyWasSuccess,
                                                        bReplyWasFailure,
                                                        bTransactionWasSuccess,
                                                        bTransactionWasFailure);
                } // if there's a transaction to be harvested inside this message.
            } // if pNym !NULL
            // ----------------------
            mapOfMessages::iterator temp_it = it;
            ++temp_it;
            m_mapMessages.erase(it);
            it = temp_it; // here's where the iterator gets incremented (during the erase, basically.)
            // ----------------------
            delete pThisMsg;                // <============ DELETE
            pThisMsg = NULL;
            // ---------------------------------------------------------------------------
            if (NULL != pstrNymID && NULL != pstrServerID)
            {
                OTString strFolder, strFile;
                strFolder.Format("%s%s%s%s%s%s%s",
                                 OTFolders::Nym().Get(),     OTLog::PathSeparator(),
                                 pstrServerID->Get(),        OTLog::PathSeparator(),
                                 "sent", /*todo hardcoding*/ OTLog::PathSeparator(),
                                 pstrNymID->Get());
                strFile.Format("%lld.msg", lRequestNum);
                // ---------------------------------------------------------------------------
                OTNumList theNumList;
                std::string str_data_filename("sent.dat");  // todo hardcoding.
                if (OTDB::Exists(strFolder.Get(), str_data_filename))
                {
                    OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
                    if (strNumList.Exists())
                        theNumList.Add(strNumList);
                    theNumList.Remove(lRequestNum); // Clear (this function) loops and removes them. (Here's the one being removed this iteration.)
                }
                else // it doesn't exist on disk, so let's just create it from the list we have in RAM so we can store it to disk.
                {    // NOTE: this may be unnecessary since we are "clear"ing them all anyway. But that just means we can remove this
                     // block during optimization. Todo optimize.
                     // Since we create the NumList based on m_mapMessages, and since the message for this iteration was already removed
                     // above, we don't need to remove anything at this point, we just create the NumList to contain the same numbers as are
                     // in m_mapMessages.
                     //
                    it = m_mapMessages.begin();
                    while (it != m_mapMessages.end())
                    {
                        // -----------------------------
                        const int64_t  & lTempReqNum   = it->first;
                        // -----------------------
                        OTMessage   * pMsg          = it->second;
                        OT_ASSERT(NULL != pMsg);
                        // -----------------------------
                        //
                        // If a server ID was passed in, but doesn't match the server ID on this message,
                        // Then skip this one. (Same with the NymID.)
                        //
                        if (!pstrServerID->Compare(pMsg->m_strServerID) ||
                            !pstrNymID->   Compare(pMsg->m_strNymID))
                        {
                            ++it;
                            continue;
                        }
                        // --------
                        else
                        {
                            theNumList.Add(lTempReqNum);
                        }
                        ++it;
                    }
                }// else
                // ----------------------------------
                // By this point, theNumList has either been loaded from local storage and had the number removed,
                // or it wasn't in local storage and thus we created it and added all the numbers to it from RAM (not
                // including the one being erased, since it was already removed from the RAM list, above.) So either
                // way, the number being removed is now ABSENT from theNumList.
                //
                // Therefore nothing left to do here, but save it back again!
                //
                OTString strOutput;
                theNumList.Output(strOutput);
                if (!OTDB::StorePlainString(strOutput.Get(), strFolder.Get(), str_data_filename)) // todo hardcoding.
                {
                    OTLog::Error("OTMessageOutbuffer::Clear: Error: failed writing list of request numbers to storage.\n");
                }
                // ----------------------------------
                // Make sure any messages being erased here, are also erased from local storage.
                // Now that we've updated the numlist in local storage, let's
                // erase the sent message itself...
                //
                OTMessage * pMsg = new OTMessage;
                OT_ASSERT(NULL != pMsg);
                OTCleanup<OTMessage> theMsgAngel(pMsg);
                
                if (OTDB::Exists(strFolder.Get(), strFile.Get()) && pMsg->LoadContract(strFolder.Get(), strFile.Get()))
                {
                    OTDB::EraseValueByKey(strFolder.Get(), strFile.Get());
                }
            }
            // ---------------------------------------------------------------------------
        }
    }
}
Example #21
0
// static
bool String::vformat(const char* fmt, va_list* pvl, std::string& str_Output)
{
    OT_ASSERT(nullptr != fmt);
    OT_ASSERT(nullptr != pvl);

    int32_t size = 0;
    int32_t nsize = 0;
    char* buffer = nullptr;
    va_list args;

#ifdef _WIN32
    va_list args_2 = *pvl; // windows only.

    args = *pvl;
    size = _vscprintf(fmt, args) + 1;
#else
    va_copy(args, *pvl);
    size = 512;
#endif

    buffer = new char[size + 100];
    OT_ASSERT(nullptr != buffer);
    OTPassword::zeroMemory(buffer, size + 100);

#ifdef _WIN32
    nsize = vsnprintf_s(buffer, size, size, fmt, args_2);
#else
    nsize = vsnprintf(buffer, size, fmt, args);
    va_end(args);
#endif

    OT_ASSERT(nsize >= 0);

    // fail -- delete buffer and try again
    // If nsize was 1024 bytes, then that would mean that it printed 1024
    // characters,
    // even though the actual string must be 1025 in length (to have room for
    // the null
    // terminator.)
    // If size, the ACTUAL buffer, was 1024 (that is, if size <= nsize) then
    // size would
    // LACK the necessary space to store the 1025th byte containing the null
    // terminator.
    // Therefore we are forced to delete the buffer and make one that is
    // nsize+1, so that
    // it will be 1025 bytes and thus have the necessary space for the
    // terminator
    //
    if (size <= nsize) {
        size = nsize + 1;
        delete[] buffer;
        buffer = new char[size + 100];
        OT_ASSERT(nullptr != buffer);
        OTPassword::zeroMemory(buffer, size + 100);

#ifdef _WIN32
        nsize = vsnprintf_s(buffer, size, size, fmt, *pvl);
        va_end(args);
        va_end(args_2);
#else
        nsize = vsnprintf(buffer, size, fmt, *pvl);
#endif

        OT_ASSERT(nsize >= 0);
    }
    OT_ASSERT(size > nsize);

    str_Output = buffer;
    delete[] buffer;
    buffer = nullptr;
    return true;
}
// OTMessageOutbuffer deletes the OTMessage when you call this.
//
bool OTMessageOutbuffer::RemoveSentMessage(const int64_t & lRequestNum, const OTString & strServerID, const OTString & strNymID)
{
    OTString strFolder, strFile;
    strFolder.Format("%s%s%s%s%s%s%s",
                     OTFolders::Nym().Get(),         OTLog::PathSeparator(),
                     strServerID.Get(),          OTLog::PathSeparator(),
                     "sent", /*todo hardcoding*/ OTLog::PathSeparator(),
                     strNymID.Get());
    strFile.Format("%lld.msg", lRequestNum);
    // ------------------------------------------------
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    bool bReturnValue = false;
    
    while (it != m_mapMessages.end())
    {
        // -----------------------------
        const int64_t  & lTempReqNum   = it->first;
        // -----------------------
        if (lTempReqNum != lRequestNum)
        {
            ++it;
            continue;
        }
        // -----------------------
        OTMessage   * pMsg          = it->second;
        OT_ASSERT(NULL != pMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        if (!strServerID.Compare(pMsg->m_strServerID) ||
            !strNymID.   Compare(pMsg->m_strNymID))
        {
            ++it;
            continue;
        }
        // --------
        else
        {
            delete pMsg; pMsg = NULL;
            // ----------------------
            mapOfMessages::iterator temp_it = it;
            ++temp_it;
            m_mapMessages.erase(it);
            it = temp_it; // here's where it gets incremented. (During the erase, basically.)
            // ----------------------
            bReturnValue = true;
            break;
        }
    }
    // ----------------------------------
    // Whether we found it in RAM or not, let's make sure to delete it from
    // local storage, if it's there... (Since there's a list there we have to update,
    // anyway.)
    // We keep a list of the request numbers, so let's load it up, remove the number
    // from that list, and then save it again.
    // ----------------------------------
    OTNumList theNumList;
    std::string str_data_filename("sent.dat");  // todo hardcoding.
    if (OTDB::Exists(strFolder.Get(), str_data_filename))
    {
        OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
        if (strNumList.Exists())
            theNumList.Add(strNumList);
        theNumList.Remove(lRequestNum);
    }
    else // it doesn't exist on disk, so let's just create it from the list we have in RAM so we can store it to disk.
    {
        it = m_mapMessages.begin();
        while (it != m_mapMessages.end())
        {
            // -----------------------------
            const int64_t  & lTempReqNum   = it->first;
            // -----------------------
            OTMessage   * pMsg          = it->second;
            OT_ASSERT(NULL != pMsg);
            // -----------------------------
            //
            // If a server ID was passed in, but doesn't match the server ID on this message,
            // Then skip this one. (Same with the NymID.)
            //
            if (!strServerID.Compare(pMsg->m_strServerID) ||
                !strNymID.   Compare(pMsg->m_strNymID))
            {
                ++it;
                continue;
            }
            // --------
            else
            {
                theNumList.Add(lTempReqNum);
            }
            ++it;
        }
    }// else
    // ----------------------------------
    // By this point, theNumList has either been loaded from local storage and had the number removed,
    // or it wasn't in local storage and thus we created it and added all the numbers to it from RAM (not
    // including the one being erased, since it was already removed from the RAM list, above.) So either
    // way, the number being removed is now ABSENT from theNumList.
    //
    // Therefore nothing left to do here, but save it back again!
    //
    OTString strOutput;
    theNumList.Output(strOutput);
    if (!OTDB::StorePlainString(strOutput.Get(), strFolder.Get(), str_data_filename))
    {
        OTLog::Error("OTMessageOutbuffer::RemoveSentMessage: Error: failed writing list of request numbers to storage.\n");
    }
    // ----------------------------------
    // Now that we've updated the numlist in local storage, let's
    // erase the sent message itself...
    //
    OTMessage * pMsg = new OTMessage;
    OT_ASSERT(NULL != pMsg);
    OTCleanup<OTMessage> theMsgAngel(pMsg);
    
    if (OTDB::Exists(strFolder.Get(), strFile.Get()) && pMsg->LoadContract(strFolder.Get(), strFile.Get()))
    {
        OTDB::EraseValueByKey(strFolder.Get(), strFile.Get());
        return true;
    }
    // ----------------------------------
	return bReturnValue;
}
// This version is fully functional, and performs compression in addition to base64-encoding.
//
bool OTASCIIArmor::SetString(const OTString & strData, bool bLineBreaks) //=true
{
	
	return SetAndPackString(strData, bLineBreaks);
	
	
	// ---------------------------------------------------------------
	
//	OTLog::vError("DEBUGGING OTASCIIARMOR::SETSTRING, INPUT:  --------->%s<---------", strData.Get());
	
	Release();
	
	if (strData.GetLength() < 1)
		return true;
	
	char *	pString	= NULL;
	
	// Set up source buffer and destination buffer
	long nDestLen	= DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.)
	const	long lSourcelen	= sizeof(unsigned char)*strData.GetLength()+1;// for null terminator
	
	unsigned char* pSource	= new unsigned char[lSourcelen+10]; // for safety
	unsigned char* pDest	= new unsigned char[nDestLen+10]; // for safety
	
	OT_ASSERT(NULL != pSource);
	OT_ASSERT(NULL != pDest);
	
    OTPassword::safe_memcpy(pSource, lSourcelen, (const unsigned char*)strData.Get(), lSourcelen);
//	memcpy(pSource, (const unsigned char*)strData.Get(), lSourcelen );
	
	// Now we are compressing first before base64-encoding (for strings, anyway)	
	int nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	
	// If the destination buffer wasn't the right size the first time around,
	// then we re-allocate it to the right size (which we now know) and try again...
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = new unsigned char [nDestLen]; // enough room now
		
		OT_ASSERT(NULL != pDest);
		
		nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	}
	
	// Clean this up...
	delete [] pSource;
	pSource = NULL;
	
	// Still errors?
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "Error allocating memory in OTASCIIArmor::SetString\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::SetString\n");
		return false; // not really necessary but just making sure.
	}
	else if ( nErr == EZ_DATA_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "corrupted pSrc passed to ezuncompress OTASCIIArmor::SetString\n");
		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::SetString\n");
		return false; // not really necessary but just making sure.
	}
	
	
	OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetString\n");
	
	// Success
	if (0 < nDestLen)
	{
		// Now let's base-64 encode it...
		pString = OT_base64_encode((const uint8_t*)pDest, nDestLen, (bLineBreaks ? 1 : 0));
		//	pString = OT_base64_encode((const uint8_t*)strData.Get(), strData.GetLength()+1, (bLineBreaks ? 1 : 0)); // this was before we used compression.
		
		delete [] pDest;
		pDest = NULL;
		
		if (pString)
		{
			Set(pString);
			delete [] pString; pString=NULL; 
			return true;
		}
		else 
		{
			OTLog::Error("pString NULL in OTASCIIArmor::SetString\n");
		}
	}
	else 
	{
		OTLog::Error("nDestLen 0 in OTASCIIArmor::SetString\n");
	}
	
	if (pDest)
		delete [] pDest;
	
	pDest = NULL;
	
	return false;
}
// This is called by OTCronItem::HookRemovalFromCron
// (After calling this method, HookRemovalFromCron then calls onRemovalFromCron.)
//
void OTAgreement::onFinalReceipt(OTCronItem & theOrigCronItem,
                                 const long & lNewTransactionNumber,
                                 OTPseudonym & theOriginator,
                                 OTPseudonym * pRemover)
{    
    OTCron * pCron  = GetCron();
    OT_ASSERT(NULL != pCron);
    
    OTPseudonym * pServerNym = pCron->GetServerNym();
    OT_ASSERT(NULL != pServerNym);
    
    // -------------------------------------------------
    
    // The finalReceipt Item's ATTACHMENT contains the UPDATED Cron Item.
    // (With the SERVER's signature on it!)
    //
    OTString strUpdatedCronItem(*this);
    OTString * pstrAttachment=&strUpdatedCronItem;
    
    const OTString strOrigCronItem(theOrigCronItem);
    // -----------------------------------------------------------------

    
    OTPseudonym theRecipientNym; // Don't use this... use the pointer just below.
    
    // The Nym who is actively requesting to remove a cron item will be passed in as pRemover.
    // However, sometimes there is no Nym... perhaps it just expired and pRemover is NULL.
    // The originating Nym (if different than remover) is loaded up. Otherwise the originator
    // pointer just pointers to *pRemover.
    //
    OTPseudonym * pRecipient = NULL;
    
    if (pServerNym->CompareID(this->GetRecipientUserID()))
    {
        pRecipient = pServerNym; // Just in case the recipient Nym is also the server Nym.
    }
    // *******************************************************
    //
    // If pRemover is NOT NULL, and he has the Recipient's ID...
    // then set the pointer accordingly.
    //
    else if ((NULL != pRemover) && (true == pRemover->CompareID(this->GetRecipientUserID())))
    {
        pRecipient = pRemover; // <======== now both pointers are set (to same Nym). DONE!
    }
    // --------------------------------------------------------------------------------------------------

    if (NULL == pRecipient)
    {
        // GetSenderUserID() should be the same on THIS (updated version of the same cron item) 
        // but for whatever reason, I'm checking the userID on the original version. Sue me.
        //
        const OTIdentifier NYM_ID(this->GetRecipientUserID());
        
        theRecipientNym.SetIdentifier(NYM_ID);  
        
        if (false == theRecipientNym.LoadPublicKey())
        {
            OTString strNymID(NYM_ID);
            OTLog::vError("OTAgreement::onFinalReceipt: Failure loading Recipient's public key:\n%s\n", strNymID.Get());
        }		
        else if (theRecipientNym.VerifyPseudonym() && 
                 theRecipientNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is merely the signer on this file.
        {
            pRecipient = &theRecipientNym; //  <=====
        }
        else 
        {
            OTString strNymID(NYM_ID);
            OTLog::vError("OTAgreement::onFinalReceipt: Failure verifying Recipient's public key or loading signed nymfile: %s\n",
                          strNymID.Get());
        }
    }
    
    // -------------------------------

    // First, we are closing the transaction number ITSELF, of this cron item,
    // as an active issued number on the originating nym. (Changing it to CLOSED.)
    //
    // Second, we're verifying the CLOSING number, and using it as the closing number
    // on the FINAL RECEIPT (with that receipt being "InReferenceTo" this->GetTransactionNum())
    //
    const long lRecipientOpeningNumber = this->GetRecipientOpeningNum();
    const long lRecipientClosingNumber = this->GetRecipientClosingNum();
    
    // -----------------------------------------------------------------------------------
    const long lSenderOpeningNumber = theOrigCronItem.GetTransactionNum();

    const long lSenderClosingNumber = (theOrigCronItem.GetCountClosingNumbers() > 0) ? 
        theOrigCronItem.GetClosingTransactionNoAt(0) : 0; // index 0 is closing number for sender, since GetTransactionNum() is his opening #.
    
    // ----------------------------------
        
    const OTString strServerID(GetServerID());
    
    // -----------------------------------------------------------------
    //
    
    if ((lSenderOpeningNumber > 0) &&
        theOriginator.VerifyIssuedNum(strServerID, lSenderOpeningNumber))
    {
        // The Nym (server side) stores a list of all opening and closing cron #s.
        // So when the number is released from the Nym, we also take it off that list.
        //
        std::set<long> & theIDSet = theOriginator.GetSetOpenCronItems();
        theIDSet.erase(lSenderOpeningNumber);
        
        // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED.
        // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out.
        // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it
        // remains ISSUED, until the final receipt itself is accepted during a process inbox.
        //
        theOriginator.RemoveIssuedNum(*pServerNym, strServerID, lSenderOpeningNumber, false); //bSave=false
        theOriginator.SaveSignedNymfile(*pServerNym);
        // ------------------------------------
        
        OTPseudonym *   pActualNym = NULL;  // use this. DON'T use theActualNym.
        OTPseudonym     theActualNym; // unused unless it's really not already loaded. (use pActualNym.)
        const OTIdentifier ACTUAL_NYM_ID = GetSenderUserID();
        
        if ( (NULL != pServerNym) && pServerNym->CompareID(ACTUAL_NYM_ID) )
            pActualNym = pServerNym;
        else if (theOriginator.CompareID(ACTUAL_NYM_ID))
            pActualNym = &theOriginator;
        else if ( (NULL != pRemover) && pRemover->CompareID(ACTUAL_NYM_ID) )
            pActualNym = pRemover;
        // --------------------------
        else    // We couldn't find the Nym among those already loaded--so we have to load
        {       // it ourselves (so we can update its NymboxHash value.)
            theActualNym.SetIdentifier(ACTUAL_NYM_ID);
            
            if (false == theActualNym.LoadPublicKey()) // Note: this step may be unnecessary since we are only updating his Nymfile, not his key.
            {
                OTString strNymID(ACTUAL_NYM_ID);
                OTLog::vError("OTAgreement::onFinalReceipt: Failure loading public key for Nym: %s. "
                              "(To update his NymboxHash.) \n", strNymID.Get());
            }
            else if (theActualNym.VerifyPseudonym()	&& // this line may be unnecessary.
                     theActualNym.LoadSignedNymfile(*pServerNym)) // ServerNym here is not theActualNym's identity, but merely the signer on this file.
            {
                OTLog::Output(0, "OTAgreement::onFinalReceipt: Loading actual Nym, since he wasn't already loaded. "
                              "(To update his NymboxHash.)\n");
                pActualNym = &theActualNym; //  <=====
            }
            else
            {
                OTString strNymID(ACTUAL_NYM_ID);
                OTLog::vError("OTAgreement::onFinalReceipt: Failure loading or verifying Actual Nym public key: %s. "
                              "(To update his NymboxHash.)\n", strNymID.Get());
            }
        }
        // -------------
        
        if (false == this->DropFinalReceiptToNymbox(GetSenderUserID(),
                                                    lNewTransactionNumber,
                                                    strOrigCronItem,
                                                    NULL,
                                                    pstrAttachment,
                                                    pActualNym))
        {
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping sender final receipt into nymbox.\n");
        }        
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failure verifying sender's opening number.\n");
    }
    
    // -----------------------------------------------------------------
    
    if ((lSenderClosingNumber > 0) &&
        theOriginator.VerifyIssuedNum(strServerID, lSenderClosingNumber)         
        ) // ---------------------------------------------------------------
    {
        // In this case, I'm passing NULL for pstrNote, since there is no note.
        // (Additional information would normally be stored in the note.) 
        
        if (false == this->DropFinalReceiptToInbox(GetSenderUserID(),
                                          GetSenderAcctID(),
                                          lNewTransactionNumber,
                                          lSenderClosingNumber, // The closing transaction number to put on the receipt.
                                          strOrigCronItem,
                                          NULL, 
                                          pstrAttachment))
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into sender's inbox.\n");

        // This part below doesn't happen until theOriginator ACCEPTS the final receipt (when processing his inbox.)
        //
//      theOriginator.RemoveIssuedNum(strServerID, lSenderClosingNumber, true); //bSave=false
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying lSenderClosingNumber=theOrigCronItem.GetClosingTransactionNoAt(0)>0 &&  "
                     "theOriginator.VerifyTransactionNum(lSenderClosingNumber)\n");
    }
    // -----------------------------------------------------------------
    //
    if ((NULL != pRecipient) && (lRecipientOpeningNumber > 0) && 
        pRecipient->VerifyIssuedNum(strServerID, lRecipientOpeningNumber)
        )
    {
        // The Nym (server side) stores a list of all opening and closing cron #s.
        // So when the number is released from the Nym, we also take it off that list.
        //
        std::set<long> & theIDSet = pRecipient->GetSetOpenCronItems();
        theIDSet.erase(lRecipientOpeningNumber);
        
        // the RemoveIssued call means the original transaction# (to find this cron item on cron) is now CLOSED.
        // But the Transaction itself is still OPEN. How? Because the CLOSING number is still signed out.
        // The closing number is also USED, since the NotarizePaymentPlan or NotarizeMarketOffer call, but it
        // remains ISSUED, until the final receipt itself is accepted during a process inbox.
        //
        pRecipient->RemoveIssuedNum(*pServerNym, strServerID, lRecipientOpeningNumber, false); //bSave=false       
//      pRecipient->SaveSignedNymfile(*pServerNym); // Moved lower.
        // -----------------------------------------------------
        
        if (false == this->DropFinalReceiptToNymbox(GetRecipientUserID(),
                                                    lNewTransactionNumber,
                                                    strOrigCronItem,
                                                    NULL,
                                                    pstrAttachment,
                                                    pRecipient)) // NymboxHash is updated here in pRecipient.
        {
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping recipient final receipt into nymbox.\n");
        }
        // -----------------------------------------------------

        // Saving both the Removed Issued Number, as well as the new NymboxHash.
        // NOTE: Todo: if the NymboxHash WAS updated (as it should have been) then
        // it was probably saved at that time. Below is therefore a redundant save.
        // Need to fix by making certain objects savable and dirty, and then let them
        // autosave before destruction, IF they are dirty.
        //
        pRecipient->SaveSignedNymfile(*pServerNym); 
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying "
                     "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 &&  "
                     "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n");
    }
    
    // -----------------------------------------------------------------
    
    if ((NULL != pRecipient) && (lRecipientClosingNumber > 0) && 
        pRecipient->VerifyIssuedNum(strServerID, lRecipientClosingNumber)
        )
    {
        if (false == this->DropFinalReceiptToInbox(GetRecipientUserID(),
                                      GetRecipientAcctID(),
                                      lNewTransactionNumber,
                                      lRecipientClosingNumber, // The closing transaction number to put on the receipt.
                                      strOrigCronItem,
                                      NULL,
                                      pstrAttachment))
            OTLog::Error("OTAgreement::onFinalReceipt: Failure dropping receipt into recipient's inbox.\n");

        // This part below doesn't happen until pRecipient ACCEPTs the final receipt (when processing his inbox.)
        //
//      pRecipient->RemoveIssuedNum(strServerID, lRecipientClosingNumber, true); //bSave=false
    }
    else
    {
        OTLog::Error("OTAgreement::onFinalReceipt: Failed verifying "
                     "lRecipientClosingNumber=this->GetRecipientClosingTransactionNoAt(1)>0 &&  "
                     "pRecipient->VerifyTransactionNum(lRecipientClosingNumber) && VerifyIssuedNum(lRecipientOpeningNumber)\n");
    }
    
    // QUESTION: Won't there be Cron Items that have no asset account at all?
    // In which case, there'd be no need to drop a final receipt, but I don't think
    // that's the case, since you have to use a transaction number to get onto cron
    // in the first place.
    // -----------------------------------------------------------------
}
/// 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 = 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_ASSERT_MSG(false, "Buffer error in OTASCIIArmor::GetAndUnpackString\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::GetAndUnpackString\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::GetAndUnpackString, 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::GetAndUnpackString\n");
			return false; // not really necessary but just making sure.
		}
		
		// ---------------------------------------
		
		// 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;
	}
}
Example #26
0
// Return the public key as an OTAsymmetricKey object
// TODO this violates encapsulation and should be deprecated
const OTAsymmetricKey& OTKeypair::GetPublicKey() const
{
    OT_ASSERT(m_pkeyPublic);

    return (*m_pkeyPublic);
}
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;
	
}
Example #28
0
// Return the private key as an OTAsymmetricKey object
// TODO this violates encapsulation and should be deprecated
const OTAsymmetricKey& OTKeypair::GetPrivateKey() const
{
    OT_ASSERT(m_pkeyPrivate);

    return (*m_pkeyPrivate);
}
Example #29
0
bool OTASCIIArmor::GetString(OTString & theData, bool bLineBreaks) const //bLineBreaks=true
{	
	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;
	}
}
Example #30
0
// UNIX:
//    void * memcpy(void* restrict s1, const void* restrict s2, size_t n);
//
// static
void* OTPassword::safe_memcpy(void* dest, uint32_t dest_size, const void* src,
                              uint32_t src_length,
                              bool bZeroSource) // if true, sets the
                                                // source buffer to
                                                // zero after copying
                                                // is done.
{
    // Make sure they aren't null.
    OT_ASSERT(nullptr != dest);
    OT_ASSERT(nullptr != src);

    // Make sure they aren't the same pointer.
    OT_ASSERT(src != dest);

    // Make sure it will fit.
    OT_ASSERT_MSG(src_length <= dest_size,
                  "ASSERT: safe_memcpy: destination buffer too small.\n");

    // Make sure they don't overlap.
    // First assert does the beginning of the string, makes sure it's not within
    // the bounds of the destination
    // string. Second assert does the same thing for the end of the string.
    // Finally a third is needed to make sure
    // we're not in a situation where the beginning is less than the dest
    // beginning, yet the end is also more than
    // the dest ending!
    //
    OT_ASSERT_MSG(
        false ==
            ((static_cast<const uint8_t*>(src) > static_cast<uint8_t*>(dest)) &&
             (static_cast<const uint8_t*>(src) <
              (static_cast<uint8_t*>(dest) + dest_size))),
        "ASSERT: safe_memcpy: Unexpected memory overlap, start of src.\n");
    OT_ASSERT_MSG(
        false == (((static_cast<const uint8_t*>(src) + src_length) >
                   static_cast<uint8_t*>(dest)) &&
                  ((static_cast<const uint8_t*>(src) + src_length) <
                   (static_cast<uint8_t*>(dest) + dest_size))),
        "ASSERT: safe_memcpy: Unexpected memory overlap, end of src.\n");
    OT_ASSERT(false == ((static_cast<const uint8_t*>(src) <=
                         static_cast<uint8_t*>(dest)) &&
                        ((static_cast<const uint8_t*>(src) + src_length) >=
                         (static_cast<uint8_t*>(dest) + dest_size))));

#ifdef _WIN32
    bool bSuccess = (0 == memcpy_s(dest, static_cast<size_t>(dest_size), src,
                                   static_cast<size_t>(src_length)));
#else
    bool bSuccess =
        (memcpy(dest, src, static_cast<size_t>(src_length)) == dest);
#endif

    if (bSuccess) {
        if (bZeroSource) {
            OTPassword::zeroMemory(const_cast<void*>(src), src_length);
        }

        return dest;
    }

    return nullptr;
}