forked from f1xpl/aasdk
-
Notifications
You must be signed in to change notification settings - Fork 47
Cryptor_8cpp
github-actions edited this page Mar 15, 2026
·
3 revisions
title: src/Messenger/Cryptor.cpp
| Name |
|---|
| aasdk |
| aasdk::messenger |
| Name | |
|---|---|
| bool | enabled |
| int | sampleEvery |
bool enabled {false};int sampleEvery {1};// This file is part of aasdk library project.
// Copyright (C) 2018 f1x.studio (Michal Szwaj)
// Copyright (C) 2024 CubeOne (Simon Dean - simon.dean@cubeone.co.uk)
// Copyright (C) 2024 OpenCarDev (Matthew Hilton - matthilton2005@gmail.com)
// Copyright (C) 2026 OpenCarDev (Matthew Hilton - matthilton2005@gmail.com)
//
// aasdk is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// aasdk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with aasdk. If not, see <http://www.gnu.org/licenses/>.
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstdlib>
#include <functional>
#include <fstream>
#include <sstream>
#include <aasdk/Messenger/Cryptor.hpp>
#include <aasdk/Error/Error.hpp>
#include <aasdk/Common/Log.hpp>
#include <aasdk/Common/ModernLogger.hpp>
namespace aasdk {
namespace messenger {
namespace {
struct RuntimeTraceConfig {
bool enabled{false};
int sampleEvery{1};
};
static auto parseEnvBool(const char* value, bool defaultValue) -> bool {
if (value == nullptr) {
return defaultValue;
}
const std::string token(value);
if (token.empty()) {
return defaultValue;
}
if (token == "1" || token == "true" || token == "TRUE" || token == "on" ||
token == "ON" || token == "yes" || token == "YES") {
return true;
}
if (token == "0" || token == "false" || token == "FALSE" || token == "off" ||
token == "OFF" || token == "no" || token == "NO") {
return false;
}
return defaultValue;
}
static auto parseEnvInt(const char* value, int defaultValue, int minValue, int maxValue) -> int {
if (value == nullptr) {
return defaultValue;
}
try {
const int parsed = std::stoi(value);
return std::max(minValue, std::min(maxValue, parsed));
} catch (...) {
return defaultValue;
}
}
static auto readRuntimeTraceConfig() -> RuntimeTraceConfig {
RuntimeTraceConfig cfg;
cfg.enabled = parseEnvBool(std::getenv("AASDK_TRACE_CRYPTOR"), false);
cfg.sampleEvery = parseEnvInt(std::getenv("AASDK_TRACE_CRYPTOR_SAMPLE_EVERY"), 1, 1, 1000);
return cfg;
}
static auto getRuntimeTraceConfig() -> RuntimeTraceConfig {
static RuntimeTraceConfig cached = readRuntimeTraceConfig();
static auto lastRefresh = std::chrono::steady_clock::now();
const auto now = std::chrono::steady_clock::now();
if (now - lastRefresh > std::chrono::seconds(1)) {
cached = readRuntimeTraceConfig();
lastRefresh = now;
}
return cached;
}
static auto shouldEmitTraceSample() -> bool {
static std::atomic<uint64_t> counter{0};
const RuntimeTraceConfig cfg = getRuntimeTraceConfig();
if (!cfg.enabled) {
return false;
}
const uint64_t current = ++counter;
return (current % static_cast<uint64_t>(cfg.sampleEvery)) == 0;
}
} // namespace
// Embedded certificate constants
static const std::string cCertificate = "-----BEGIN CERTIFICATE-----\n\
MIIDKjCCAhICARswDQYJKoZIhvcNAQELBQAwWzELMAkGA1UEBhMCVVMxEzARBgNV\n\
BAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAdBgNVBAoM\n\
Fkdvb2dsZSBBdXRvbW90aXZlIExpbmswJhcRMTQwNzA0MDAwMDAwLTA3MDAXETQ1\n\
MDQyOTE0MjgzOC0wNzAwMFMxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzER\n\
MA8GA1UEBwwISGFjaGlvamkxFDASBgNVBAoMC0pWQyBLZW53b29kMQswCQYDVQQL\n\
DAIwMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM911mNnUfx+WJtx\n\
uk06GO7kXRW/gXUVNQBkbAFZmVdVNvLoEQNthi2X8WCOwX6n6oMPxU2MGJnvicP3\n\
6kBqfHhfQ2Fvqlf7YjjhgBHh0lqKShVPxIvdatBjVQ76aym5H3GpkigLGkmeyiVo\n\
VO8oc3cJ1bO96wFRmk7kJbYcEjQyakODPDu4QgWUTwp1Z8Dn41ARMG5OFh6otITL\n\
XBzj9REkUPkxfS03dBXGr5/LIqvSsnxib1hJ47xnYJXROUsBy3e6T+fYZEEzZa7y\n\
7tFioHIQ8G/TziPmvFzmQpaWMGiYfoIgX8WoR3GD1diYW+wBaZTW+4SFUZJmRKgq\n\
TbMNFkMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAsGdH5VFn78WsBElMXaMziqFC\n\
zmilkvr85/QpGCIztI0FdF6xyMBJk/gYs2thwvF+tCCpXoO8mjgJuvJZlwr6fHzK\n\
Ox5hNUb06AeMtsUzUfFjSZXKrSR+XmclVd+Z6/ie33VhGePOPTKYmJ/PPfTT9wvT\n\
93qswcxhA+oX5yqLbU3uDPF1ZnJaEeD/YN45K/4eEA4/0SDXaWW14OScdS2LV0Bc\n\
YmsbkPVNYZn37FlY7e2Z4FUphh0A7yME2Eh/e57QxWrJ1wubdzGnX8mrABc67ADU\n\
U5r9tlTRqMs7FGOk6QS2Cxp4pqeVQsrPts4OEwyPUyb3LfFNo3+sP111D9zEow==\n\
-----END CERTIFICATE-----\n";
static const std::string cPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n\
MIIEowIBAAKCAQEAz3XWY2dR/H5Ym3G6TToY7uRdFb+BdRU1AGRsAVmZV1U28ugR\n\
A22GLZfxYI7Bfqfqgw/FTYwYme+Jw/fqQGp8eF9DYW+qV/tiOOGAEeHSWopKFU/E\n\
i91q0GNVDvprKbkfcamSKAsaSZ7KJWhU7yhzdwnVs73rAVGaTuQlthwSNDJqQ4M8\n\
O7hCBZRPCnVnwOfjUBEwbk4WHqi0hMtcHOP1ESRQ+TF9LTd0Fcavn8siq9KyfGJv\n\
WEnjvGdgldE5SwHLd7pP59hkQTNlrvLu0WKgchDwb9POI+a8XOZClpYwaJh+giBf\n\
xahHcYPV2Jhb7AFplNb7hIVRkmZEqCpNsw0WQwIDAQABAoIBAB2u7ZLheKCY71Km\n\
bhKYqnKb6BmxgfNfqmq4858p07/kKG2O+Mg1xooFgHrhUhwuKGbCPee/kNGNrXeF\n\
pFW9JrwOXVS2pnfaNw6ObUWhuvhLaxgrhqLAdoUEgWoYOHcKzs3zhj8Gf6di+edq\n\
SyTA8+xnUtVZ6iMRKvP4vtCUqaIgBnXdmQbGINP+/4Qhb5R7XzMt/xPe6uMyAIyC\n\
y5Fm9HnvekaepaeFEf3bh4NV1iN/R8px6cFc6ELYxIZc/4Xbm91WGqSdB0iSriaZ\n\
TjgrmaFjSO40tkCaxI9N6DGzJpmpnMn07ifhl2VjnGOYwtyuh6MKEnyLqTrTg9x0\n\
i3mMwskCgYEA9IyljPRerXxHUAJt+cKOayuXyNt80q9PIcGbyRNvn7qIY6tr5ut+\n\
ZbaFgfgHdSJ/4nICRq02HpeDJ8oj9BmhTAhcX6c1irH5ICjRlt40qbPwemIcpybt\n\
mb+DoNYbI8O4dUNGH9IPfGK8dRpOok2m+ftfk94GmykWbZF5CnOKIp8CgYEA2Syc\n\
5xlKB5Qk2ZkwXIzxbzozSfunHhWWdg4lAbyInwa6Y5GB35UNdNWI8TAKZsN2fKvX\n\
RFgCjbPreUbREJaM3oZ92o5X4nFxgjvAE1tyRqcPVbdKbYZgtcqqJX06sW/g3r/3\n\
RH0XPj2SgJIHew9sMzjGWDViMHXLmntI8rVA7d0CgYBOr36JFwvrqERN0ypNpbMr\n\
epBRGYZVSAEfLGuSzEUrUNqXr019tKIr2gmlIwhLQTmCxApFcXArcbbKs7jTzvde\n\
PoZyZJvOr6soFNozP/YT8Ijc5/quMdFbmgqhUqLS5CPS3z2N+YnwDNj0mO1aPcAP\n\
STmcm2DmxdaolJksqrZ0owKBgQCD0KJDWoQmaXKcaHCEHEAGhMrQot/iULQMX7Vy\n\
gl5iN5E2EgFEFZIfUeRWkBQgH49xSFPWdZzHKWdJKwSGDvrdrcABwdfx520/4MhK\n\
d3y7CXczTZbtN1zHuoTfUE0pmYBhcx7AATT0YCblxrynosrHpDQvIefBBh5YW3AB\n\
cKZCOQKBgEM/ixzI/OVSZ0Py2g+XV8+uGQyC5XjQ6cxkVTX3Gs0ZXbemgUOnX8co\n\
eCXS4VrhEf4/HYMWP7GB5MFUOEVtlLiLM05ruUL7CrphdfgayDXVcTPfk75lLhmu\n\
KAwp3tIHPoJOQiKNQ3/qks5km/9dujUGU2ARiU3qmxLMdgegFz8e\n\
-----END RSA PRIVATE KEY-----\n";
// Helper function to read file contents
static std::string readFileContents(const std::string& filepath) {
std::ifstream file(filepath);
if (!file.is_open()) {
AASDK_LOG(error) << "[Cryptor] Failed to open file: " << filepath;
return "";
}
std::stringstream buffer;
buffer << file.rdbuf();
return buffer.str();
}
// Helper to try multiple certificate paths
static std::string loadCertificate() {
// Try paths in order of preference
std::vector<std::string> certPaths = {
"/etc/aasdk/headunit.crt", // Installed system path
"/etc/openauto/headunit.crt", // Legacy path (backward compatibility)
"/usr/share/aasdk/cert/headunit.crt", // Alternative system path
"./cert/headunit.crt", // Development path
"../cert/headunit.crt" // Alternative development path
};
for (const auto& path : certPaths) {
std::string content = readFileContents(path);
if (!content.empty()) {
AASDK_LOG(info) << "[Cryptor] Loaded certificate from: " << path;
return content;
}
}
AASDK_LOG(warning) << "[Cryptor] Could not load certificate from file, using embedded fallback";
return cCertificate; // Fallback to embedded certificate
}
// Helper to try multiple private key paths
static std::string loadPrivateKey() {
// Try paths in order of preference
std::vector<std::string> keyPaths = {
"/etc/aasdk/headunit.key", // Installed system path
"/etc/openauto/headunit.key", // Legacy path (backward compatibility)
"/usr/share/aasdk/cert/headunit.key", // Alternative system path
"./cert/headunit.key", // Development path
"../cert/headunit.key" // Alternative development path
};
for (const auto& path : keyPaths) {
std::string content = readFileContents(path);
if (!content.empty()) {
AASDK_LOG(info) << "[Cryptor] Loaded private key from: " << path;
return content;
}
}
AASDK_LOG(warning) << "[Cryptor] Could not load private key from file, using embedded fallback";
return cPrivateKey; // Fallback to embedded key
}
Cryptor::Cryptor(transport::ISSLWrapper::Pointer sslWrapper)
: sslWrapper_(std::move(sslWrapper)), maxBufferSize_(1024 * 20), certificate_(nullptr), privateKey_(nullptr),
context_(nullptr), ssl_(nullptr), isActive_(false) {
}
void Cryptor::init() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
// Load certificate from file or fallback to embedded
std::string certContent = loadCertificate();
certificate_ = sslWrapper_->readCertificate(certContent);
if (certificate_ == nullptr) {
throw error::Error(error::ErrorCode::SSL_READ_CERTIFICATE);
}
// Load private key from file or fallback to embedded
std::string keyContent = loadPrivateKey();
privateKey_ = sslWrapper_->readPrivateKey(keyContent);
if (privateKey_ == nullptr) {
throw error::Error(error::ErrorCode::SSL_READ_PRIVATE_KEY);
}
auto method = sslWrapper_->getMethod();
if (method == nullptr) {
throw error::Error(error::ErrorCode::SSL_METHOD);
}
context_ = sslWrapper_->createContext(method);
if (context_ == nullptr) {
throw error::Error(error::ErrorCode::SSL_CONTEXT_CREATION);
}
if (!sslWrapper_->useCertificate(context_, certificate_)) {
throw error::Error(error::ErrorCode::SSL_USE_CERTIFICATE);
}
if (!sslWrapper_->usePrivateKey(context_, privateKey_)) {
throw error::Error(error::ErrorCode::SSL_USE_PRIVATE_KEY);
}
ssl_ = sslWrapper_->createInstance(context_);
if (ssl_ == nullptr) {
throw error::Error(error::ErrorCode::SSL_HANDLER_CREATION);
}
bIOs_ = sslWrapper_->createBIOs();
if (bIOs_.first == nullptr) {
throw error::Error(error::ErrorCode::SSL_READ_BIO_CREATION);
}
if (bIOs_.second == nullptr) {
throw error::Error(error::ErrorCode::SSL_WRITE_BIO_CREATION);
}
sslWrapper_->setBIOs(ssl_, bIOs_, maxBufferSize_);
sslWrapper_->setConnectState(ssl_);
}
void Cryptor::deinit() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
if (ssl_ != nullptr) {
sslWrapper_->free(ssl_);
ssl_ = nullptr;
}
bIOs_ = {nullptr, nullptr};
if (context_ != nullptr) {
sslWrapper_->free(context_);
context_ = nullptr;
}
if (certificate_ != nullptr) {
sslWrapper_->free(certificate_);
certificate_ = nullptr;
}
if (privateKey_ != nullptr) {
sslWrapper_->free(privateKey_);
privateKey_ = nullptr;
}
}
bool Cryptor::doHandshake() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
auto result = sslWrapper_->doHandshake(ssl_);
if (result == SSL_ERROR_WANT_READ) {
return false;
} else if (result == SSL_ERROR_NONE) {
isActive_ = true;
return true;
} else {
throw error::Error(error::ErrorCode::SSL_HANDSHAKE, result);
}
}
size_t Cryptor::encrypt(common::Data &output, const common::DataConstBuffer &buffer) {
std::lock_guard<decltype(mutex_)> lock(mutex_);
size_t totalWrittenBytes = 0;
while (totalWrittenBytes < buffer.size) {
const common::DataConstBuffer currentBuffer(buffer.cdata, buffer.size, totalWrittenBytes);
const auto writeSize = sslWrapper_->sslWrite(ssl_, currentBuffer.cdata, currentBuffer.size);
if (writeSize <= 0) {
throw error::Error(error::ErrorCode::SSL_WRITE, sslWrapper_->getError(ssl_, writeSize));
}
totalWrittenBytes += writeSize;
}
return this->read(output);
}
size_t Cryptor::decrypt(common::Data &output, const common::DataConstBuffer &buffer, int frameLength) {
std::lock_guard<decltype(mutex_)> lock(mutex_);
const bool traceSample = shouldEmitTraceSample();
const int pendingBeforeWrite = sslWrapper_->getAvailableBytes(ssl_);
this->write(buffer);
const size_t beginOffset = output.size();
size_t totalReadSize = 0;
while (true) {
const size_t readBytes = 2048;
output.resize(beginOffset + totalReadSize + readBytes);
const auto ¤tBuffer = common::DataBuffer(output, totalReadSize + beginOffset);
const auto readSize = sslWrapper_->sslRead(ssl_, currentBuffer.data, currentBuffer.size);
if (readSize <= 0) {
const auto nativeError = sslWrapper_->getError(ssl_, readSize);
const int pendingAfterRead = sslWrapper_->getAvailableBytes(ssl_);
if (nativeError == SSL_ERROR_WANT_READ || nativeError == SSL_ERROR_WANT_WRITE) {
if (traceSample) {
AASDK_LOG(info) << "[CryptorTrace] decrypt-drained"
<< " frameLength=" << frameLength
<< " encryptedBytesIn=" << buffer.size
<< " totalReadSize=" << totalReadSize
<< " requestedReadBytes=" << readBytes
<< " sslError=" << nativeError
<< " pendingBeforeWrite=" << pendingBeforeWrite
<< " pendingAfterRead=" << pendingAfterRead;
}
AASDK_LOG(debug) << "[Cryptor] SSL decrypt drained"
<< " frameLength=" << frameLength
<< " totalReadSize=" << totalReadSize
<< " requestedReadBytes=" << readBytes
<< " sslError=" << nativeError;
output.resize(beginOffset + totalReadSize);
return totalReadSize;
}
const std::string info = "decrypt sslRead<=0"
" frameLength=" + std::to_string(frameLength) +
" totalReadSize=" + std::to_string(totalReadSize) +
" requestedReadBytes=" + std::to_string(readBytes) +
" returnCode=" + std::to_string(readSize);
throw error::Error(error::ErrorCode::SSL_READ, nativeError, info);
}
totalReadSize += static_cast<size_t>(readSize);
if (traceSample) {
AASDK_LOG(info) << "[CryptorTrace] decrypt-read"
<< " frameLength=" << frameLength
<< " encryptedBytesIn=" << buffer.size
<< " readSize=" << readSize
<< " totalReadSize=" << totalReadSize
<< " pendingBeforeWrite=" << pendingBeforeWrite;
}
}
}
common::Data Cryptor::readHandshakeBuffer() {
std::lock_guard<decltype(mutex_)> lock(mutex_);
common::Data output;
this->read(output);
return output;
}
void Cryptor::writeHandshakeBuffer(const common::DataConstBuffer &buffer) {
std::lock_guard<decltype(mutex_)> lock(mutex_);
this->write(buffer);
}
size_t Cryptor::read(common::Data &output) {
const auto pendingSize = sslWrapper_->bioCtrlPending(bIOs_.second);
size_t beginOffset = output.size();
output.resize(beginOffset + pendingSize);
size_t totalReadSize = 0;
while (totalReadSize < pendingSize) {
const auto ¤tBuffer = common::DataBuffer(output, totalReadSize + beginOffset);
const auto readSize = sslWrapper_->bioRead(bIOs_.second, currentBuffer.data, currentBuffer.size);
if (readSize <= 0) {
const auto nativeError = sslWrapper_->getError(ssl_, readSize);
const std::string info = "read bioRead<=0"
" pendingSize=" + std::to_string(pendingSize) +
" totalReadSize=" + std::to_string(totalReadSize) +
" currentBufferSize=" + std::to_string(currentBuffer.size) +
" returnCode=" + std::to_string(readSize);
throw error::Error(error::ErrorCode::SSL_BIO_READ, nativeError, info);
}
totalReadSize += readSize;
}
return totalReadSize;
}
void Cryptor::write(const common::DataConstBuffer &buffer) {
size_t totalWrittenBytes = 0;
while (totalWrittenBytes < buffer.size) {
const common::DataConstBuffer currentBuffer(buffer.cdata, buffer.size, totalWrittenBytes);
const auto writeSize = sslWrapper_->bioWrite(bIOs_.first, currentBuffer.cdata, currentBuffer.size);
if (writeSize <= 0) {
throw error::Error(error::ErrorCode::SSL_BIO_WRITE, sslWrapper_->getError(ssl_, writeSize));
}
totalWrittenBytes += writeSize;
}
}
bool Cryptor::isActive() const {
std::lock_guard<decltype(mutex_)> lock(mutex_);
return isActive_;
}
}
}Updated on 2026-03-15 at 09:02:41 +0000