Compare commits
3 Commits
a529e82912
...
3b83e60352
Author | SHA1 | Date |
---|---|---|
laptoy | 3b83e60352 | 6 months ago |
laptoy | f6130b2d1f | 6 months ago |
laptoy | e7778c32b7 | 6 months ago |
@ -0,0 +1,575 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* (c) 2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
*
|
||||
* QGroundControl is licensed according to the terms in the file
|
||||
* COPYING.md in the root of the source code directory.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "PairingManager.h"
|
||||
#include "SettingsManager.h"
|
||||
#include "MicrohardManager.h"
|
||||
#include "QGCApplication.h"
|
||||
#include "QGCCorePlugin.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QJsonObject>
|
||||
#include <QStandardPaths>
|
||||
#include <QMutexLocker>
|
||||
|
||||
QGC_LOGGING_CATEGORY(PairingManagerLog, "PairingManagerLog")
|
||||
|
||||
static const char* jsonFileName = "pairing.json";
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static QString
|
||||
random_string(uint length)
|
||||
{
|
||||
auto randchar = []() -> char
|
||||
{
|
||||
const char charset[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
const uint max_index = (sizeof(charset) - 1);
|
||||
return charset[static_cast<uint>(rand()) % max_index];
|
||||
};
|
||||
std::string str(length, 0);
|
||||
std::generate_n(str.begin(), length, randchar);
|
||||
return QString::fromStdString(str);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
PairingManager::PairingManager(QGCApplication* app, QGCToolbox* toolbox)
|
||||
: QGCTool(app, toolbox)
|
||||
, _aes("J6+KuWh9K2!hG(F'", 0x368de30e8ec063ce)
|
||||
{
|
||||
_jsonFileName = QDir::temp().filePath(jsonFileName);
|
||||
connect(this, &PairingManager::parsePairingJson, this, &PairingManager::_parsePairingJson);
|
||||
connect(this, &PairingManager::setPairingStatus, this, &PairingManager::_setPairingStatus);
|
||||
connect(this, &PairingManager::startUpload, this, &PairingManager::_startUpload);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
PairingManager::~PairingManager()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
PairingManager::setToolbox(QGCToolbox *toolbox)
|
||||
{
|
||||
QGCTool::setToolbox(toolbox);
|
||||
_updatePairedDeviceNameList();
|
||||
emit pairedListChanged();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_pairingCompleted(QString name)
|
||||
{
|
||||
_writeJson(_jsonDoc, _pairingCacheFile(name));
|
||||
_remotePairingMap["NM"] = name;
|
||||
_lastPaired = name;
|
||||
_updatePairedDeviceNameList();
|
||||
emit pairedListChanged();
|
||||
emit pairedVehicleChanged();
|
||||
//_app->informationMessageBoxOnMainThread("", tr("Paired with %1").arg(name));
|
||||
setPairingStatus(PairingSuccess, tr("Pairing Successfull"));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_connectionCompleted(QString /*name*/)
|
||||
{
|
||||
//QString pwd = _remotePairingMap["PWD"].toString();
|
||||
//_toolbox->microhardManager()->switchToConnectionEncryptionKey(pwd);
|
||||
//_app->informationMessageBoxOnMainThread("", tr("Connected to %1").arg(name));
|
||||
setPairingStatus(PairingConnected, tr("Connection Successfull"));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_startUpload(QString pairURL, QJsonDocument jsonDoc)
|
||||
{
|
||||
QMutexLocker lock(&_uploadMutex);
|
||||
if (_uploadManager != nullptr) {
|
||||
return;
|
||||
}
|
||||
_uploadManager = new QNetworkAccessManager(this);
|
||||
|
||||
QString str = jsonDoc.toJson(QJsonDocument::JsonFormat::Compact);
|
||||
qCDebug(PairingManagerLog) << "Starting upload to: " << pairURL << " " << str;
|
||||
_uploadData = QString::fromStdString(_aes.encrypt(str.toStdString()));
|
||||
_uploadURL = pairURL;
|
||||
_startUploadRequest();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_startUploadRequest()
|
||||
{
|
||||
QNetworkRequest req;
|
||||
req.setUrl(QUrl(_uploadURL));
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
QNetworkReply *reply = _uploadManager->post(req, _uploadData.toUtf8());
|
||||
connect(reply, &QNetworkReply::finished, this, &PairingManager::_uploadFinished);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_stopUpload()
|
||||
{
|
||||
QMutexLocker lock(&_uploadMutex);
|
||||
if (_uploadManager != nullptr) {
|
||||
delete _uploadManager;
|
||||
_uploadManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_uploadFinished()
|
||||
{
|
||||
QMutexLocker lock(&_uploadMutex);
|
||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(QObject::sender());
|
||||
if (reply) {
|
||||
if (_uploadManager != nullptr) {
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
qCDebug(PairingManagerLog) << "Upload finished.";
|
||||
QByteArray bytes = reply->readAll();
|
||||
QString str = QString::fromUtf8(bytes.data(), bytes.size());
|
||||
qCDebug(PairingManagerLog) << "Reply: " << str;
|
||||
auto a = str.split(QRegExp("\\s+"));
|
||||
if (a[0] == "Accepted" && a.length() > 1) {
|
||||
_pairingCompleted(a[1]);
|
||||
} else if (a[0] == "Connected" && a.length() > 1) {
|
||||
_connectionCompleted(a[1]);
|
||||
} else if (a[0] == "Connection" && a.length() > 1) {
|
||||
setPairingStatus(PairingConnectionRejected, tr("Connection Rejected"));
|
||||
qCDebug(PairingManagerLog) << "Connection error: " << str;
|
||||
} else {
|
||||
setPairingStatus(PairingRejected, tr("Pairing Rejected"));
|
||||
qCDebug(PairingManagerLog) << "Pairing error: " << str;
|
||||
}
|
||||
_uploadManager->deleteLater();
|
||||
_uploadManager = nullptr;
|
||||
} else {
|
||||
if(++_pairRetryCount > 3) {
|
||||
qCDebug(PairingManagerLog) << "Giving up";
|
||||
setPairingStatus(PairingError, tr("No Response From Vehicle"));
|
||||
_uploadManager->deleteLater();
|
||||
_uploadManager = nullptr;
|
||||
} else {
|
||||
qCDebug(PairingManagerLog) << "Upload error: " + reply->errorString();
|
||||
_startUploadRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_parsePairingJsonFile()
|
||||
{
|
||||
QFile file(_jsonFileName);
|
||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
QString json = file.readAll();
|
||||
file.remove();
|
||||
file.close();
|
||||
|
||||
jsonReceived(json);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::connectToPairedDevice(QString name)
|
||||
{
|
||||
setPairingStatus(PairingConnecting, tr("Connecting to %1").arg(name));
|
||||
QFile file(_pairingCacheFile(name));
|
||||
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
QString json = file.readAll();
|
||||
jsonReceived(json);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::removePairedDevice(QString name)
|
||||
{
|
||||
QFile file(_pairingCacheFile(name));
|
||||
file.remove();
|
||||
_updatePairedDeviceNameList();
|
||||
emit pairedListChanged();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_updatePairedDeviceNameList()
|
||||
{
|
||||
_deviceList.clear();
|
||||
QDirIterator it(_pairingCacheDir().absolutePath(), QDir::Files);
|
||||
while (it.hasNext()) {
|
||||
QFileInfo fileInfo(it.next());
|
||||
_deviceList.append(fileInfo.fileName());
|
||||
qCDebug(PairingManagerLog) << "Listing: " << fileInfo.fileName();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString
|
||||
PairingManager::_assumeMicrohardPairingJson()
|
||||
{
|
||||
QJsonDocument json;
|
||||
QJsonObject jsonObject;
|
||||
|
||||
jsonObject.insert("LT", "MH");
|
||||
jsonObject.insert("IP", "192.168.168.10");
|
||||
jsonObject.insert("AIP", _toolbox->microhardManager()->remoteIPAddr());
|
||||
jsonObject.insert("CU", _toolbox->microhardManager()->configUserName());
|
||||
jsonObject.insert("CP", _toolbox->microhardManager()->configPassword());
|
||||
jsonObject.insert("EK", _toolbox->microhardManager()->encryptionKey());
|
||||
json.setObject(jsonObject);
|
||||
|
||||
return QString(json.toJson(QJsonDocument::Compact));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_parsePairingJson(QString jsonEnc)
|
||||
{
|
||||
QString json = QString::fromStdString(_aes.decrypt(jsonEnc.toStdString()));
|
||||
if (json == "") {
|
||||
json = jsonEnc;
|
||||
}
|
||||
qCDebug(PairingManagerLog) << "Parsing JSON: " << json;
|
||||
|
||||
_jsonDoc = QJsonDocument::fromJson(json.toUtf8());
|
||||
|
||||
if (_jsonDoc.isNull()) {
|
||||
setPairingStatus(PairingError, tr("Invalid Pairing File"));
|
||||
qCDebug(PairingManagerLog) << "Failed to create Pairing JSON doc.";
|
||||
return;
|
||||
}
|
||||
if (!_jsonDoc.isObject()) {
|
||||
setPairingStatus(PairingError, tr("Error Parsing Pairing File"));
|
||||
qCDebug(PairingManagerLog) << "Pairing JSON is not an object.";
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject jsonObj = _jsonDoc.object();
|
||||
|
||||
if (jsonObj.isEmpty()) {
|
||||
setPairingStatus(PairingError, tr("Error Parsing Pairing File"));
|
||||
qCDebug(PairingManagerLog) << "Pairing JSON object is empty.";
|
||||
return;
|
||||
}
|
||||
|
||||
_remotePairingMap = jsonObj.toVariantMap();
|
||||
QString linkType = _remotePairingMap["LT"].toString();
|
||||
QString pport = _remotePairingMap["PP"].toString();
|
||||
if (pport.length()==0) {
|
||||
pport = "29351";
|
||||
}
|
||||
|
||||
if (linkType.length()==0) {
|
||||
setPairingStatus(PairingError, tr("Error Parsing Pairing File"));
|
||||
qCDebug(PairingManagerLog) << "Pairing JSON is malformed.";
|
||||
return;
|
||||
}
|
||||
|
||||
_toolbox->microhardManager()->switchToPairingEncryptionKey();
|
||||
|
||||
QString pairURL = "http://" + _remotePairingMap["IP"].toString() + ":" + pport;
|
||||
bool connecting = jsonObj.contains("PWD");
|
||||
QJsonDocument jsonDoc;
|
||||
|
||||
if (!connecting) {
|
||||
pairURL += + "/pair";
|
||||
QString pwd = random_string(8);
|
||||
// TODO generate certificates
|
||||
QString cert1 = "";
|
||||
QString cert2 = "";
|
||||
jsonObj.insert("PWD", pwd);
|
||||
jsonObj.insert("CERT1", cert1);
|
||||
jsonObj.insert("CERT2", cert2);
|
||||
_jsonDoc.setObject(jsonObj);
|
||||
if (linkType == "ZT") {
|
||||
jsonDoc = _createZeroTierPairingJson(cert1);
|
||||
} else if (linkType == "MH") {
|
||||
jsonDoc = _createMicrohardPairingJson(pwd, cert1);
|
||||
}
|
||||
} else {
|
||||
pairURL += + "/connect";
|
||||
QString cert2 = _remotePairingMap["CERT2"].toString();
|
||||
if (linkType == "ZT") {
|
||||
jsonDoc = _createZeroTierConnectJson(cert2);
|
||||
} else if (linkType == "MH") {
|
||||
jsonDoc = _createMicrohardConnectJson(cert2);
|
||||
}
|
||||
}
|
||||
|
||||
if (linkType == "ZT") {
|
||||
_toolbox->settingsManager()->appSettings()->enableMicrohard()->setRawValue(false);
|
||||
_toolbox->settingsManager()->appSettings()->enableTaisync()->setRawValue(false);
|
||||
emit startUpload(pairURL, jsonDoc);
|
||||
} else if (linkType == "MH") {
|
||||
_toolbox->settingsManager()->appSettings()->enableMicrohard()->setRawValue(true);
|
||||
_toolbox->settingsManager()->appSettings()->enableTaisync()->setRawValue(false);
|
||||
if (_remotePairingMap.contains("AIP")) {
|
||||
_toolbox->microhardManager()->setRemoteIPAddr(_remotePairingMap["AIP"].toString());
|
||||
}
|
||||
if (_remotePairingMap.contains("CU")) {
|
||||
_toolbox->microhardManager()->setConfigUserName(_remotePairingMap["CU"].toString());
|
||||
}
|
||||
if (_remotePairingMap.contains("CP")) {
|
||||
_toolbox->microhardManager()->setConfigPassword(_remotePairingMap["CP"].toString());
|
||||
}
|
||||
if (_remotePairingMap.contains("EK") && !connecting) {
|
||||
_toolbox->microhardManager()->setEncryptionKey(_remotePairingMap["EK"].toString());
|
||||
}
|
||||
_toolbox->microhardManager()->updateSettings();
|
||||
emit startUpload(pairURL, jsonDoc);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString
|
||||
PairingManager::_getLocalIPInNetwork(QString remoteIP, int num)
|
||||
{
|
||||
QStringList pieces = remoteIP.split(".");
|
||||
QString ipPrefix = "";
|
||||
for (int i = 0; i<num && i<pieces.length(); i++) {
|
||||
ipPrefix += pieces[i] + ".";
|
||||
}
|
||||
|
||||
const QHostAddress &localhost = QHostAddress(QHostAddress::LocalHost);
|
||||
for (const QHostAddress &address: QNetworkInterface::allAddresses()) {
|
||||
if (address.protocol() == QAbstractSocket::IPv4Protocol && address != localhost) {
|
||||
if (address.toString().startsWith(ipPrefix)) {
|
||||
return address.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QDir
|
||||
PairingManager::_pairingCacheDir()
|
||||
{
|
||||
const QString spath(QFileInfo(QSettings().fileName()).dir().absolutePath());
|
||||
QDir dir = spath + QDir::separator() + "PairingCache";
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString
|
||||
PairingManager::_pairingCacheFile(QString uavName)
|
||||
{
|
||||
return _pairingCacheDir().filePath(uavName);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_writeJson(QJsonDocument &jsonDoc, QString fileName)
|
||||
{
|
||||
QString val = jsonDoc.toJson(QJsonDocument::JsonFormat::Compact);
|
||||
qCDebug(PairingManagerLog) << "Write json " << val;
|
||||
QString enc = QString::fromStdString(_aes.encrypt(val.toStdString()));
|
||||
|
||||
QFile file(fileName);
|
||||
file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
|
||||
file.write(enc.toUtf8());
|
||||
file.close();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QJsonDocument
|
||||
PairingManager::_createZeroTierPairingJson(QString cert1)
|
||||
{
|
||||
QString localIP = _getLocalIPInNetwork(_remotePairingMap["IP"].toString(), 2);
|
||||
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("LT", "ZT");
|
||||
jsonObj.insert("IP", localIP);
|
||||
jsonObj.insert("P", 14550);
|
||||
jsonObj.insert("CERT1", cert1);
|
||||
return QJsonDocument(jsonObj);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QJsonDocument
|
||||
PairingManager::_createMicrohardPairingJson(QString pwd, QString cert1)
|
||||
{
|
||||
QString localIP = _getLocalIPInNetwork(_remotePairingMap["IP"].toString(), 3);
|
||||
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("LT", "MH");
|
||||
jsonObj.insert("IP", localIP);
|
||||
jsonObj.insert("P", 14550);
|
||||
jsonObj.insert("PWD", pwd);
|
||||
jsonObj.insert("CERT1", cert1);
|
||||
return QJsonDocument(jsonObj);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QJsonDocument
|
||||
PairingManager::_createZeroTierConnectJson(QString cert2)
|
||||
{
|
||||
QString localIP = _getLocalIPInNetwork(_remotePairingMap["IP"].toString(), 2);
|
||||
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("LT", "ZT");
|
||||
jsonObj.insert("IP", localIP);
|
||||
jsonObj.insert("P", 14550);
|
||||
jsonObj.insert("CERT2", cert2);
|
||||
return QJsonDocument(jsonObj);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QJsonDocument
|
||||
PairingManager::_createMicrohardConnectJson(QString cert2)
|
||||
{
|
||||
QString localIP = _getLocalIPInNetwork(_remotePairingMap["IP"].toString(), 3);
|
||||
|
||||
QJsonObject jsonObj;
|
||||
jsonObj.insert("LT", "MH");
|
||||
jsonObj.insert("IP", localIP);
|
||||
jsonObj.insert("P", 14550);
|
||||
jsonObj.insert("CERT2", cert2);
|
||||
return QJsonDocument(jsonObj);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
QStringList
|
||||
PairingManager::pairingLinkTypeStrings()
|
||||
{
|
||||
//-- Must follow same order as enum LinkType in LinkConfiguration.h
|
||||
static QStringList list;
|
||||
int i = 0;
|
||||
if (!list.size()) {
|
||||
#if defined QGC_ENABLE_QTNFC
|
||||
list += tr("NFC");
|
||||
_nfcIndex = i++;
|
||||
#endif
|
||||
#if defined QGC_GST_MICROHARD_ENABLED
|
||||
list += tr("Microhard");
|
||||
_microhardIndex = i++;
|
||||
#endif
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::_setPairingStatus(PairingStatus status, QString statusStr)
|
||||
{
|
||||
_status = status;
|
||||
_statusString = statusStr;
|
||||
emit pairingStatusChanged();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
QString
|
||||
PairingManager::pairingStatusStr() const
|
||||
{
|
||||
return _statusString;
|
||||
}
|
||||
|
||||
#if QGC_GST_MICROHARD_ENABLED
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::startMicrohardPairing()
|
||||
{
|
||||
stopPairing();
|
||||
_pairRetryCount = 0;
|
||||
setPairingStatus(PairingActive, tr("Pairing..."));
|
||||
_parsePairingJson(_assumeMicrohardPairingJson());
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::stopPairing()
|
||||
{
|
||||
#if defined QGC_ENABLE_QTNFC
|
||||
pairingNFC.stop();
|
||||
#endif
|
||||
_stopUpload();
|
||||
setPairingStatus(PairingIdle, "");
|
||||
}
|
||||
|
||||
#if defined QGC_ENABLE_QTNFC
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingManager::startNFCScan()
|
||||
{
|
||||
stopPairing();
|
||||
setPairingStatus(PairingActive, tr("Pairing..."));
|
||||
pairingNFC.start();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef __android__
|
||||
static const char kJniClassName[] {"org/mavlink/qgroundcontrol/QGCActivity"};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static void jniNFCTagReceived(JNIEnv *envA, jobject thizA, jstring messageA)
|
||||
{
|
||||
Q_UNUSED(thizA);
|
||||
|
||||
const char *stringL = envA->GetStringUTFChars(messageA, nullptr);
|
||||
QString ndef = QString::fromUtf8(stringL);
|
||||
envA->ReleaseStringUTFChars(messageA, stringL);
|
||||
if (envA->ExceptionCheck())
|
||||
envA->ExceptionClear();
|
||||
qCDebug(PairingManagerLog) << "NDEF Tag Received: " << ndef;
|
||||
qgcApp()->toolbox()->pairingManager()->jsonReceived(ndef);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void PairingManager::setNativeMethods(void)
|
||||
{
|
||||
// REGISTER THE C++ FUNCTION WITH JNI
|
||||
JNINativeMethod javaMethods[] {
|
||||
{"nativeNFCTagReceived", "(Ljava/lang/String;)V", reinterpret_cast<void *>(jniNFCTagReceived)}
|
||||
};
|
||||
|
||||
QAndroidJniEnvironment jniEnv;
|
||||
if (jniEnv->ExceptionCheck()) {
|
||||
jniEnv->ExceptionDescribe();
|
||||
jniEnv->ExceptionClear();
|
||||
}
|
||||
|
||||
jclass objectClass = jniEnv->FindClass(kJniClassName);
|
||||
if(!objectClass) {
|
||||
qWarning() << "Couldn't find class:" << kJniClassName;
|
||||
return;
|
||||
}
|
||||
|
||||
jint val = jniEnv->RegisterNatives(objectClass, javaMethods, sizeof(javaMethods) / sizeof(javaMethods[0]));
|
||||
|
||||
if (val < 0) {
|
||||
qWarning() << "Error registering methods: " << val;
|
||||
} else {
|
||||
qCDebug(PairingManagerLog) << "Native Functions Registered";
|
||||
}
|
||||
|
||||
if (jniEnv->ExceptionCheck()) {
|
||||
jniEnv->ExceptionDescribe();
|
||||
jniEnv->ExceptionClear();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
@ -0,0 +1,153 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* (c) 2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
*
|
||||
* QGroundControl is licensed according to the terms in the file
|
||||
* COPYING.md in the root of the source code directory.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QMutex>
|
||||
#include <QNetworkReply>
|
||||
#include <QTimer>
|
||||
#include <QTime>
|
||||
#include <QVariantMap>
|
||||
|
||||
#include "aes.h"
|
||||
#include "QGCToolbox.h"
|
||||
#include "QGCLoggingCategory.h"
|
||||
#include "Fact.h"
|
||||
#if defined QGC_ENABLE_QTNFC
|
||||
#include "QtNFC.h"
|
||||
#endif
|
||||
#ifdef __android__
|
||||
#include <jni.h>
|
||||
#include <QtAndroidExtras/QtAndroidExtras>
|
||||
#include <QtAndroidExtras/QAndroidJniObject>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(PairingManagerLog)
|
||||
|
||||
class AppSettings;
|
||||
class QGCApplication;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class PairingManager : public QGCTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PairingManager (QGCApplication* app, QGCToolbox* toolbox);
|
||||
~PairingManager () override;
|
||||
|
||||
// Override from QGCTool
|
||||
virtual void setToolbox(QGCToolbox *toolbox) override;
|
||||
|
||||
enum PairingStatus {
|
||||
PairingIdle,
|
||||
PairingActive,
|
||||
PairingSuccess,
|
||||
PairingConnecting,
|
||||
PairingConnected,
|
||||
PairingRejected,
|
||||
PairingConnectionRejected,
|
||||
PairingError
|
||||
};
|
||||
|
||||
Q_ENUM(PairingStatus)
|
||||
|
||||
QStringList pairingLinkTypeStrings ();
|
||||
QString pairingStatusStr () const;
|
||||
QStringList pairedDeviceNameList () { return _deviceList; }
|
||||
PairingStatus pairingStatus () { return _status; }
|
||||
QString pairedVehicle () { return _lastPaired; }
|
||||
int nfcIndex () { return _nfcIndex; }
|
||||
int microhardIndex () { return _microhardIndex; }
|
||||
bool firstBoot () { return _firstBoot; }
|
||||
bool errorState () { return _status == PairingRejected || _status == PairingConnectionRejected || _status == PairingError; }
|
||||
void setStatusMessage (PairingStatus status, QString statusStr) { emit setPairingStatus(status, statusStr); }
|
||||
void jsonReceived (QString json) { emit parsePairingJson(json); }
|
||||
void setFirstBoot (bool set) { _firstBoot = set; emit firstBootChanged(); }
|
||||
#ifdef __android__
|
||||
static void setNativeMethods (void);
|
||||
#endif
|
||||
Q_INVOKABLE void connectToPairedDevice (QString name);
|
||||
Q_INVOKABLE void removePairedDevice (QString name);
|
||||
|
||||
#if defined defined QGC_ENABLE_QTNFC
|
||||
Q_INVOKABLE void startNFCScan();
|
||||
#endif
|
||||
#if QGC_GST_MICROHARD_ENABLED
|
||||
Q_INVOKABLE void startMicrohardPairing();
|
||||
#endif
|
||||
Q_INVOKABLE void stopPairing();
|
||||
|
||||
Q_PROPERTY(QString pairingStatusStr READ pairingStatusStr NOTIFY pairingStatusChanged)
|
||||
Q_PROPERTY(PairingStatus pairingStatus READ pairingStatus NOTIFY pairingStatusChanged)
|
||||
Q_PROPERTY(QStringList pairedDeviceNameList READ pairedDeviceNameList NOTIFY pairedListChanged)
|
||||
Q_PROPERTY(QStringList pairingLinkTypeStrings READ pairingLinkTypeStrings CONSTANT)
|
||||
Q_PROPERTY(QString pairedVehicle READ pairedVehicle NOTIFY pairedVehicleChanged)
|
||||
Q_PROPERTY(bool errorState READ errorState NOTIFY pairingStatusChanged)
|
||||
Q_PROPERTY(int nfcIndex READ nfcIndex CONSTANT)
|
||||
Q_PROPERTY(int microhardIndex READ microhardIndex CONSTANT)
|
||||
Q_PROPERTY(bool firstBoot READ firstBoot WRITE setFirstBoot NOTIFY firstBootChanged)
|
||||
|
||||
signals:
|
||||
void startUpload (QString pairURL, QJsonDocument);
|
||||
void closeConnection ();
|
||||
void pairingConfigurationsChanged ();
|
||||
void nameListChanged ();
|
||||
void pairingStatusChanged ();
|
||||
void parsePairingJson (QString json);
|
||||
void setPairingStatus (PairingStatus status, QString pairingStatus);
|
||||
void pairedListChanged ();
|
||||
void pairedVehicleChanged ();
|
||||
void firstBootChanged ();
|
||||
|
||||
private slots:
|
||||
void _startUpload (QString pairURL, QJsonDocument);
|
||||
void _stopUpload ();
|
||||
void _startUploadRequest ();
|
||||
void _parsePairingJson (QString jsonEnc);
|
||||
void _setPairingStatus (PairingStatus status, QString pairingStatus);
|
||||
|
||||
private:
|
||||
QString _statusString;
|
||||
QString _jsonFileName;
|
||||
QString _lastPaired;
|
||||
QVariantMap _remotePairingMap;
|
||||
int _nfcIndex = -1;
|
||||
int _microhardIndex = -1;
|
||||
int _pairRetryCount = 0;
|
||||
PairingStatus _status = PairingIdle;
|
||||
AES _aes;
|
||||
QJsonDocument _jsonDoc{};
|
||||
QMutex _uploadMutex{};
|
||||
QNetworkAccessManager* _uploadManager = nullptr;
|
||||
QString _uploadURL{};
|
||||
QString _uploadData{};
|
||||
bool _firstBoot = true;
|
||||
QStringList _deviceList;
|
||||
|
||||
void _parsePairingJsonFile ();
|
||||
QJsonDocument _createZeroTierConnectJson (QString cert2);
|
||||
QJsonDocument _createMicrohardConnectJson (QString cert2);
|
||||
QJsonDocument _createZeroTierPairingJson (QString cert1);
|
||||
QJsonDocument _createMicrohardPairingJson (QString pwd, QString cert1);
|
||||
QString _assumeMicrohardPairingJson ();
|
||||
void _writeJson (QJsonDocument &jsonDoc, QString fileName);
|
||||
QString _getLocalIPInNetwork (QString remoteIP, int num);
|
||||
void _uploadFinished ();
|
||||
void _uploadError (QNetworkReply::NetworkError code);
|
||||
void _pairingCompleted (QString name);
|
||||
void _connectionCompleted (QString name);
|
||||
QDir _pairingCacheDir ();
|
||||
QString _pairingCacheFile (QString uavName);
|
||||
void _updatePairedDeviceNameList ();
|
||||
|
||||
#if defined QGC_ENABLE_QTNFC
|
||||
PairingNFC pairingNFC;
|
||||
#endif
|
||||
};
|
@ -0,0 +1,135 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* (c) 2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
*
|
||||
* QGroundControl is licensed according to the terms in the file
|
||||
* COPYING.md in the root of the source code directory.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "PairingManager.h"
|
||||
#include "QtNFC.h"
|
||||
#include "QGCApplication.h"
|
||||
#include <QSoundEffect>
|
||||
|
||||
QGC_LOGGING_CATEGORY(PairingNFCLog, "PairingNFCLog")
|
||||
|
||||
#include <QNdefNfcTextRecord>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
PairingNFC::PairingNFC()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::start()
|
||||
{
|
||||
if (manager != nullptr) {
|
||||
return;
|
||||
}
|
||||
qgcApp()->toolbox()->pairingManager()->setStatusMessage(tr("Waiting for NFC connection"));
|
||||
qCDebug(PairingNFCLog) << "Waiting for NFC connection";
|
||||
|
||||
manager = new QNearFieldManager(this);
|
||||
if (!manager->isAvailable()) {
|
||||
qWarning() << "NFC not available";
|
||||
delete manager;
|
||||
manager = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
QNdefFilter filter;
|
||||
filter.setOrderMatch(false);
|
||||
filter.appendRecord<QNdefNfcTextRecord>(1, UINT_MAX);
|
||||
// type parameter cannot specify substring so filter for "image/" below
|
||||
filter.appendRecord(QNdefRecord::Mime, QByteArray(), 0, 1);
|
||||
|
||||
int result = manager->registerNdefMessageHandler(filter, this, SLOT(handleMessage(QNdefMessage, QNearFieldTarget*)));
|
||||
|
||||
if (result < 0)
|
||||
qWarning() << "Platform does not support NDEF message handler registration";
|
||||
|
||||
manager->startTargetDetection();
|
||||
connect(manager, &QNearFieldManager::targetDetected, this, &PairingNFC::targetDetected);
|
||||
connect(manager, &QNearFieldManager::targetLost, this, &PairingNFC::targetLost);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::stop()
|
||||
{
|
||||
if (manager != nullptr) {
|
||||
qgcApp()->toolbox()->pairingManager()->setStatusMessage("");
|
||||
qCDebug(PairingNFCLog) << "NFC: Stop";
|
||||
manager->stopTargetDetection();
|
||||
delete manager;
|
||||
manager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::targetDetected(QNearFieldTarget *target)
|
||||
{
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
qgcApp()->toolbox()->pairingManager()->setStatusMessage(tr("Device detected"));
|
||||
qCDebug(PairingNFCLog) << "NFC: Device detected";
|
||||
connect(target, &QNearFieldTarget::ndefMessageRead, this, &PairingNFC::handlePolledNdefMessage);
|
||||
connect(target, SIGNAL(error(QNearFieldTarget::Error,QNearFieldTarget::RequestId)),
|
||||
this, SLOT(targetError(QNearFieldTarget::Error,QNearFieldTarget::RequestId)));
|
||||
connect(target, &QNearFieldTarget::requestCompleted, this, &PairingNFC::handleRequestCompleted);
|
||||
|
||||
manager->setTargetAccessModes(QNearFieldManager::NdefReadTargetAccess);
|
||||
QNearFieldTarget::RequestId id = target->readNdefMessages();
|
||||
if (target->waitForRequestCompleted(id)) {
|
||||
qCDebug(PairingNFCLog) << "requestCompleted ";
|
||||
QVariant res = target->requestResponse(id);
|
||||
qCDebug(PairingNFCLog) << "Response: " << res.toString();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::handleRequestCompleted(const QNearFieldTarget::RequestId& id)
|
||||
{
|
||||
Q_UNUSED(id);
|
||||
qCDebug(PairingNFCLog) << "handleRequestCompleted ";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::targetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId& id)
|
||||
{
|
||||
Q_UNUSED(id);
|
||||
qCDebug(PairingNFCLog) << "Error: " << error;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::targetLost(QNearFieldTarget *target)
|
||||
{
|
||||
qgcApp()->toolbox()->pairingManager()->setStatusMessage(tr("Device removed"));
|
||||
qCDebug(PairingNFCLog) << "NFC: Device removed";
|
||||
if (target) {
|
||||
target->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
PairingNFC::handlePolledNdefMessage(QNdefMessage message)
|
||||
{
|
||||
qCDebug(PairingNFCLog) << "NFC: Handle NDEF message";
|
||||
// QNearFieldTarget *target = qobject_cast<QNearFieldTarget *>(sender());
|
||||
for (const QNdefRecord &record : message) {
|
||||
if (record.isRecordType<QNdefNfcTextRecord>()) {
|
||||
QNdefNfcTextRecord textRecord(record);
|
||||
qgcApp()->toolbox()->pairingManager()->jsonReceived(textRecord.text());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* (c) 2019 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||
*
|
||||
* QGroundControl is licensed according to the terms in the file
|
||||
* COPYING.md in the root of the source code directory.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QNdefMessage>
|
||||
#include <QNearFieldManager>
|
||||
#include <QNearFieldTarget>
|
||||
|
||||
#include "QGCLoggingCategory.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(PairingNFCLog)
|
||||
|
||||
class PairingNFC : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PairingNFC();
|
||||
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void parsePairingJson(QString json);
|
||||
|
||||
public slots:
|
||||
void targetDetected(QNearFieldTarget *target);
|
||||
void targetLost(QNearFieldTarget *target);
|
||||
void handlePolledNdefMessage(QNdefMessage message);
|
||||
void targetError(QNearFieldTarget::Error error, const QNearFieldTarget::RequestId& id);
|
||||
void handleRequestCompleted(const QNearFieldTarget::RequestId& id);
|
||||
|
||||
private:
|
||||
bool _exitThread = false; ///< true: signal thread to exit
|
||||
QNearFieldManager *manager = nullptr;
|
||||
};
|
@ -0,0 +1,154 @@
|
||||
#include "aes.h"
|
||||
|
||||
#include <memory>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <zlib.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
AES::AES(std::string password, unsigned long long salt)
|
||||
{
|
||||
int nrounds = 5;
|
||||
unsigned char key[32], iv[32];
|
||||
|
||||
/*
|
||||
* Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material.
|
||||
* nrounds is the number of times the we hash the material. More rounds are more secure but
|
||||
* slower.
|
||||
*/
|
||||
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(),
|
||||
reinterpret_cast<const unsigned char*>(&salt),
|
||||
reinterpret_cast<const unsigned char*>(password.c_str()),
|
||||
static_cast<int>(password.length()),
|
||||
nrounds, key, iv);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
encCipherContext = EVP_CIPHER_CTX_new();
|
||||
decCipherContext = EVP_CIPHER_CTX_new();
|
||||
|
||||
EVP_CIPHER_CTX_init(encCipherContext);
|
||||
EVP_EncryptInit_ex(encCipherContext, EVP_aes_256_cbc(), nullptr, key, iv);
|
||||
EVP_CIPHER_CTX_init(decCipherContext);
|
||||
EVP_DecryptInit_ex(decCipherContext, EVP_aes_256_cbc(), nullptr, key, iv);
|
||||
#else
|
||||
EVP_CIPHER_CTX_init(&encCipherContext);
|
||||
EVP_EncryptInit_ex(&encCipherContext, EVP_aes_256_cbc(), nullptr, key, iv);
|
||||
EVP_CIPHER_CTX_init(&decCipherContext);
|
||||
EVP_DecryptInit_ex(&decCipherContext, EVP_aes_256_cbc(), nullptr, key, iv);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
AES::~AES()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
EVP_CIPHER_CTX_free(encCipherContext);
|
||||
EVP_CIPHER_CTX_free(decCipherContext);
|
||||
#else
|
||||
EVP_CIPHER_CTX_cleanup(&encCipherContext);
|
||||
EVP_CIPHER_CTX_cleanup(&decCipherContext);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string
|
||||
AES::encrypt(std::string plainText)
|
||||
{
|
||||
unsigned long sourceLen = static_cast<unsigned long>(plainText.length() + 1);
|
||||
unsigned long destLen = sourceLen * 2;
|
||||
unsigned char* compressed = new unsigned char[destLen];
|
||||
int err = compress2(compressed, &destLen,
|
||||
reinterpret_cast<const unsigned char *>(plainText.c_str()),
|
||||
sourceLen, 9);
|
||||
if (err != Z_OK) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int pLen = static_cast<int>(destLen);
|
||||
int cLen = pLen + AES_BLOCK_SIZE;
|
||||
int fLen = 0;
|
||||
unsigned char* cipherText = new unsigned char[cLen];
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
EVP_EncryptInit_ex(encCipherContext, nullptr, nullptr, nullptr, nullptr);
|
||||
EVP_EncryptUpdate(encCipherContext, cipherText, &cLen, compressed, pLen);
|
||||
EVP_EncryptFinal_ex(encCipherContext, cipherText + cLen, &fLen);
|
||||
#else
|
||||
EVP_EncryptInit_ex(&encCipherContext, nullptr, nullptr, nullptr, nullptr);
|
||||
EVP_EncryptUpdate(&encCipherContext, cipherText, &cLen, compressed, pLen);
|
||||
EVP_EncryptFinal_ex(&encCipherContext, cipherText + cLen, &fLen);
|
||||
#endif
|
||||
|
||||
std::vector<unsigned char> data(cipherText, cipherText + cLen + fLen);
|
||||
std::string res = base64Encode(data);
|
||||
delete[] cipherText;
|
||||
delete[] compressed;
|
||||
|
||||
return res;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string
|
||||
AES::decrypt(std::string cipherText)
|
||||
{
|
||||
int fLen = 0;
|
||||
std::vector<unsigned char> text = base64Decode(cipherText);
|
||||
int pLen = static_cast<int>(text.size());
|
||||
unsigned char* plainText = new unsigned char[pLen];
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
EVP_DecryptInit_ex(decCipherContext, nullptr, nullptr, nullptr, nullptr);
|
||||
EVP_DecryptUpdate(decCipherContext, plainText, &pLen, text.data(), pLen);
|
||||
EVP_DecryptFinal_ex(decCipherContext, plainText + pLen, &fLen);
|
||||
#else
|
||||
EVP_DecryptInit_ex(&decCipherContext, nullptr, nullptr, nullptr, nullptr);
|
||||
EVP_DecryptUpdate(&decCipherContext, plainText, &pLen, text.data(), pLen);
|
||||
EVP_DecryptFinal_ex(&decCipherContext, plainText + pLen, &fLen);
|
||||
#endif
|
||||
|
||||
unsigned long destLen = static_cast<unsigned long>((pLen + fLen) * 2);
|
||||
unsigned char* uncompressed = new unsigned char[destLen];
|
||||
int err = uncompress(uncompressed, &destLen, plainText, static_cast<unsigned long>(pLen + fLen));
|
||||
if (err != Z_OK) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string res(reinterpret_cast<char*>(uncompressed));
|
||||
delete[] uncompressed;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
struct BIOFreeAll { void operator()(BIO* p) { BIO_free_all(p); } };
|
||||
|
||||
std::string
|
||||
AES::base64Encode(const std::vector<unsigned char>& binary)
|
||||
{
|
||||
std::unique_ptr<BIO, BIOFreeAll> b64(BIO_new(BIO_f_base64()));
|
||||
BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO* sink = BIO_new(BIO_s_mem());
|
||||
BIO_push(b64.get(), sink);
|
||||
BIO_write(b64.get(), binary.data(), static_cast<int>(binary.size()));
|
||||
BIO_ctrl(b64.get(), BIO_CTRL_FLUSH, 0, nullptr);
|
||||
const char* encoded;
|
||||
const unsigned long len = static_cast<unsigned long>(BIO_ctrl(sink, BIO_CTRL_INFO, 0, &encoded));
|
||||
|
||||
return std::string(encoded, len);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::vector<unsigned char>
|
||||
AES::base64Decode(std::string encoded)
|
||||
{
|
||||
std::unique_ptr<BIO, BIOFreeAll> b64(BIO_new(BIO_f_base64()));
|
||||
BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO* source = BIO_new_mem_buf(encoded.c_str(), -1); // read-only source
|
||||
BIO_push(b64.get(), source);
|
||||
const unsigned long maxlen = encoded.length() / 4 * 3 + 1;
|
||||
std::vector<unsigned char> decoded(maxlen);
|
||||
const unsigned long len = static_cast<unsigned long>(BIO_read(b64.get(), decoded.data(), static_cast<int>(maxlen)));
|
||||
decoded.resize(len);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
@ -0,0 +1,35 @@
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
class AES
|
||||
{
|
||||
public:
|
||||
AES(std::string password, unsigned long long salt);
|
||||
|
||||
~AES();
|
||||
|
||||
std::string encrypt(std::string plainText);
|
||||
|
||||
std::string decrypt(std::string cipherText);
|
||||
|
||||
private:
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
|
||||
EVP_CIPHER_CTX *encCipherContext = nullptr;
|
||||
EVP_CIPHER_CTX *decCipherContext = nullptr;
|
||||
#else
|
||||
EVP_CIPHER_CTX encCipherContext;
|
||||
EVP_CIPHER_CTX decCipherContext;
|
||||
#endif
|
||||
|
||||
std::string base64Encode(const std::vector<unsigned char>& binary);
|
||||
|
||||
std::vector<unsigned char> base64Decode(std::string encoded);
|
||||
};
|
||||
|
||||
#endif // AES_H
|
Loading…
Reference in new issue