// Low-level
//
// (Internal) ASCII-Armored key ====> (Internal) Actual loaded OpenSSL key.
//
//
EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::InstantiatePublicKey(OTPasswordData * pPWData/*=NULL*/)
{
    OT_ASSERT(m_pKey     == NULL);
    OT_ASSERT(backlink->m_p_ascKey != NULL);
    OT_ASSERT(backlink->IsPublic());
    
    const char * szFunc = "OTAsymmetricKey_OpenSSL::InstantiatePublicKey";
    // ------------------------------
    EVP_PKEY * pReturnKey = NULL;
    OTPayload  theData;
    // -----------------------------------------------
    // This base64 decodes the string m_p_ascKey into the
    // binary payload object "theData"
    //
    backlink->m_p_ascKey->GetData(theData);
    
    if (theData.GetSize() > 0)
    {
        // -------------------------------------------
        // Next, copy theData's contents into a new BIO_mem_buf,
        // so OpenSSL can load the key out of it.
        //
        OpenSSL_BIO keyBio	= BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), 
                                      theData.GetSize());
        OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::InstantiatePublicKey: Assert: NULL != keyBio \n");
        // -------------------------------------------
        // Next we load up the key from the BIO string into an instantiated key object.
        //
        OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::InstantiatePublicKey is calling PEM_read_bio_PUBKEY...");
        
        if (NULL == pPWData)
            pPWData = &thePWData;
        
        pReturnKey = PEM_read_bio_PUBKEY(keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), pPWData);
        // -------------------------------------------

        // -------------------------------------------
        backlink->ReleaseKeyLowLevel(); // Release whatever loaded key I might have already had.
        
        if (NULL != pReturnKey)
        {
            m_pKey = pReturnKey;
            OTLog::vOutput(4, "%s: Success reading public key from ASCII-armored data:\n\n%s\n\n",
                           szFunc, backlink->m_p_ascKey->Get());
            return m_pKey;
        }
    }
    
    OTLog::vError("%s: Failed reading public key from ASCII-armored data:\n\n%s\n\n", 
                  szFunc, backlink->m_p_ascKey->Get());
    return NULL;
}
void SetupHeader( union u_header * pCMD, int nTypeID, int nCmdID, OTPayload & thePayload)
{
	pCMD->fields.type_id	= nTypeID;
	pCMD->fields.command_id	= nCmdID;
//	pCMD->fields.size		= thePayload.GetSize();
	pCMD->fields.size		= htonl(thePayload.GetSize()); // think this is causing problems
	pCMD->fields.checksum	= CalcChecksum(pCMD->buf, OT_CMD_HEADER_SIZE-1);
	
	BYTE byChecksum	= (BYTE)pCMD->fields.checksum;
	int nChecksum	= byChecksum;
	
	uint32_t nTemp	= thePayload.GetSize();
	fprintf(stderr, "(Payload size %d, TYPE %d command, checksum: %d...)\n", nTemp, nTypeID, nChecksum);
}
void SetupHeader( union u_header * pCMD, int nTypeID, int nCmdID, OTPayload & thePayload)
{
	OT_ASSERT(NULL != pCMD);
	
	pCMD->fields.type_id	= (nTypeID > 0) ? static_cast<BYTE>(nTypeID) : '\0';
	pCMD->fields.command_id	= (nCmdID > 0) ? static_cast<BYTE>(nCmdID) : '\0';
//	pCMD->fields.size		= thePayload.GetSize();
	pCMD->fields.size		= htonl(thePayload.GetSize()); // think this is causing problems
	pCMD->fields.checksum	= CalcChecksum(pCMD->buf, OT_CMD_HEADER_SIZE-1);
	
	BYTE byChecksum	= (BYTE)pCMD->fields.checksum;
	int nChecksum	= byChecksum;
	
	uint32_t nTemp	= thePayload.GetSize();
	OTLog::vOutput(4, "(Payload size %d, TYPE %d command, checksum: %d...)\n", nTemp, nTypeID, nChecksum);
}
Example #4
0
// The above method uses this one internally...
bool OTAccount::GenerateNewAccount(const OTPseudonym & theServer, const OTMessage & theMessage,
								   const OTAccount::AccountType eAcctType/*=OTAccount::simple*/)
{
	// First we generate a secure random number into a binary object.
	OTPayload thePayload;
	thePayload.SetPayloadSize(100);
	if (!RAND_bytes((unsigned char*)thePayload.GetPayloadPointer(), 100)) 
	{
		OTLog::Error("The PRNG is not seeded!\n");
//		abort(  );
		return false;	
	}
	
	// Next we calculate that binary object into a message digest (an OTIdentifier).
	OTIdentifier newID;
	if (!newID.CalculateDigest(thePayload))
	{
		OTLog::Error("Error generating new account ID.\n");
		return false;	
	}		
	
	// Next we get that digest (which is a binary hash number)
	// and extract a human-readable standard string format of that hash,
	// into an OTString.
	OTString strID(newID);
	
	SetRealAccountID(newID);		// Set the account number based on what we just generated.
	SetPurportedAccountID(newID);	// Might as well set them both. (Safe here to do so, for once.)

	m_strName.Set(strID); // So it's not blank. The user can always change it.
	
	// Next we create the full path filename for the account using the ID.
	m_strFilename.Format("%s%s%s%s%s", OTLog::Path(), OTLog::PathSeparator(),
						 OTLog::AccountFolder(),
						 OTLog::PathSeparator(), strID.Get());
	
	// Then we try to load it, in order to make sure that it doesn't already exist.
	if (LoadContractRawFile())
	{
		OTLog::Error("Error generating new account ID, account already exists.\n");
		return false;	
	}

	// Set up the various important starting values of the account.
	m_AcctType = eAcctType; // account type defaults to OTAccount::simple. But there are also issuer accts...
	
	// for basket accounts, the server is the user.
	if (OTAccount::basket == eAcctType)
	{
		theServer.GetIdentifier(m_AcctUserID);
	}
	else 
	{
		m_AcctUserID.SetString(theMessage.m_strNymID);
	}

	m_AcctAssetTypeID.SetString(theMessage.m_strAssetID);
	
	OTString TEMPstr(m_AcctAssetTypeID);

	OTLog::vOutput(3, "Creating new account, type:\n%s\nChanged to ID then back to string:\n%s\n", 
				   theMessage.m_strAssetID.Get(), TEMPstr.Get());
	
	OTIdentifier SERVER_ID(theMessage.m_strServerID);	
	SetRealServerID(SERVER_ID);			// todo this assumes the serverID on the message is correct. It's vetted, but still...
	SetPurportedServerID(SERVER_ID);

	const time_t tDate = time(NULL); // Today, now.
	m_BalanceDate.Format("%d", tDate);
		
	m_BalanceAmount.Set("0");
	
		
	// Sign the Account (so we know that we did)... Otherwise someone could put a fake
	// account file on the server if the code wasn't designed to verify the signature on the
	// account.
	SignContract(theServer);		
	SaveContract();		
	
	// Save the Account to storage (based on its ID.)
	SaveAccount();

	// Don't know why I had this here. Putting SaveAccount() instead.
//	OTString strFilename(m_strFilename);
//	SaveContract(strFilename.Get()); // Saves the account to a specific filename
	
	// No need to create the inbox and outbox ledgers...they will be created automatically
	// if they do not exist when they are needed.
	
	return true;
}
Example #5
0
bool OTPAYLOAD_GetMessage(OTPayload & thePayload, OTMessage & theMessage)
{
	return thePayload.GetMessage(theMessage);
}
// Process my reply back out to the client.  @something.
// For TCP / SSL mode.
void OTClientConnection::ProcessReply(OTMessage &theReply)
{
    OT_ASSERT(NULL != m_pPublicKey);
    
    int  err = 0;
	uint32_t nwritten = 0;
	bool bSendCommand = false;
	bool bSendPayload = false;
	
	u_header  theCMD;
	OTPayload thePayload;

	memset((void *)theCMD.buf, 0, OT_CMD_HEADER_SIZE); // todo cast

	// For now let's send ALL replies in Envelopes (encrypted to public key of client)
	// IF we have a public key, that is. Otherwise we send as a normal message.
	//
	// All messages already require either a public key, or a nymID used to look up a
	// public key. So given that I have that information when I reply, I might as well
	// ENCRYPT my reply to that same public key. More secure that way.
	//
	// The wallet (and server) are both ready to open and process these encrypted envelopes.
	
		
	// If GetKey() returns something, that means the key was set in there, it's
	// not just a null pointer. This means we can use it!  So let's encrypt to it.
	if (m_pPublicKey->IsPublic())
	{
		OTString strEnvelopeContents(theReply);
		// Save the ready-to-go message into a string.
		
		OTEnvelope theEnvelope;
		// Seal the string up into an encrypted Envelope
		theEnvelope.Seal(*m_pPublicKey, strEnvelopeContents);
		
		// From here on out, theMessage is disposable. OTPayload takes over. 
		// OTMessage doesn't care about checksums and headers.
		thePayload.SetEnvelope(theEnvelope);
		
		// Now that the payload is ready, we'll set up the header.
		SetupHeader(&theCMD, CMD_TYPE_1, TYPE_1_CMD_2, thePayload);
	}
	else 
    {
		thePayload.SetMessage(theReply);
		
		// Now that the payload is ready, we'll set up the header.
		SetupHeader(&theCMD, CMD_TYPE_1, TYPE_1_CMD_1, thePayload);
	}
	
	bSendCommand = true;
	bSendPayload = true;				
	
	
	OTLog::vOutput(2, "\n****************************************************************\n"
			"===> Finished setting up header for response.\nFirst 9 bytes are: %d %d %d %d %d %d %d %d %d...\n",
			theCMD.buf[0], theCMD.buf[1], theCMD.buf[2], theCMD.buf[3], theCMD.buf[4], 
			theCMD.buf[5], theCMD.buf[6], theCMD.buf[7], theCMD.buf[8]);
	
	
	// ------------------------------------------------------------------------------			
	/*
	 // Write to Client
	 strcpy(buffer, "Hello Client!");
	 SFSocketWrite(clientSocket, buffer, strlen(buffer));
	 
	 */
	
	if (bSendCommand)
	{
		
		const unsigned int nHeaderSize = OT_CMD_HEADER_SIZE;
		
		for (nwritten = 0;  nwritten < nHeaderSize;  nwritten += err)
		{
//			err = SFSocketWrite(m_pSocket, theCMD.buf + nwritten, nHeaderSize - nwritten);

#ifdef _WIN32
			if (0 == err || SOCKET_ERROR == err) // 0 means disconnect. error means error. >0 means bytes read.
#else
			if (err <= 0)
#endif
				break;
		}
	}
	// At this point, we have sent the header across the pipe.
	
	if (bSendPayload)
	{
		
		uint32_t nPayloadSize = thePayload.GetSize();
		
		for (nwritten = 0;  nwritten < nPayloadSize;  nwritten += err)
		{
//			err = SFSocketWrite(m_pSocket, (unsigned char *)thePayload.GetPayloadPointer() + nwritten, nPayloadSize - nwritten);

#ifdef _WIN32
			if (0 == err || SOCKET_ERROR == err) // 0 means disconnect. error means error. >0 means bytes read.
#else
			if (err <= 0)
#endif
				break;
		}		
	}
	// At this point, we have sent the payload across the pipe.		
	
	OTLog::Output(2, "...Done.\n");
}
// A certain number of bytes are expected in the payload, according to the header.
// This function tries to read that many bytes, and inserts them into an OTPayload object.
// From there, a simple method call extracts the message, we return true, and the message
// gets added to our internal list for processing.
bool OTClientConnection::ProcessType1Cmd(u_header & theCMD, OTMessage & theMessage)
{
	// At this point, the checksum has already validated. 
	// Might as well get the PAYLOAD next.
//	int  err;
	uint32_t nread, lSize = theCMD.fields.size;
	
	// Make sure our byte-order is correct here.
//	theCMD.fields.size = ntohl(theCMD.fields.size); // I was doing this twice!! This is already done when the header is first read.

	// setup the buffer we are reading into
	OTPayload thePayload;
	nread = thePayload.ReadBytesFrom(m_Buffer, lSize);
	
	/*
	// actually read the payload from the socket into the buffer.
	for (nread = 0;  nread < theCMD.fields.size;  nread += err)
	{
		err = SFSocketRead(m_pSocket, 
						   (unsigned char *)thePayload.GetPayloadPointer() + nread,
						   theCMD.fields.size - nread);
		
		// if we don't read anything more, stop reading and move on
		if (err <= 0)
			break;
	}
	*/
	// TODO fix the buffering so that if a complete command has not yet been received, it saves the other
	// bytes instead of discarding them.  For now I'll just sleep for a second to make sure the entire command
	// was received.
//	sleep(1);
	
	// ------------------------------------------------------------
	
	// Try to interpret the command number.
	// Right now we support signed messages and encrypted envelopes containing
	// signed messages.
	switch (theCMD.fields.command_id) {
		case TYPE_1_CMD_1:
			OTLog::Output(2, "Received Type 1 CMD 1:\nThere is a signed OTMessage in the payload.\n");
			break;
		case TYPE_1_CMD_2:
			OTLog::Output(2, "Received Type 1 CMD 2:\n"
					"There is an encrypted OTEnvelope (containing signed OTMessage) in the payload.\n");
			break;
		default:
			OTLog::vError("Received unexpected command number %d in OTClientConnection::ProcessType1Cmd\n", 
					theCMD.fields.command_id);
			break;
	}
	
	// ------------------------------------------------------------
	// Hm, that's weird. It was a 0 size payload message. DoS?
	if (theCMD.fields.size == 0)
	{
		OTLog::Output(2, "(The payload was a 0 size.)\n");
		return true;
	}
	// Uh-oh, somehow the number of bytes read was less than what we expected...
	else if (nread < theCMD.fields.size)
	{
		// TODO: Verify that the amount read matched the amount expected
		// if not, we have a problem that needs to be handled.
		
		// Long term solution is to buffer the data as a comes in and just
		// add it to the buffer.
		
		// Then if we don't have the complete message yet, we just come around next
		// time some data is read, and we add that to the buffer, THEN we check to see
		// if there are enough bytes yet read to match the amount expected according to
		// the header.
		//
		// Until I can do that, I'm not yet TRULY asynchronous. TODO: lookup a good buffer class.

		OTLog::Error("Number of bytes read did NOT match size in header.\n");
		return false;
	}
	else
		OTLog::vOutput(2, "Loaded a payload, size: %d\n", theCMD.fields.size);
	
	// ------------------------------------------------------------
	
	// Okay so now we've received the expected size from the socket. Let's transfer it
	// into an object type that we can manipulate here in code. (Message or Envelope.)
	
	// a signed OTMessage
	if (TYPE_1_CMD_1 == theCMD.fields.command_id) 
	{
#ifdef _WIN32
		if (OTPAYLOAD_GetMessage(thePayload, theMessage))
#else
		if (thePayload.GetMessage(theMessage))
#endif
		{
			OTLog::Output(2, "Successfully retrieved payload message...\n");
			
			if (theMessage.ParseRawFile())
			{
				OTLog::Output(2, "Successfully parsed payload message.\n");
				
				return true;
			}
			else {
				OTLog::Error("Error parsing message.\n");
				return false;
			}
			
		}
		else {
			OTLog::Error("Error retrieving message from payload.\n");
			return false;
		}
		
	}
	
	// A base64-encoded envelope, encrypted, and containing a signed message.
	else if (TYPE_1_CMD_2 == theCMD.fields.command_id) 
	{
		OTEnvelope theEnvelope;
		if (thePayload.GetEnvelope(theEnvelope))
		{
			OTLog::Output(2, "Successfully retrieved envelope from payload...\n");
			
			OTString strEnvelopeContents;
			
			// Decrypt the Envelope.    
			if (m_pServer && theEnvelope.Open(m_pServer->GetServerNym(), strEnvelopeContents))
			{
				// All decrypted, now let's load the results into an OTMessage.
				// No need to call theMessage.ParseRawFile() after, since
				// LoadContractFromString handles it.
				//
				if (strEnvelopeContents.Exists() && theMessage.LoadContractFromString(strEnvelopeContents))
				{
					OTLog::Output(2, "Success loading message out of the envelope contents and parsing it.\n");
					return true;
				}
				else 
				{
					OTLog::Error("Error loading message from envelope contents.\n");
					return false;		
				}
			}
			else 
			{
				OTLog::Error("Unable to open envelope.\n");
				return false;
			}			
		}
		else 
		{
			OTLog::Error("Error retrieving message from payload.\n");
			return false;
		}
	}
	
	return true;
}
bool OTEnvelope::Decrypt(OTString & theOutput, const OTSymmetricKey & theKey, const OTPassword & thePassword)
{
    const char * szFunc = "OTEnvelope::Decrypt";
    // ------------------------------------------------
    OT_ASSERT((thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0)));
    OT_ASSERT(theKey.IsGenerated());
    // -----------------------------------------------
    OTPassword  theRawSymmetricKey;
    
    if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey))
    {
		OTLog::vError("%s: Failed trying to retrieve raw symmetric key using password. (Wrong password?)\n", 
                      szFunc);
		return false;	
    }
    // -----------------------------------------------
    //
    uint32_t    nRead         = 0;
    uint32_t    nRunningTotal = 0;
    
    m_dataContents.reset(); // Reset the fread position on this object to 0.

    // ****************************************************************************
    //
    // Read the ENVELOPE TYPE (as network order version -- and convert to host version.)
    //
    // 0 == Error
    // 1 == Asymmetric Key  (this function -- Seal / Open)
    // 2 == Symmetric Key   (other functions -- Encrypt / Decrypt use this.)
    // Anything else: error.
    //
    uint16_t  env_type_n = 0;
    
    if (0 == (nRead = m_dataContents.OTfread(reinterpret_cast<uint8_t*>(&env_type_n),
                                             static_cast<uint32_t>(sizeof(env_type_n)))))
	{
		OTLog::vError("%s: Error reading Envelope Type. Expected asymmetric(1) or symmetric (2).\n", szFunc);
		return false;
	}
    nRunningTotal += nRead;
    OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(env_type_n)));
    // ----------------------------------------------------------------------------
	// convert that envelope type from network to HOST endian.
    //
    const uint16_t env_type = static_cast<uint16_t>(ntohs(static_cast<uint16_t>(env_type_n)));
