mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 15:26:09 +00:00
pairing works
This commit is contained in:
parent
af607bd8a2
commit
a3ef66981c
13
nvhttp.cpp
13
nvhttp.cpp
@ -155,6 +155,19 @@ NvHTTP::verifyResponseStatus(QString xml)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray
|
||||||
|
NvHTTP::getXmlStringFromHex(QString xml,
|
||||||
|
QString tagName)
|
||||||
|
{
|
||||||
|
QString str = getXmlString(xml, tagName);
|
||||||
|
if (str == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QByteArray::fromHex(str.toLatin1());
|
||||||
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
NvHTTP::getXmlString(QString xml,
|
NvHTTP::getXmlString(QString xml,
|
||||||
QString tagName)
|
QString tagName)
|
||||||
|
4
nvhttp.h
4
nvhttp.h
@ -85,6 +85,10 @@ public:
|
|||||||
getXmlString(QString xml,
|
getXmlString(QString xml,
|
||||||
QString tagName);
|
QString tagName);
|
||||||
|
|
||||||
|
QByteArray
|
||||||
|
getXmlStringFromHex(QString xml,
|
||||||
|
QString tagName);
|
||||||
|
|
||||||
QString
|
QString
|
||||||
openConnectionToString(QUrl baseUrl,
|
openConnectionToString(QUrl baseUrl,
|
||||||
QString command,
|
QString command,
|
||||||
|
@ -46,7 +46,7 @@ NvPairingManager::~NvPairingManager()
|
|||||||
QString
|
QString
|
||||||
NvPairingManager::generatePinString()
|
NvPairingManager::generatePinString()
|
||||||
{
|
{
|
||||||
return QString::number(QRandomGenerator::global()->bounded(10000));
|
return QString::asprintf("%04d", QRandomGenerator::global()->bounded(10000));
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray
|
QByteArray
|
||||||
@ -87,10 +87,35 @@ NvPairingManager::decrypt(QByteArray ciphertext, AES_KEY* key)
|
|||||||
return plaintext;
|
return plaintext;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
QByteArray
|
||||||
NvPairingManager::verifySignature(QByteArray data, QByteArray signature)
|
NvPairingManager::getSignatureFromPemCert(QByteArray certificate)
|
||||||
{
|
{
|
||||||
EVP_PKEY* pubKey = X509_get_pubkey(m_Cert);
|
BIO* bio = BIO_new_mem_buf(certificate.data(), -1);
|
||||||
|
THROW_BAD_ALLOC_IF_NULL(bio);
|
||||||
|
|
||||||
|
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||||||
|
BIO_free_all(bio);
|
||||||
|
|
||||||
|
const ASN1_BIT_STRING *asnSignature;
|
||||||
|
X509_get0_signature(&asnSignature, NULL, cert);
|
||||||
|
|
||||||
|
QByteArray signature(reinterpret_cast<char*>(asnSignature->data), asnSignature->length);
|
||||||
|
|
||||||
|
X509_free(cert);
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
NvPairingManager::verifySignature(QByteArray data, QByteArray signature, QByteArray serverCertificate)
|
||||||
|
{
|
||||||
|
BIO* bio = BIO_new_mem_buf(serverCertificate.data(), -1);
|
||||||
|
THROW_BAD_ALLOC_IF_NULL(bio);
|
||||||
|
|
||||||
|
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||||||
|
BIO_free_all(bio);
|
||||||
|
|
||||||
|
EVP_PKEY* pubKey = X509_get_pubkey(cert);
|
||||||
THROW_BAD_ALLOC_IF_NULL(pubKey);
|
THROW_BAD_ALLOC_IF_NULL(pubKey);
|
||||||
|
|
||||||
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
|
EVP_MD_CTX* mdctx = EVP_MD_CTX_create();
|
||||||
@ -102,6 +127,7 @@ NvPairingManager::verifySignature(QByteArray data, QByteArray signature)
|
|||||||
|
|
||||||
EVP_PKEY_free(pubKey);
|
EVP_PKEY_free(pubKey);
|
||||||
EVP_MD_CTX_destroy(mdctx);
|
EVP_MD_CTX_destroy(mdctx);
|
||||||
|
X509_free(cert);
|
||||||
|
|
||||||
return result > 0;
|
return result > 0;
|
||||||
}
|
}
|
||||||
@ -176,7 +202,16 @@ NvPairingManager::pair(QString serverInfo, QString pin)
|
|||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray encryptedChallenge = encrypt(generateRandomBytes(16), &encKey);
|
QByteArray serverCert = m_Http.getXmlStringFromHex(getCert, "plaincert");
|
||||||
|
if (serverCert == nullptr)
|
||||||
|
{
|
||||||
|
qDebug() << "Server likely already pairing";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
|
return PairState::ALREADY_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray randomChallenge = generateRandomBytes(16);
|
||||||
|
QByteArray encryptedChallenge = encrypt(randomChallenge, &encKey);
|
||||||
QString challengeXml = m_Http.openConnectionToString(m_Http.m_BaseUrlHttp,
|
QString challengeXml = m_Http.openConnectionToString(m_Http.m_BaseUrlHttp,
|
||||||
"pair",
|
"pair",
|
||||||
"devicename=roth&updateState=1&clientchallenge=" +
|
"devicename=roth&updateState=1&clientchallenge=" +
|
||||||
@ -186,20 +221,20 @@ NvPairingManager::pair(QString serverInfo, QString pin)
|
|||||||
if (m_Http.getXmlString(challengeXml, "paired") != "1")
|
if (m_Http.getXmlString(challengeXml, "paired") != "1")
|
||||||
{
|
{
|
||||||
qDebug() << "Failed pairing at stage #2";
|
qDebug() << "Failed pairing at stage #2";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray challengeResponseData = decrypt(
|
QByteArray challengeResponseData = decrypt(m_Http.getXmlStringFromHex(challengeXml, "challengeresponse"), &decKey);
|
||||||
QByteArray::fromHex(m_Http.getXmlString(challengeXml, "challengeresponse").toLatin1()),
|
|
||||||
&decKey);
|
|
||||||
QByteArray clientSecretData = generateRandomBytes(16);
|
QByteArray clientSecretData = generateRandomBytes(16);
|
||||||
QByteArray challengeResponse;
|
QByteArray challengeResponse;
|
||||||
|
QByteArray serverResponse(challengeResponseData.data(), hashLength);
|
||||||
|
|
||||||
const ASN1_BIT_STRING *asnSignature;
|
const ASN1_BIT_STRING *asnSignature;
|
||||||
X509_get0_signature(&asnSignature, NULL, m_Cert);
|
X509_get0_signature(&asnSignature, NULL, m_Cert);
|
||||||
|
|
||||||
challengeResponse.append(challengeResponseData.data() + hashLength, 16);
|
challengeResponse.append(challengeResponseData.data() + hashLength, 16);
|
||||||
challengeResponse.append(reinterpret_cast<char*>(asnSignature->data), 256);
|
challengeResponse.append(reinterpret_cast<char*>(asnSignature->data), asnSignature->length);
|
||||||
challengeResponse.append(clientSecretData);
|
challengeResponse.append(clientSecretData);
|
||||||
|
|
||||||
QByteArray encryptedChallengeResponseHash = encrypt(QCryptographicHash::hash(challengeResponse, hashAlgo), &encKey);
|
QByteArray encryptedChallengeResponseHash = encrypt(QCryptographicHash::hash(challengeResponse, hashAlgo), &encKey);
|
||||||
@ -212,19 +247,34 @@ NvPairingManager::pair(QString serverInfo, QString pin)
|
|||||||
if (m_Http.getXmlString(respXml, "paired") != "1")
|
if (m_Http.getXmlString(respXml, "paired") != "1")
|
||||||
{
|
{
|
||||||
qDebug() << "Failed pairing at stage #3";
|
qDebug() << "Failed pairing at stage #3";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray pairingSecret =
|
QByteArray pairingSecret = m_Http.getXmlStringFromHex(respXml, "pairingsecret");
|
||||||
QByteArray::fromHex(m_Http.getXmlString(challengeXml, "pairingsecret").toLatin1());
|
QByteArray serverSecret = QByteArray(pairingSecret.data(), 16);
|
||||||
|
QByteArray serverSignature = QByteArray(&pairingSecret.data()[16], 256);
|
||||||
|
|
||||||
if (!verifySignature(QByteArray(pairingSecret.data(), 16),
|
if (!verifySignature(serverSecret,
|
||||||
QByteArray(&pairingSecret.data()[16], 256)))
|
serverSignature,
|
||||||
|
serverCert))
|
||||||
{
|
{
|
||||||
qDebug() << "MITM detected";
|
qDebug() << "MITM detected";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray expectedResponseData;
|
||||||
|
expectedResponseData.append(randomChallenge);
|
||||||
|
expectedResponseData.append(getSignatureFromPemCert(serverCert));
|
||||||
|
expectedResponseData.append(serverSecret);
|
||||||
|
if (QCryptographicHash::hash(expectedResponseData, hashAlgo) != serverResponse)
|
||||||
|
{
|
||||||
|
qDebug() << "Incorrect PIN";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
|
return PairState::PIN_WRONG;
|
||||||
|
}
|
||||||
|
|
||||||
QByteArray clientPairingSecret;
|
QByteArray clientPairingSecret;
|
||||||
clientPairingSecret.append(clientSecretData);
|
clientPairingSecret.append(clientSecretData);
|
||||||
clientPairingSecret.append(signMessage(clientSecretData));
|
clientPairingSecret.append(signMessage(clientSecretData));
|
||||||
@ -238,6 +288,7 @@ NvPairingManager::pair(QString serverInfo, QString pin)
|
|||||||
if (m_Http.getXmlString(secretRespXml, "paired") != "1")
|
if (m_Http.getXmlString(secretRespXml, "paired") != "1")
|
||||||
{
|
{
|
||||||
qDebug() << "Failed pairing at stage #4";
|
qDebug() << "Failed pairing at stage #4";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +300,7 @@ NvPairingManager::pair(QString serverInfo, QString pin)
|
|||||||
if (m_Http.getXmlString(pairChallengeXml, "paired") != "1")
|
if (m_Http.getXmlString(pairChallengeXml, "paired") != "1")
|
||||||
{
|
{
|
||||||
qDebug() << "Failed pairing at stage #5";
|
qDebug() << "Failed pairing at stage #5";
|
||||||
|
m_Http.openConnectionToString(m_Http.m_BaseUrlHttp, "unpair", nullptr, true);
|
||||||
return PairState::FAILED;
|
return PairState::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,11 @@ private:
|
|||||||
QByteArray
|
QByteArray
|
||||||
decrypt(QByteArray ciphertext, AES_KEY* key);
|
decrypt(QByteArray ciphertext, AES_KEY* key);
|
||||||
|
|
||||||
|
QByteArray
|
||||||
|
getSignatureFromPemCert(QByteArray certificate);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
verifySignature(QByteArray data, QByteArray signature);
|
verifySignature(QByteArray data, QByteArray signature, QByteArray serverCertificate);
|
||||||
|
|
||||||
QByteArray
|
QByteArray
|
||||||
signMessage(QByteArray message);
|
signMessage(QByteArray message);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user