#include "../inc/integretychecker.h" #include "../cryptopp/base64.h" #include "../cryptopp/files.h" #include "../cryptopp/osrng.h" #include "../cryptopp/rsa.h" #include #include #include namespace fs = std::filesystem; const int IntegretyCheck::KEY_SIZE = 2048; const std::string IntegretyCheck::HASH_FILE = "hashlist.sha256"; const std::string IntegretyCheck::KEY_FILE = "appKey.pub"; const std::string IntegretyCheck::SIGNATURE_MARKER = "### signature ###\n"; std::string string_to_hex(const std::string &input) { static const char *const lut = "0123456789ABCDEF"; size_t len = input.length(); std::string output; output.reserve(2 * len); for (size_t i = 0; i < len; ++i) { const unsigned char c = input[i]; output.push_back(lut[c >> 4]); output.push_back(lut[c & 15]); } return output; } IntegretyCheck::IntegretyCheck() {} IntegretyCheck::IntegretyCheck(const std::string &appPath, const std::string &keyFile, const std::string &hashList) { generateKeyPair(); saveKeyFile(appPath); std::string hashlist = generateHashList(appPath); signHashList(hashlist); // loadHashList(hashList); } bool IntegretyCheck::loadKeyFile(const std::string &app) { fs::path appPath(app); CryptoPP::FileSource input((appPath / KEY_FILE).c_str(), true); m_publicKey.BERDecode(input); return true; } bool IntegretyCheck::saveKeyFile(const std::string &app) { ///@todo https://github.com/noloader/cryptopp-pem fs::path appPath(app); std::cout << (appPath / KEY_FILE).string() << std::endl; CryptoPP::FileSink output((appPath / KEY_FILE).c_str()); m_publicKey.DEREncode(output); return true; } bool IntegretyCheck::generateKeyPair() { CryptoPP::AutoSeededRandomPool rng; CryptoPP::InvertibleRSAFunction params; params.GenerateRandomWithKeySize(rng, KEY_SIZE); m_privateKey = CryptoPP::RSA::PrivateKey(params); m_publicKey = CryptoPP::RSA::PublicKey(params); return true; } std::string IntegretyCheck::generateHashList(const std::string &app) { std::stringstream hashlist; fs::path appPath(app); std::string p = appPath.string(); for (auto f : fs::recursive_directory_iterator(appPath)) { if (f.is_directory()) { // skip directory, iterator is recursive } else { // strip appPath std::string filepath = f.path().string(); filepath.erase(0, p.size()); // write hash line to file hashlist << generateFileHash(f.path().string()) << " *" << filepath << std::endl; } } return hashlist.str(); } std::string IntegretyCheck::generateFileHash(const std::string &filepath) { std::ifstream in(filepath); std::string contents((std::istreambuf_iterator(in)), std::istreambuf_iterator()); CryptoPP::byte const *pbData = (CryptoPP::byte *)contents.c_str(); unsigned long nDataLen = contents.size(); CryptoPP::byte abDigest[CryptoPP::SHA256::DIGESTSIZE]; CryptoPP::SHA256().CalculateDigest(abDigest, pbData, nDataLen); return string_to_hex( std::string((char *)abDigest, CryptoPP::SHA256::DIGESTSIZE)); } void IntegretyCheck::signHashList(std::string &hashList) { CryptoPP::AutoSeededRandomPool rng; tmp = hashList; CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(m_privateKey); size_t signature_length = signer.MaxSignatureLength(); CryptoPP::SecByteBlock signature(signature_length); signature_length = signer.SignMessage(rng, (const CryptoPP::byte *)hashList.c_str(), hashList.length(), signature); std::cerr << signature_length << std::endl; signature.resize(signature_length); tmpSec = signature; // transfrom binary signature to base64 encoded string std::string strHexSignature; CryptoPP::Base64Encoder base64enc(new CryptoPP::StringSink(strHexSignature)); base64enc.Put(signature, signature_length); base64enc.MessageEnd(); // add divider and base64 encoded signature to hash list hashList.append(SIGNATURE_MARKER); hashList.append(strHexSignature); } bool IntegretyCheck::verifyHashList(const std::string &signedHashList) { size_t startSig = signedHashList.find(SIGNATURE_MARKER); if (startSig == std::string::npos) { return false; } // extract hash list std::string hashList = signedHashList.substr(0, startSig); // extract base64 encoded signature std::string base64Signature = signedHashList.substr(startSig + SIGNATURE_MARKER.length()); // decode base64 encoded signature std::string decodedSignature; CryptoPP::StringSource decoder( base64Signature, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decodedSignature))); // transform std::string into SecByteBlock CryptoPP::SecByteBlock signature( (const CryptoPP::byte *)decodedSignature.c_str(), decodedSignature.length()); CryptoPP::RSASSA_PKCS1v15_SHA_Verifier verifier(m_publicKey); bool result = verifier.VerifyMessage((const CryptoPP::byte *)hashList.c_str(), hashList.length(), signature, signature.size()); return result; }