//  nRunningTotal += env_type;    // NOPE! Just because envelope type is 1 or 2, doesn't mean we add 1 or 2 extra bytes to the length here. Nope!
    
    if (2 != env_type)
	{
        const uint32_t l_env_type = static_cast<uint32_t>(env_type);
		OTLog::vError("%s: Error: Expected Envelope for Symmetric key (type 2) but instead found type: %ld.\n", 
                      szFunc, l_env_type);
		return false;
	}
    // ****************************************************************************
    //
    // Read network-order IV size (and convert to host version) 
    //    
    const uint32_t max_iv_length   = OTCryptoConfig::SymmetricIvSize(); // I believe this is a max length, so it may not match the actual length of the IV.
    
    // Read the IV SIZE (network order version -- convert to host version.)
    //
    uint32_t	iv_size_n   = 0;
    
    if (0 == (nRead = m_dataContents.OTfread(reinterpret_cast<uint8_t*>(&iv_size_n),
                                             static_cast<uint32_t>(sizeof(iv_size_n)))))
	{
		OTLog::vError("%s: Error reading IV Size.\n", szFunc);
		return false;
	}
    nRunningTotal += nRead;
    OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(iv_size_n)));
    // ----------------------------------------------------------------------------
	// convert that iv size from network to HOST endian.
    //
    const uint32_t iv_size_host_order = ntohl(iv_size_n);
    
    if (iv_size_host_order > max_iv_length)
    {
        OTLog::vError("%s: Error: iv_size (%ld) is larger than max_iv_length (%ld).\n",
                      szFunc, static_cast<long>(iv_size_host_order), static_cast<long>(max_iv_length));
        return false;
    }
