mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-12-13 04:42:27 +00:00
pairing stuff
This commit is contained in:
parent
3ee554cd91
commit
a38bef6bc4
7 changed files with 259 additions and 10 deletions
113
identitymanager.cpp
Normal file
113
identitymanager.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "identitymanager.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
|
||||
IdentityManager::IdentityManager(QDir directory)
|
||||
: m_RootDirectory(directory),
|
||||
m_CachedPrivateKey(nullptr),
|
||||
m_CachedPemCert(nullptr),
|
||||
m_CachedUniqueId(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
QString
|
||||
IdentityManager::getUniqueId()
|
||||
{
|
||||
if (m_CachedUniqueId == nullptr)
|
||||
{
|
||||
QFile uniqueIdFile(m_RootDirectory.filePath("uniqueid"));
|
||||
if (uniqueIdFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
m_CachedUniqueId = QTextStream(uniqueIdFile.open(QIODevice::ReadOnly)).readAll();
|
||||
qDebug() << "Loaded cached unique ID: " << m_CachedUniqueId;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
int n = qrand() % 16;
|
||||
m_CachedUniqueId.append(QString::number(n, 16));
|
||||
}
|
||||
|
||||
qDebug() << "Generated new unique ID: " << m_CachedUniqueId;
|
||||
|
||||
uniqueIdFile.open(QIODevice::ReadWrite);
|
||||
QTextStream(uniqueIdFile) << m_CachedUniqueId;
|
||||
}
|
||||
}
|
||||
|
||||
return m_CachedUniqueId;
|
||||
}
|
||||
|
||||
void
|
||||
IdentityManager::loadKeyPair()
|
||||
{
|
||||
if (m_CachedPemCert != nullptr && m_CachedPrivateKey != nullptr)
|
||||
{
|
||||
// Already have cached data
|
||||
return;
|
||||
}
|
||||
|
||||
QFile certificateFile(m_RootDirectory.filePath("cert"));
|
||||
QFile privateKeyFile(m_RootDirectory.filePath("key"));
|
||||
|
||||
if (certificateFile.open(QIODevice::ReadOnly) && privateKeyFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
// Not cached yet, but it's on disk
|
||||
m_CachedPemCert = certificateFile.readAll();
|
||||
m_CachedPrivateKey = privateKeyFile.readAll();
|
||||
|
||||
qDebug() << "Loaded cached identity credentials from disk";
|
||||
return;
|
||||
}
|
||||
|
||||
X509* cert = X509_new();
|
||||
if (cert == nullptr)
|
||||
{
|
||||
throw new std::bad_alloc();
|
||||
}
|
||||
|
||||
EVP_PKEY* pk = EVP_PKEY_new();
|
||||
if (pk == nullptr)
|
||||
{
|
||||
X509_free(cert);
|
||||
throw new std::bad_alloc();
|
||||
}
|
||||
|
||||
EVP_PKEY_assign_RSA(pk, RSA_generate_key(2048, RSA_F4, nullptr, nullptr));
|
||||
|
||||
X509_set_version(cert, 2);
|
||||
X509_gmtime_adj(X509_get_notBefore(cert), 0);
|
||||
X509_gmtime_adj(X509_get0_notAfter(cert), 60 * 60 * 24 * 365 * 20); // 20 yrs
|
||||
X509_set_pubkey(cert, pk);
|
||||
|
||||
X509_NAME* name = X509_get_subject_name(cert);
|
||||
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast<unsigned char *>("NVIDIA GameStream Client"), -1, -1, 0);
|
||||
X509_set_issuer_name(x, name);
|
||||
|
||||
privateKeyFile.open(QIODevice::ReadWrite);
|
||||
PEM_write_PrivateKey(privateKeyFile.handle(), pk, nullptr, nullptr, 0, nullptr, nullptr);
|
||||
|
||||
certificateFile.open(QIODevice::ReadWrite);
|
||||
PEM_write_X509(certificateFile.handle(), cert);
|
||||
|
||||
qDebug() << "Wrote new identity credentials to disk";
|
||||
}
|
||||
|
||||
QByteArray
|
||||
IdentityManager::getCertificate()
|
||||
{
|
||||
loadKeyPair();
|
||||
return m_CachedPemCert;
|
||||
}
|
||||
|
||||
QByteArray
|
||||
IdentityManager::getPrivateKey()
|
||||
{
|
||||
loadKeyPair();
|
||||
return m_CachedPrivateKey;
|
||||
}
|
15
identitymanager.h
Normal file
15
identitymanager.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
class IdentityManager
|
||||
{
|
||||
public:
|
||||
IdentityManager(QDir directory);
|
||||
|
||||
private:
|
||||
QDir m_RootDirectory;
|
||||
|
||||
QString m_CachedUniqueId;
|
||||
QByteArray m_CachedPemCert;
|
||||
QByteArray m_CachedPrivateKey;
|
||||
};
|
|
@ -20,17 +20,25 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
|||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
nvhttp.cpp
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
nvhttp.cpp \
|
||||
nvpairingmanager.cpp \
|
||||
identitymanager.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
nvhttp.h
|
||||
mainwindow.h \
|
||||
nvhttp.h \
|
||||
nvpairingmanager.h \
|
||||
identitymanager.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
mainwindow.ui
|
||||
|
||||
OPENSSL_LIBS='-L/usr/lib -lssl -lcrypto'
|
||||
|
||||
QMAKE_CXXFLAGS += -openssl-linked
|
||||
|
|
22
nvhttp.cpp
22
nvhttp.cpp
|
@ -58,6 +58,19 @@ NvHTTP::getComputerInfo()
|
|||
return computer;
|
||||
}
|
||||
|
||||
QVector<int>
|
||||
NvHTTP::getServerVersionQuad(QString serverInfo)
|
||||
{
|
||||
QString quad = getXmlString(serverInfo, "appversion");
|
||||
QStringList parts = quad.split(".");
|
||||
QVector<int> ret;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
ret.append(parts.at(i).toInt());
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
NvHTTP::getCurrentGame(QString serverInfo)
|
||||
{
|
||||
|
@ -65,10 +78,12 @@ NvHTTP::getCurrentGame(QString serverInfo)
|
|||
// has the semantics that its name would indicate. To contain the effects of this change as much
|
||||
// as possible, we'll force the current game to zero if the server isn't in a streaming session.
|
||||
QString serverState = getXmlString(serverInfo, "state");
|
||||
if (serverState != nullptr && serverState.endsWith("_SERVER_BUSY")) {
|
||||
if (serverState != nullptr && serverState.endsWith("_SERVER_BUSY"))
|
||||
{
|
||||
return getXmlString(serverInfo, "currentgame").toInt();
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -201,8 +216,9 @@ NvHTTP::openConnection(QUrl baseUrl,
|
|||
if (reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
qDebug() << command << " request for failed with error " << reply->error();
|
||||
GfeHttpResponseException* exception = new GfeHttpResponseException(reply->error(), reply->errorString());
|
||||
delete reply;
|
||||
throw new GfeHttpResponseException(reply->error(), reply->errorString());
|
||||
throw exception;
|
||||
}
|
||||
|
||||
return reply;
|
||||
|
|
3
nvhttp.h
3
nvhttp.h
|
@ -96,6 +96,9 @@ private:
|
|||
QString arguments,
|
||||
bool enableTimeout);
|
||||
|
||||
QVector<int>
|
||||
getServerVersionQuad(QString serverInfo);
|
||||
|
||||
QString m_Address;
|
||||
QUrl m_BaseUrlHttp;
|
||||
QUrl m_BaseUrlHttps;
|
||||
|
|
67
nvpairingmanager.cpp
Normal file
67
nvpairingmanager.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "nvpairingmanager.h"
|
||||
|
||||
#include <QRandomGenerator>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
|
||||
NvPairingManager::NvPairingManager(QString address) :
|
||||
m_Http(address)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QString
|
||||
NvPairingManager::generatePinString()
|
||||
{
|
||||
return QString::number(QRandomGenerator::global()->bounded(10000));
|
||||
}
|
||||
|
||||
QByteArray
|
||||
NvPairingManager::generateRandomBytes(int length)
|
||||
{
|
||||
QByteArray array(length);
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
array.data()[i] = static_cast<char>(QRandomGenerator::global()->bounded(256));
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
QByteArray
|
||||
NvPairingManager::saltPin(QByteArray salt, QString pin)
|
||||
{
|
||||
return QByteArray().append(salt).append(pin.toStdString().c_str());
|
||||
}
|
||||
|
||||
NvPairingManager::PairState
|
||||
NvPairingManager::pair(QString serverInfo, QString pin)
|
||||
{
|
||||
int serverMajorVersion = m_Http.getServerVersionQuad(serverInfo).at(0);
|
||||
qDebug() << "Pairing with server generation: " << serverMajorVersion;
|
||||
|
||||
QCryptographicHash::Algorithm hashAlgo;
|
||||
if (serverMajorVersion >= 7)
|
||||
{
|
||||
// Gen 7+ uses SHA-256 hashing
|
||||
hashAlgo = QCryptographicHash::Sha256;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prior to Gen 7 uses SHA-1 hashing
|
||||
hashAlgo = QCryptographicHash::Sha1;
|
||||
}
|
||||
|
||||
QByteArray salt = generateRandomBytes(16);
|
||||
QByteArray saltedPin = saltPin(salt, pin);
|
||||
|
||||
AES_KEY encKey, decKey;
|
||||
AES_set_decrypt_key(QCryptographicHash::hash(saltedPin, hashAlgo).data(), 128, &decKey);
|
||||
AES_set_encrypt_key(QCryptographicHash::hash(saltedPin, hashAlgo).data(), 128, &encKey);
|
||||
|
||||
QString getCert = m_Http.openConnectionToString(m_Http.m_BaseUrlHttp,
|
||||
"pair",
|
||||
"&devicename=roth&updateState=1&phrase=getservercert&salt=" +
|
||||
salt.toHex() + "&clientcert=" + )
|
||||
}
|
27
nvpairingmanager.h
Normal file
27
nvpairingmanager.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <nvhttp.h>
|
||||
|
||||
class NvPairingManager
|
||||
{
|
||||
public:
|
||||
enum PairState
|
||||
{
|
||||
NOT_PAIRED,
|
||||
PAIRED,
|
||||
PIN_WRONG,
|
||||
FAILED,
|
||||
ALREADY_IN_PROGRESS
|
||||
};
|
||||
|
||||
NvPairingManager(QString address);
|
||||
|
||||
QString
|
||||
generatePinString();
|
||||
|
||||
PairState
|
||||
pair(QString serverInfo, QString pin);
|
||||
|
||||
private:
|
||||
NvHTTP m_Http;
|
||||
};
|
Loading…
Reference in a new issue