SoftwareIntegretyChecker/src/integretychecker.cpp

161 lines
5.0 KiB
C++

#include "../inc/integretychecker.h"
#include "../cryptopp/base64.h"
#include "../cryptopp/files.h"
#include "../cryptopp/osrng.h"
#include "../cryptopp/rsa.h"
#include <filesystem>
#include <fstream>
#include <iostream>
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<char>(in)),
std::istreambuf_iterator<char>());
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;
}