//  nRunningTotal += iv_size_host_order; // Nope!
    // ****************************************************************************
    //
    // Then read the IV (initialization vector) itself.
    //
    OTPayload theIV;
    theIV.SetPayloadSize(iv_size_host_order);
    
    if (0 == (nRead = m_dataContents.OTfread(static_cast<uint8_t*>(const_cast<void *>(theIV.GetPayloadPointer())), 
                                             static_cast<uint32_t>(iv_size_host_order))))
    {
        OTLog::vError("%s: Error reading initialization vector.\n", szFunc);
        return false;
    }
    nRunningTotal += nRead;
    OT_ASSERT(nRead == static_cast<uint32_t>(iv_size_host_order));
    
    OT_ASSERT(nRead <= max_iv_length);
    
	// ----------------------------------------------------------------------------    
    // We create an OTPayload object to store the ciphertext itself, which begins AFTER the end of the IV.
    // So we see pointer + nRunningTotal as the starting point for the ciphertext.
    // the size of the ciphertext, meanwhile, is the size of the entire thing, MINUS nRunningTotal.
    //
	OTPayload theCipherText(static_cast<const void*>( 
                                               static_cast<const uint8_t *>(m_dataContents.GetPointer()) + nRunningTotal
                                               ), 
					  m_dataContents.GetSize() - nRunningTotal);
    // ----------------------------------------------------------------------------
    // Now we've got all the pieces together, let's try to decrypt it...
    //
    OTPayload thePlaintext; // for output.
    
    const bool bDecrypted = OTCrypto::It()->Decrypt(theRawSymmetricKey, // The symmetric key, in clear form.
                                                    // -------------------------------
                                                    static_cast<const char *>(theCipherText.GetPayloadPointer()),  // This is the Ciphertext.
                                                    theCipherText.GetSize(),
                                                    // -------------------------------
                                                    theIV,
                                                    // -------------------------------
                                                    thePlaintext); // OUTPUT. (Recovered plaintext.) You can pass OTPassword& OR OTPayload& here (either will work.)
    // -----------------------------------------------
    // theOutput is where we'll put the decrypted data.
    //
    theOutput.Release();
    
    if (bDecrypted)
    {
        // -----------------------------------------------------
        // Make sure it's null-terminated...
        //
        uint32_t nIndex = thePlaintext.GetSize()-1;
        (static_cast<uint8_t*>(const_cast<void *>(thePlaintext.GetPointer())))[nIndex] = '\0';
        
        // -----------------------------------------------------
        // Set it into theOutput (to return the plaintext to the caller)
        //
        theOutput.Set(static_cast<const char *>(thePlaintext.GetPointer()));
        // ----------------
    }
    
    return bDecrypted;
}
bool OTEnvelope::Encrypt(const OTString & theInput, OTSymmetricKey & theKey, const OTPassword & thePassword)
{
    OT_ASSERT((thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0)));
    OT_ASSERT(theInput.Exists());
    // -----------------------------------------------
    // Generate a random initialization vector.
    //
    OTPayload theIV;

    if (false == theIV.Randomize(OTCryptoConfig::SymmetricIvSize()))
    {
		OTLog::vError("%s: Failed trying to randomly generate IV.\n", __FUNCTION__);
		return false;	
    }
    // -----------------------------------------------
    // If the symmetric key hasn't already been generated, we'll just do that now...
    // (The passphrase is used to derive another key that is used to encrypt the
    // actual symmetric key, and to access it later.)
    //
    if ((false == theKey.IsGenerated()) && (false == theKey.GenerateKey(thePassword)))
    {
		OTLog::vError("%s: Failed trying to generate symmetric key using password.\n", __FUNCTION__);
		return false;	
    }
    // -----------------------------------------------

	if (!theKey.HasHashCheck())
	{
		if(!theKey.GenerateHashCheck(thePassword))
		{
		OTLog::vError("%s: Failed trying to generate hash check using password.\n", __FUNCTION__);
		return false;
		}
	}

	OT_ASSERT(theKey.HasHashCheck());

    OTPassword  theRawSymmetricKey;
    
    if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey))
    {
		OTLog::vError("%s: Failed trying to retrieve raw symmetric key using password.\n", __FUNCTION__);
		return false;	
    }
    // -----------------------------------------------
    //
    OTPayload theCipherText;
    
    const bool bEncrypted = OTCrypto::It()->Encrypt(theRawSymmetricKey, // The symmetric key, in clear form.
                                                    // -------------------------------
                                                    theInput.Get(),     // This is the Plaintext.
                                                    theInput.GetLength() + 1, // for null terminator
                                                    // -------------------------------
                                                    theIV,              // Initialization vector.
                                                    // -------------------------------
                                                    theCipherText);     // OUTPUT. (Ciphertext.)
    // -----------------------------------------------
    //
    // Success?
    //
    if (!bEncrypted)
    {
        OTLog::vError("%s: (static) call failed to encrypt. Wrong key? (Returning false.)\n", __FUNCTION__);
		return false;
    }
    // -----------------------------------------------
    //
	// This is where the envelope final contents will be placed,
    // including the envelope type, the size of the IV, the IV
    // itself, and the ciphertext.
    //
	m_dataContents.Release();

    // -----------------------------------------------
    // Write the ENVELOPE TYPE (network order version.)
    //
    // 0 == Error
    // 1 == Asymmetric Key  (other functions -- Seal / Open.)
    // 2 == Symmetric Key   (this function -- Encrypt / Decrypt.)
    // Anything else: error.
    
    uint16_t   env_type_n = static_cast<uint16_t>(htons(static_cast<uint16_t>(2))); // Calculate "network-order" version of envelope type 2.
    
    m_dataContents.Concatenate(reinterpret_cast<void *>(&env_type_n),   
                               // (uint32_t here is the 2nd parameter to Concatenate, and has nothing to do with env_type_n being uint16_t)
                               static_cast<uint32_t>(sizeof(env_type_n)));  
    // ------------------------------------------------------------
    //
    // Write IV size (in network-order)
    //
    uint32_t  ivlen   = OTCryptoConfig::SymmetricIvSize(); // Length of IV for this cipher...
    OT_ASSERT(ivlen >= theIV.GetSize());
    uint32_t  ivlen_n = htonl(theIV.GetSize()); // Calculate "network-order" version of iv length.
    
	m_dataContents.Concatenate(reinterpret_cast<void *>(&ivlen_n),   
                               static_cast<uint32_t>(sizeof(ivlen_n)));
	
    // Write the IV itself.
    //
	m_dataContents.Concatenate(theIV.GetPayloadPointer(), 
                               static_cast<uint32_t>(theIV.GetSize()));
    // ------------------------------------------------------------
    
    // Write the Ciphertext.
    //
    m_dataContents.Concatenate(theCipherText.GetPayloadPointer(), 
                               static_cast<uint32_t>(theCipherText.GetSize()));
    
    // We don't write the size of the ciphertext before the ciphertext itself,
    // since the decryption is able to deduce the size based on the total envelope
    // size minus the other pieces. We might still want to add that size here, however.
    // (for security / safety reasons.)
    
    // -----------------------------------------------
    return true;
}
// The above method uses this one internally...
bool OTAccount::GenerateNewAccount(const OTPseudonym & theServer, const OTMessage & theMessage,
								   const OTAccount::AccountType eAcctType/*=OTAccount::simple*/,
								   int64_t lStashTransNum/*=0*/)
{
    const char *szFunc = "OTAccount::GenerateNewAccount";
    // -----------------------------------------------
	// First we generate a secure random number into a binary object...
    //
    OTPayload thePayload;

    if (false == thePayload.Randomize(100)) // todo hardcoding. Plus: is 100 bytes of random a little much here?
    {
		OTLog::vError("%s: Failed trying to acquire random numbers.\n", szFunc);
		return false;
    }
	// --------------------------------------------------
    //
	// Next we calculate that binary object into a message digest (an OTIdentifier).
    //
	OTIdentifier newID;
	if (!newID.CalculateDigest(thePayload))
	{
		OTLog::vError("%s: Error generating new account ID.\n", szFunc);
		return false;
	}
    // --------------------------------------------------
    //
	// Next we get that digest (which is a binary hash number)
	// and extract a human-readable standard string format of that hash,
	// into an OTString.
    //
	OTString strID(newID);

	SetRealAccountID(newID);		// Set the account number based on what we just generated.
	SetPurportedAccountID(newID);	// Might as well set them both. (Safe here to do so, for once.)

	m_strName.Set(strID); // So it's not blank. The user can always change it.

	// Next we create the full path filename for the account using the ID.
    //
	m_strFoldername = OTFolders::Account().Get();
	m_strFilename = strID.Get();

	// Then we try to load it, in order to make sure that it doesn't already exist.
	// --------------------------------------------------------------------

	if (OTDB::Exists(m_strFoldername.Get(), m_strFilename.Get()))
	{
		OTLog::vError("%s: Account already exists: %s\n", szFunc,
					  m_strFilename.Get());
		return false;
	}

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

	// Set up the various important starting values of the account.
	m_AcctType = eAcctType; // account type defaults to OTAccount::simple. But there are also issuer accts...

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

	if (IsInternalServerAcct())  // basket, basketsub, mint, voucher, and stash accounts are all "owned" by the server.
	{
		theServer.GetIdentifier(m_AcctUserID);
	}
	else
	{
		m_AcctUserID.SetString(theMessage.m_strNymID);
	}

	// --------------------------------------------------------------------
	m_AcctAssetTypeID.SetString(theMessage.m_strAssetID);

	OTLog::vOutput(3, "%s: Creating new account, type:\n%s\n", szFunc,
				   theMessage.m_strAssetID.Get());

	OTIdentifier SERVER_ID(theMessage.m_strServerID);
	SetRealServerID(SERVER_ID);			// todo this assumes the serverID on the message is correct. It's vetted, but still...
	SetPurportedServerID(SERVER_ID);

	const time64_t tDate = OTTimeGetCurrentTime(); // Today, now.
	m_BalanceDate.Format("%d", tDate);

	m_BalanceAmount.Set("0");

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

	if (IsStashAcct())
	{
		OT_ASSERT_MSG(lStashTransNum > 0,
					  "You created a stash account, but with a zero-or-negative transaction number for its cron item.");
		m_lStashTransNum	= lStashTransNum;
	}

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

	// Sign the Account (so we know that we did)... Otherwise someone could put a fake
	// account file on the server if the code wasn't designed to verify the signature on the
	// account.
	SignContract(theServer);
	SaveContract();

	// Save the Account to storage (based on its ID.)
	SaveAccount();

	// Don't know why I had this here. Putting SaveAccount() instead.
//	OTString strFilename(m_strFilename);
//	SaveContract(strFilename.Get()); // Saves the account to a specific filename

	// No need to create the inbox and outbox ledgers...they will be created automatically
	// if they do not exist when they are needed.

	return true;
}
//static
bool OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::ArmorPrivateKey(EVP_PKEY & theKey, OTASCIIArmor & ascKey, Timer & theTimer, OTPasswordData * pPWData/*=NULL*/, OTPassword * pImportPassword/*=NULL*/)
{
	bool bReturnVal = false;
    
    ascKey.Release();
    // ----------------------------------------
	// Create a new memory buffer on the OpenSSL side
	OpenSSL_BIO bmem = BIO_new(BIO_s_mem());    
	OT_ASSERT(NULL != bmem);
    
    int64_t lSize = 0;
	// ----------------------------------------
	// write a private key to that buffer, from theKey
    //
    OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::ArmorPrivateKey is calling PEM_write_bio_PrivateKey...");

    if (NULL == pPWData)
        pPWData = &thePWData;
    
    int32_t nWriteBio = 0;

    if (NULL == pImportPassword)
        nWriteBio = PEM_write_bio_PrivateKey(bmem, &theKey, EVP_des_ede3_cbc(), // todo should this algorithm be hardcoded?
                                             NULL, 0, OTAsymmetricKey::GetPasswordCallback(), pPWData);
    else
        nWriteBio = PEM_write_bio_PrivateKey(bmem, &theKey, EVP_des_ede3_cbc(), // todo should this algorithm be hardcoded?
                                             NULL, 0, 0, const_cast<void*>(reinterpret_cast<const void*>(pImportPassword->getPassword())));
	
	if (0 == nWriteBio)
	{
		OTLog::vError("%s: Failed writing EVP_PKEY to memory buffer.\n", __FUNCTION__);
	}
	else 
	{
        // TODO (remove theTimer entirely. OTCachedKey replaces already.)
        // I set this timer because the above required a password. But now that master key is working,
        // the above would flow through even WITHOUT the user typing his passphrase (since master key still
        // not timed out.) Resulting in THIS timer being reset!  Todo: I already shortened this timer to 30
        // seconds, but need to phase it down to 0 and then remove it entirely! Master key takes over now!
        //

        theTimer.start(); // Note: this isn't the ultimate timer solution. See notes in ReleaseKeyLowLevel.
        // --------------------
		OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", __FUNCTION__);
		
		OTPayload theData;
		char * pChar = NULL;
		
		// After the below call, pChar will point to the memory buffer where the private key supposedly is,
		// and lSize will contain the size of that memory.
        //
		lSize = BIO_get_mem_data(bmem, &pChar);
		uint32_t  nSize = static_cast<uint32_t>(lSize);
		
		if (nSize > 0)
		{
			// Set the buffer size in our own memory.
			theData.SetPayloadSize(nSize);
            
//            void * pv = 
                OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination
                                    theData.GetSize(),    // size of destination buffer.
                                    pChar,                // source
                                    nSize);               // length of source.
            // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done.
            
            // ------------------------------------------------
			// This base64 encodes the private key data, which
            // is already encrypted to its passphase as well.
            //
			ascKey.SetData(theData);
			
            OTLog::vOutput(5, "%s: Success copying private key into memory.\n", __FUNCTION__);
			bReturnVal = true;
		}
		else 
		{
			OTLog::vError("%s: Failed copying private key into memory.\n", __FUNCTION__);
		}
	}
	
	return bReturnVal;	
}
EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::InstantiatePrivateKey(OTPasswordData * pPWData/*=NULL*/)
{
    OT_ASSERT(m_pKey     == NULL);
    OT_ASSERT(backlink->m_p_ascKey != NULL);
    OT_ASSERT(backlink->IsPrivate());
    // ------------------------------
	EVP_PKEY * pReturnKey = NULL;
	OTPayload theData;  // after base64-decoding the ascii-armored string, the (encrypted) binary will be stored here.
	// --------------------------------------	
	// This line base64 decodes the ascii-armored string into binary object theData...
    //
    backlink->m_p_ascKey->GetData(theData); // theData now contains binary data, the encrypted private key itself, no longer in text-armoring.
    //
    // Note, for future optimization: the ASCII-ARMORING could be used for serialization, but the BIO (still encrypted)
    // could be used in RAM for this object. Otherwise you just have to do the extra step of ascii-decoding it first to get
    // the BIO, before being able to instantiate the key itself from that. That final step can't change, but I can remove
    // the step before it, in most cases, by just storing the BIO itself, instead of the ascii-armored string. Or perhaps
    // make them both available...hm.
	// --------------------------------------
    // Copy the encrypted binary private key data into an OpenSSL memory BIO...
    //
    if (theData.GetSize() > 0)
    {
        OpenSSL_BIO keyBio = BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), 
                                       theData.GetSize()); // theData will zeroMemory upon destruction.
        OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::InstantiatePrivateKey: Assert: NULL != keyBio \n");
        // --------------------------------------
        // Here's thePWData we use if we didn't have anything else:
        //
        OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::InstantiatePrivateKey is calling PEM_read_bio_PrivateKey...");

        if (NULL == pPWData)
            pPWData = &thePWData;
        
        pReturnKey = PEM_read_bio_PrivateKey( keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), pPWData );
        
        // Free the BIO and related buffers, filters, etc.
        backlink->ReleaseKeyLowLevel();
        // --------------------------------------
        if (NULL != pReturnKey)
        {
            m_pKey = pReturnKey;
            // TODO (remove theTimer entirely. OTCachedKey replaces already.)
            // I set this timer because the above required a password. But now that master key is working,
            // the above would flow through even WITHOUT the user typing his passphrase (since master key still
            // not timed out.) Resulting in THIS timer being reset!  Todo: I already shortened this timer to 30
            // seconds, but need to phase it down to 0 and then remove it entirely! Master key takes over now!
            //

            backlink->m_timer.start();  // Note: this isn't the ultimate timer solution. See notes in ReleaseKeyLowLevel.
            OTLog::vOutput(4, "%s: Success reading private key from ASCII-armored data.\n\n",
                           __FUNCTION__);
//          OTLog::vOutput(4, "%s: Success reading private key from ASCII-armored data:\n\n%s\n\n",
//                         __FUNCTION__, m_p_ascKey->Get());
            return m_pKey;
        }
    }
    OTLog::vError("%s: Failed reading private key from ASCII-armored data.\n\n",
                  __FUNCTION__);
