#pragma once #ifndef MESSMER_CPPUTILS_DATA_FIXEDSIZEDATA_H_ #define MESSMER_CPPUTILS_DATA_FIXEDSIZEDATA_H_ #include #include #include #include namespace cpputils { template class FixedSizeData { public: //Non-virtual destructor because we want objects to be small ~FixedSizeData() {} static constexpr unsigned int BINARY_LENGTH = SIZE; static constexpr unsigned int STRING_LENGTH = 2 * BINARY_LENGTH; // Hex encoding static FixedSizeData CreatePseudoRandom(); static FixedSizeData CreateOSRandom(); static FixedSizeData FromString(const std::string &data); std::string ToString() const; static FixedSizeData FromBinary(const void *source); void ToBinary(void *target) const; const unsigned char *data() const; private: FixedSizeData() {} static CryptoPP::AutoSeededRandomPool &PseudoRandomPool(); unsigned char _data[BINARY_LENGTH]; }; template bool operator==(const FixedSizeData &lhs, const FixedSizeData &rhs); template bool operator!=(const FixedSizeData &lhs, const FixedSizeData &rhs); // ----- Implementation ----- template constexpr unsigned int FixedSizeData::BINARY_LENGTH; template constexpr unsigned int FixedSizeData::STRING_LENGTH; template CryptoPP::AutoSeededRandomPool &FixedSizeData::PseudoRandomPool() { //TODO Make seeding use blocking=true (aka /dev/random instead of /dev/urandom) or offer a configuration option? static CryptoPP::AutoSeededRandomPool singleton; return singleton; } template FixedSizeData FixedSizeData::CreatePseudoRandom() { FixedSizeData result; PseudoRandomPool().GenerateBlock(result._data, BINARY_LENGTH); return result; } template FixedSizeData FixedSizeData::CreateOSRandom() { FixedSizeData result; CryptoPP::OS_GenerateRandomBlock(true, result._data, BINARY_LENGTH); return result; } template FixedSizeData FixedSizeData::FromString(const std::string &data) { assert(data.size() == STRING_LENGTH); FixedSizeData result; CryptoPP::StringSource(data, true, new CryptoPP::HexDecoder( new CryptoPP::ArraySink(result._data, BINARY_LENGTH) ) ); return result; } template std::string FixedSizeData::ToString() const { std::string result; CryptoPP::ArraySource(_data, BINARY_LENGTH, true, new CryptoPP::HexEncoder( new CryptoPP::StringSink(result) ) ); assert(result.size() == STRING_LENGTH); return result; } template const unsigned char *FixedSizeData::data() const { return _data; } template void FixedSizeData::ToBinary(void *target) const { std::memcpy(target, _data, BINARY_LENGTH); } template FixedSizeData FixedSizeData::FromBinary(const void *source) { FixedSizeData result; std::memcpy(result._data, source, BINARY_LENGTH); return result; } template bool operator==(const FixedSizeData &lhs, const FixedSizeData &rhs) { return 0 == std::memcmp(lhs.data(), rhs.data(), FixedSizeData::BINARY_LENGTH); } template bool operator!=(const FixedSizeData &lhs, const FixedSizeData &rhs) { return !operator==(lhs, rhs); } } #endif