161 lines
5.0 KiB
C++
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;
|
|
}
|