#include #include #include "../shared/Random.h" #include "../shared/MiscSupport.h" #include "ServerSigner.h" std::string ServerSigner::makeSecret() { return ntoa(getRandom31()) + ntoa(TimeVal(true).asMicroseconds()); } std::string ServerSigner::hashHex(std::string const &input) { unsigned char buffer[SHA_DIGEST_LENGTH]; SHA1(reinterpret_cast< const unsigned char * >(input.c_str()), input.length(), buffer); std::string result; result.reserve(SHA_DIGEST_LENGTH * 2); unsigned char *source = buffer; for (int i = 0; i < SHA_DIGEST_LENGTH; i++) { char hexBuffer[3]; sprintf(hexBuffer, "%02X", *source); result.append(hexBuffer, 2); source++; } return result; } ServerSigner::ServerSigner() : _secret(makeSecret()) { } std::string ServerSigner::encodeString(std::string const &input) const { return input + ":" + hashHex(input + _secret); } bool ServerSigner::decodeString(std::string const &encoded, std::string &output) const { auto lastColon = encoded.rfind(':'); if (lastColon == std::string::npos) { // Can't parse the input. output.clear(); return false; } output = encoded.substr(0, lastColon); if (encoded == encodeString(output)) // Valid input. return true; // Signature does not match. output.clear(); return false; } std::string ServerSigner::encodeInt(int64_t input) const { return encodeString(ntoa(input)); } int64_t ServerSigner::decodeInt(std::string const &encoded, int64_t onFail) const { std::string asString; if (!decodeString(encoded, asString)) // Invalid signature. return onFail; // Try to parse the number without the signature. return strtolDefault(asString, onFail); } std::string ServerSigner::encodeInts(std::vector< int64_t > const &input) const { std::string encoded; for (auto it = input.begin(); it != input.end(); it++) { if (!encoded.empty()) encoded += ':'; encoded += ntoa(*it); } return encodeString(encoded); } bool ServerSigner::decodeInts(std::string const &encoded, std::vector< int64_t > &output) const { output.clear(); std::string decoded; if (!decodeString(encoded, decoded)) // Problem with signature. return false; if (decoded.empty()) // This has to be a special case. explode() doesn't know the difference // between an empty list and a list containing only the empty string. We // optimistically assume the empty string points to a valid list with 0 // elements. The alternative would be a list with one item that we //couldn't decode to an integer. return true; std::vector< std::string > pieces = explode(":", decoded); output.reserve(pieces.size()); try { for (auto it = pieces.cbegin(); it != pieces.end(); it++) nfroma(nextItem(output), *it); return true; } catch (InvalidConversionException) { // Problem parsing one of the integers. output.clear(); return false; } } #ifdef DEBUG_ServerSigner #include // g++ -std=c++0x -ggdb -lssl -lcrypto -DDEBUG_ServerSigner ServerSigner.C ../shared/MiscSupport.C ../shared/Random.C int main(int, char**) { ServerSigner *serverSigner = new ServerSigner(); std::vector< int64_t > list; while (std::cin) { std::cout<<"command? "; std::string command; std::cin>>command; if (command == "encode") { std::string toEncode; std::cin>>toEncode; uint64_t asNumber = strtoulDefault(toEncode, 0); std::cout< "<encodeInt(asNumber) <>toDecode; std::cout< "<decodeInt(toDecode) <>toEncode; uint64_t asNumber = strtoulDefault(toEncode, 0); list.push_back(asNumber); std::cout<<(std::string)(TclList()< " <encodeInts(list) <>toDecode; std::vector< int64_t > decoded; bool success = serverSigner->decodeInts(toDecode, decoded); std::cout< "; if (!success) std::cout<<"Fail!"; else std::cout<<(std::string)(TclList()<