// Lucre step 4: client unblinds token -- now it's ready for use. bool OTToken::ProcessToken(const OTPseudonym & theNym, OTMint & theMint, OTToken & theRequest) { // OTLog::vError("%s <bank public info> <private coin request> <signed coin request> <coin>\n", bool bReturnValue = false; // When the Mint has signed a token and sent it back to the client, // the client must unblind the token and set it as spendable. Thus, // this function is only performed on tokens in the signedToken state. if (OTToken::signedToken != m_State) { OTLog::Error("Signed token expected in OTToken::ProcessToken\n"); return false; } // Lucre SetDumper(stderr); BIO *bioBank = BIO_new(BIO_s_mem()); // input BIO *bioSignature = BIO_new(BIO_s_mem()); // input BIO *bioPrivateRequest = BIO_new(BIO_s_mem()); // input BIO *bioCoin = BIO_new(BIO_s_mem()); // output // Get the bank's public key (decoded into strPublicMint) // and put it into bioBank so we can use it with Lucre. OTASCIIArmor ascPublicMint; theMint.GetPublic(ascPublicMint, GetDenomination()); OTString strPublicMint(ascPublicMint); BIO_puts(bioBank, strPublicMint.Get()); // Get the existing signature into a bio. // OTLog::vError("DEBUGGING, m_Signature: -------------%s--------------\n", m_Signature.Get()); OTString strSignature(m_Signature); BIO_puts(bioSignature, strSignature.Get()); // I need the Private coin request also. (Only the client has this private coin request data.) OTASCIIArmor thePrototoken; // The server sets m_nChosenIndex when it signs the token. bool bFoundToken = theRequest.GetPrivatePrototoken(thePrototoken, m_nChosenIndex); if (bFoundToken) { // OTLog::vError("THE PRIVATE REQUEST ARMORED CONTENTS:\n------------------>%s<-----------------------\n", // thePrototoken.Get()); // Decrypt the prototoken OTString strPrototoken; OTEnvelope theEnvelope(thePrototoken); theEnvelope.Open(theNym, strPrototoken); // todo check return value. // OTLog::vError("THE PRIVATE REQUEST CONTENTS:\n------------------>%s<-----------------------\n", // strPrototoken.Get()); // copy strPrototoken to a BIO BIO_puts(bioPrivateRequest, strPrototoken.Get()); // ------- Okay, the BIOs are all loaded.... let's process... PublicBank bank(bioBank); CoinRequest req(bioPrivateRequest); // TODO make sure I'm not leaking memory with these ReadNumbers // Probably need to be calling some free function for each one. // Apparently reading the request id here and then just discarding it... ReadNumber(bioSignature,"request="); // Versus the signature data, which is read into bnSignature apparently. BIGNUM * bnSignature = ReadNumber(bioSignature,"signature="); DumpNumber("signature=", bnSignature); // Produce the final unblinded token in Coin coin, and write it to bioCoin... Coin coin; // Coin Request, processes into Coin, with Bank and Signature passed in. req.ProcessResponse(&coin, bank, bnSignature); // Notice still apparently "request" info is discarded. coin.WriteBIO(bioCoin); // convert bioCoin to a C-style string... char CoinBuffer[1024]; // todo stop hardcoding these string lengths int coinLen = BIO_read(bioCoin, CoinBuffer, 1000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. if (coinLen) { // ...to OTString... OTString strCoin; strCoin.Set(CoinBuffer, coinLen); // OTLog::vError("Processing token...\n%s\n", strCoin.Get()); // ...to Envelope stored in m_ascSpendable (encrypted and base64-encoded) OTEnvelope theEnvelope; theEnvelope.Seal(theNym, strCoin); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(m_ascSpendable); // Here's the final product. // OTLog::vError("NEW SPENDABLE token...\n--------->%s<----------------\n", m_ascSpendable.Get()); // Now the coin is encrypted from here on out, and otherwise ready-to-spend. m_State = OTToken::spendableToken; bReturnValue = true; // Lastly, we free the signature data, which is no longer needed, and which could be // otherwise used to trace the token. (Which we don't want.) m_Signature.Release(); } } // Todo log error here if the private prototoken is not found. (Very strange if so!!) // else {} // Cleanup openssl resources. BIO_free_all(bioBank); BIO_free_all(bioSignature); BIO_free_all(bioPrivateRequest); BIO_free_all(bioCoin); return bReturnValue; }
// Lucre step 2 (client generates coin request) // nDenomination must be one of the denominations supported by the mint. // sets m_nTokenCount and populates the maps with prototokens (in ASCII-armored format.) bool OTToken::GenerateTokenRequest(const OTPseudonym & theNym, OTMint & theMint, long lDenomination, int nTokenCount/*=OTToken::nMinimumPrototokenCount*/) { // OTLog::vError("%s <bank public info> <coin request private output file> <coin request public output file>\n", argv[0]); if (OTToken::blankToken != m_State) { OTLog::Error("Blank token expected in OTToken::GenerateTokenRequest\n"); return false; } // We are supposed to set these values here. // The server actually sets them again, for security reasons. // But we should still set them since server may choose to reject the request. SetSeriesAndExpiration(theMint.GetSeries(), theMint.GetValidFrom(), theMint.GetValidTo()); SetDumper(stderr); BIO *bioBank = BIO_new(BIO_s_mem()); // Input. We must supply the bank's public lucre info BIO *bioCoin = BIO_new(BIO_s_mem()); // These two are output. We must write these bios, after BIO *bioPublicCoin = BIO_new(BIO_s_mem()); // the operation, back into some form we can use // This version base64-DECODES the ascii-armored string passed in, // and then sets the decoded plaintext string onto the string. //OTString::OTString(const OTASCIIArmor & strValue) OTASCIIArmor ascPublicMint; theMint.GetPublic(ascPublicMint, lDenomination); // OTLog::vError("DEBUG: OTToken public asc: \n%s\n", ascPublicMint.Get()); OTString strPublicMint(ascPublicMint); // OTLog::vError("DEBUG: OTToken public str: \n%s\n", strPublicMint.Get()); // Get the bank's public key (now decoded in strPublicMint) // and put it into bioBank so we can use it with Lucre. BIO_puts(bioBank, strPublicMint.Get()); // Instantiate a PublicBank (Lucre) object. // We will use it to generate all the prototokens in the loop below. PublicBank bank; bank.ReadBIO(bioBank); Release(); const int nFinalTokenCount = (nTokenCount < OTToken::nMinimumPrototokenCount) ? OTToken::nMinimumPrototokenCount : nTokenCount; // Token count is actually 1 (always) with Lucre, although this lib has potential to work with // multiple proto-tokens, you can see this loop as though it always executes just once. for (int i = 0; i < nFinalTokenCount; i++) { CoinRequest req(bank); // write the private coin request to BIO req.WriteBIO(bioCoin); // write the public coin request to BIO ((PublicCoinRequest *)&req)->WriteBIO(bioPublicCoin); // Convert the two bios to our format char privateCoinBuffer[4096], publicCoinBuffer[4096]; // todo stop hardcoding these string lengths int privatecoinLen = BIO_read(bioCoin, privateCoinBuffer, 4000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason. int publiccoinLen = BIO_read(bioPublicCoin, publicCoinBuffer, 4000); if (privatecoinLen && publiccoinLen) { // With this, we have the Lucre public and private bank info converted to OTStrings OTString strPublicCoin; strPublicCoin.Set(publicCoinBuffer, publiccoinLen); OTString strPrivateCoin; strPrivateCoin.Set(privateCoinBuffer, privatecoinLen); OTASCIIArmor * pArmoredPublic = new OTASCIIArmor(strPublicCoin); OTASCIIArmor * pArmoredPrivate = new OTASCIIArmor(); OT_ASSERT_MSG(((NULL != pArmoredPublic) && (NULL != pArmoredPrivate)), "ERROR: Unable to allocate memory in OTToken::GenerateTokenRequest\n"); // Change the state. It's no longer a blank token, but a prototoken. m_State = OTToken::protoToken; // Seal the private coin info up into an encrypted Envelope // and set it onto pArmoredPrivate (which was just added to our internal map, above.) OTEnvelope theEnvelope; theEnvelope.Seal(theNym, strPrivateCoin); // Todo check the return values on these two functions theEnvelope.GetAsciiArmoredData(*pArmoredPrivate); m_mapPublic[i] = pArmoredPublic; m_mapPrivate[i] = pArmoredPrivate; m_nTokenCount = nFinalTokenCount; SetDenomination(lDenomination); } else { // Error condition } // Free the Private and Public coins and allocate them fresh, for the next iteration of the loop. BIO_free_all(bioCoin); BIO_free_all(bioPublicCoin); bioCoin = BIO_new(BIO_s_mem()); bioPublicCoin = BIO_new(BIO_s_mem()); } // Cleanup openssl resources. BIO_free_all(bioBank); BIO_free_all(bioCoin); BIO_free_all(bioPublicCoin); return true; }