//  OTLog::vError("%s: Failed reading private key from ASCII-armored data:\n\n%s\n\n",
//                __FUNCTION__, m_p_ascKey->Get());
    return NULL;
}
// Take a public key, theKey (input), and create an armored version of
// it into ascKey (output.)
//
// OpenSSL loaded key ===> ASCII-Armored export of same key.
//
//static
//
bool OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::ArmorPublicKey(EVP_PKEY & theKey, OTASCIIArmor & ascKey)
{
	bool bReturnVal = false;
    
    const char * szFunc = "OTAsymmetricKey_OpenSSL::ArmorPublicKey";
    
    ascKey.Release();
    // ----------------------------------------
	// Create a new memory buffer on the OpenSSL side
	OpenSSL_BIO bmem = BIO_new(BIO_s_mem());    
	OT_ASSERT_MSG(NULL != bmem, "OTAsymmetricKey_OpenSSL::ArmorPublicKey: ASSERT: NULL != bmem");
    
    int64_t lSize = 0;
	// ----------------------------------------
	// write a public key to that buffer, from theKey (parameter.)
    //
	int32_t nWriteBio = PEM_write_bio_PUBKEY(bmem, &theKey);
	
	if (0 == nWriteBio)
	{
		OTLog::vError("%s: Error: Failed writing EVP_PKEY to memory buffer.\n", szFunc);
	}
	else 
	{
		OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", szFunc);
		
		OTPayload theData;
		char * pChar = NULL;
		
		// After the below call, pChar will point to the memory buffer where the public key
        // supposedly is, and lSize will contain the size of that memory.
        //
		lSize = BIO_get_mem_data(bmem, &pChar);
		uint32_t  nSize = static_cast<uint32_t>(lSize); // todo security, etc. Fix this assumed type conversion.
		
		if (nSize > 0)
		{
			// Set the buffer size in our own memory.
			theData.SetPayloadSize(nSize);
            
//            void * pv = 
                OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination
                                    theData.GetSize(),    // size of destination buffer.
                                    pChar,                // source
                                    nSize);               // length of source.
                                    // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done.
            
            // ------------------------------------------------
			// This base64 encodes the public key data
            //
			ascKey.SetData(theData);
			
            OTLog::vOutput(5, "%s: Success copying public key into memory.\n", szFunc);
			bReturnVal = true;
		}
		else 
		{
			OTLog::vError("%s: Failed copying public key into memory.\n", szFunc);
		}
	}
    
	return bReturnVal;	
}
// NOTE: OpenSSL will store the EVP_PKEY inside the X509, and when I get it, 
// I'm not supposed to destroy the x509 until I destroy the EVP_PKEY FIRST!
// (AND it reference-counts.)
// Since I want ability to destroy the two, independent of each other, I made
// static functions here for copying public and private keys, so I am ALWAYS
// working with MY OWN copy of any given key, and not OpenSSL's reference-counted
// one.
//
// Furthermore, BIO_mem_buf doesn't allocate its own memory, but uses the memory
// you pass to it. You CANNOT free that memory until you destroy the BIO.
//
// That's why you see me copying one bio into a payload, before copying it into
// the next bio. Todo security: copy it into an OTPassword here, instead of an
// OTPayload, which is safer, and more appropriate for a private key. Make sure
// OTPassword can accommodate a bit larger size than what it does now.
//
//static      // CALLER must EVP_pkey_free!
EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::CopyPrivateKey(EVP_PKEY & theKey, OTPasswordData * pPWData/*=NULL*/, OTPassword * pImportPassword/*=NULL*/)
{
    const EVP_CIPHER * pCipher = EVP_des_ede3_cbc(); // todo should this algorithm be hardcoded?
    // ----------------------------------------
	// Create a new memory buffer on the OpenSSL side
	OpenSSL_BIO bmem = BIO_new(BIO_s_mem());    
	OT_ASSERT(NULL != bmem);
    
    EVP_PKEY * pReturnKey = NULL;
	// ----------------------------------------
	// write a private key to that buffer, from theKey
    //
    OTPasswordData thePWDataWrite("OTAsymmetricKey_OpenSSL::CopyPrivateKey is calling PEM_write_bio_PrivateKey...");
    
    // todo optimization: might just remove the password callback here, and just write the private key in the clear,
    // and then load it up again, saving the encrypt/decrypt step that otherwise occurs, and then as long as we OpenSSL_cleanse
    // the BIO, then it SHOULD stil be safe, right?
    //
    int32_t nWriteBio = false;
    
    if (NULL == pImportPassword)
        nWriteBio = PEM_write_bio_PrivateKey(bmem, &theKey, pCipher,
                                             NULL, 0, OTAsymmetricKey::GetPasswordCallback(), NULL == pPWData ? &thePWDataWrite : pPWData);
    else
        nWriteBio = PEM_write_bio_PrivateKey(bmem, &theKey, pCipher,
                                             NULL, 0, 0, const_cast<void*>(reinterpret_cast<const void*>(pImportPassword->getPassword())));
	// ------------------------------------------------------------------------
	if (0 == nWriteBio)
	{
		OTLog::vError("%s: Failed writing EVP_PKEY to memory buffer.\n", __FUNCTION__);
	}
	else 
	{
		OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", __FUNCTION__);
		
		char * pChar = NULL;
		
		// After the below call, pChar will point to the memory buffer where the private key supposedly is,
		// and lSize will contain the size of that memory.
        //
        const int64_t      lSize = BIO_get_mem_data(bmem, &pChar);
        const uint32_t  nSize = static_cast<uint32_t>(lSize);
        
        if (nSize > 0)
        {
            OTPayload theData;
            
            // Set the buffer size in our own memory.
            theData.SetPayloadSize(nSize);
            
            void * pv = 
               OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination
                                       theData.GetSize(),    // size of destination buffer.
                                       pChar,                // source
                                       nSize);               // length of source.
            // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done.
            
            if (NULL != pv)
            {
                // -----------------------------------------------
                // Next, copy theData's contents into a new BIO_mem_buf,
                // so OpenSSL can load the key out of it.
                //
                OpenSSL_BIO keyBio	= BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), 
                                              theData.GetSize());
                OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::CopyPrivateKey: Assert: NULL != keyBio \n");
                // -------------------------------------------
                // Next we load up the key from the BIO string into an instantiated key object.
                //
                OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::CopyPrivateKey is calling PEM_read_bio_PUBKEY...");
                
                if (NULL == pImportPassword)
                    pReturnKey = PEM_read_bio_PrivateKey( keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), NULL == pPWData ? &thePWData : pPWData);
                else
                    pReturnKey = PEM_read_bio_PrivateKey( keyBio, NULL, 0, const_cast<void*>(reinterpret_cast<const void*>(pImportPassword->getPassword())));
                // -------------------------------------------
            }
            else 
                OTLog::vError("%s: Error: Failed copying memory from BIO into OTPayload.\n");
            // -------------------------------------------            
        }
		else 
		{
			OTLog::vError("%s: Failed copying private key into memory.\n", __FUNCTION__);
		}
	}

	return pReturnKey;	
}
//static      // CALLER must EVP_pkey_free!
EVP_PKEY * OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::CopyPublicKey(EVP_PKEY & theKey, OTPasswordData * pPWData/*=NULL*/, OTPassword * pImportPassword/*=NULL*/)
{
    // ----------------------------------------
	// Create a new memory buffer on the OpenSSL side
	OpenSSL_BIO bmem = BIO_new(BIO_s_mem());
	OT_ASSERT_MSG(NULL != bmem, "OTAsymmetricKey_OpenSSL::CopyPublicKey: ASSERT: NULL != bmem");
    
    EVP_PKEY * pReturnKey = NULL;
	// ----------------------------------------
	// write a public key to that buffer, from theKey (parameter.)
    //
	int32_t nWriteBio = PEM_write_bio_PUBKEY(bmem, &theKey);
	
	if (0 == nWriteBio)
	{
		OTLog::vError("%s: Error: Failed writing EVP_PKEY to memory buffer.\n", __FUNCTION__);
	}
	else 
	{
		OTLog::vOutput(5, "%s: Success writing EVP_PKEY to memory buffer.\n", __FUNCTION__);
		
		char * pChar = NULL;
		
		// After the below call, pChar will point to the memory buffer where the public key
        // supposedly is, and lSize will contain the size of that memory.
        //
		const int64_t      lSize = BIO_get_mem_data(bmem, &pChar);
        const uint32_t  nSize = static_cast<uint32_t>(lSize);
        
        if (nSize > 0)
        {
            OTPayload theData;

            // Set the buffer size in our own memory.
            theData.SetPayloadSize(nSize);
            
            void * pv = 
               OTPassword::safe_memcpy((static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer()))), // destination
                                    theData.GetSize(),    // size of destination buffer.
                                    pChar,                // source
                                    nSize);               // length of source.
            // bool bZeroSource=false); // if true, sets the source buffer to zero after copying is done.

            if (NULL != pv)
            {
                // -----------------------------------------------
                // Next, copy theData's contents into a new BIO_mem_buf,
                // so OpenSSL can load the key out of it.
                //
                OpenSSL_BIO keyBio	= BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())), 
                                              theData.GetSize());
                OT_ASSERT_MSG(NULL != keyBio, "OTAsymmetricKey_OpenSSL::CopyPublicKey: Assert: NULL != keyBio \n");
                // -------------------------------------------
                // Next we load up the key from the BIO string into an instantiated key object.
                //
                OTPasswordData thePWData(NULL == pImportPassword ?
                                         "Enter your wallet master passphrase. (OTAsymmetricKey_OpenSSL::CopyPublicKey is calling PEM_read_bio_PUBKEY...)" :
                                         "Enter the passphrase for your exported Nym.");
                
                if (NULL == pImportPassword)
                    pReturnKey = PEM_read_bio_PUBKEY(keyBio, NULL, OTAsymmetricKey::GetPasswordCallback(), NULL == pPWData ? &thePWData : pPWData);
                else
                    pReturnKey = PEM_read_bio_PUBKEY(keyBio, NULL, 0, pImportPassword);
                // -------------------------------------------
                // We don't need the BIO anymore.
                // Free the BIO and related buffers, filters, etc. (auto with scope).
                //
            }
            else 
                OTLog::vError("%s: Error: Failed copying memory from BIO into OTPayload.\n");
            // -------------------------------------------            
        }
        else 
		{
			OTLog::vError("%s: Failed copying private key into memory.\n", __FUNCTION__);
		}
    }

    return pReturnKey;
}