parent
4d0d0c1d60
commit
dd6093a5ac
|
@ -26,6 +26,7 @@ QtObject {
|
||||||
property string screenName: ""
|
property string screenName: ""
|
||||||
property string password: ""
|
property string password: ""
|
||||||
property string cipherText
|
property string cipherText
|
||||||
|
property string aeskey
|
||||||
|
|
||||||
// Client data
|
// Client data
|
||||||
property int roomCapacity: 0
|
property int roomCapacity: 0
|
||||||
|
|
|
@ -19,17 +19,23 @@ let sheduled_download = "";
|
||||||
|
|
||||||
callbacks["NetworkDelayTest"] = function(jsonData) {
|
callbacks["NetworkDelayTest"] = function(jsonData) {
|
||||||
// jsonData: RSA pub key
|
// jsonData: RSA pub key
|
||||||
let cipherText
|
let cipherText;
|
||||||
|
let aeskey;
|
||||||
if (config.savedPassword[config.serverAddr] !== undefined
|
if (config.savedPassword[config.serverAddr] !== undefined
|
||||||
&& config.savedPassword[config.serverAddr].shorten_password === config.password) {
|
&& config.savedPassword[config.serverAddr].shorten_password === config.password) {
|
||||||
cipherText = config.savedPassword[config.serverAddr].password;
|
cipherText = config.savedPassword[config.serverAddr].password;
|
||||||
|
aeskey = config.savedPassword[config.serverAddr].key;
|
||||||
|
config.aeskey = aeskey;
|
||||||
|
Backend.setAESKey(aeskey);
|
||||||
if (Debugging)
|
if (Debugging)
|
||||||
console.log("use remembered password", config.password);
|
console.log("use remembered password", config.password);
|
||||||
} else {
|
} else {
|
||||||
cipherText = Backend.pubEncrypt(jsonData, config.password);
|
cipherText = Backend.pubEncrypt(jsonData, config.password);
|
||||||
|
config.aeskey = Backend.getAESKey();
|
||||||
}
|
}
|
||||||
config.cipherText = cipherText;
|
config.cipherText = cipherText;
|
||||||
Backend.replyDelayTest(config.screenName, cipherText);
|
Backend.replyDelayTest(config.screenName, cipherText);
|
||||||
|
Backend.installAESKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
callbacks["ErrorMsg"] = function(jsonData) {
|
callbacks["ErrorMsg"] = function(jsonData) {
|
||||||
|
@ -69,6 +75,7 @@ callbacks["EnterLobby"] = function(jsonData) {
|
||||||
config.savedPassword[config.serverAddr] = {
|
config.savedPassword[config.serverAddr] = {
|
||||||
username: config.screenName,
|
username: config.screenName,
|
||||||
password: config.cipherText,
|
password: config.cipherText,
|
||||||
|
key: config.aeskey,
|
||||||
shorten_password: config.cipherText.slice(0, 8)
|
shorten_password: config.cipherText.slice(0, 8)
|
||||||
}
|
}
|
||||||
mainStack.push(lobby);
|
mainStack.push(lobby);
|
||||||
|
|
|
@ -68,3 +68,5 @@ void Client::removePlayer(int id) {
|
||||||
void Client::clearPlayers() { players.clear(); }
|
void Client::clearPlayers() { players.clear(); }
|
||||||
|
|
||||||
lua_State *Client::getLuaState() { return L; }
|
lua_State *Client::getLuaState() { return L; }
|
||||||
|
|
||||||
|
void Client::installAESKey(const QByteArray &key) { router->installAESKey(key); }
|
||||||
|
|
|
@ -29,6 +29,7 @@ public:
|
||||||
Q_INVOKABLE void clearPlayers();
|
Q_INVOKABLE void clearPlayers();
|
||||||
|
|
||||||
lua_State *getLuaState();
|
lua_State *getLuaState();
|
||||||
|
void installAESKey(const QByteArray &key);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void error_message(const QString &msg);
|
void error_message(const QString &msg);
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "client_socket.h"
|
#include "client_socket.h"
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
#include <qrandom.h>
|
||||||
|
|
||||||
ClientSocket::ClientSocket() : socket(new QTcpSocket(this)) { init(); }
|
ClientSocket::ClientSocket() : socket(new QTcpSocket(this)) {
|
||||||
|
aes_ready = false;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
ClientSocket::ClientSocket(QTcpSocket *socket) {
|
ClientSocket::ClientSocket(QTcpSocket *socket) {
|
||||||
socket->setParent(this);
|
socket->setParent(this);
|
||||||
|
@ -28,6 +33,7 @@ void ClientSocket::connectToHost(const QString &address, ushort port) {
|
||||||
void ClientSocket::getMessage() {
|
void ClientSocket::getMessage() {
|
||||||
while (socket->canReadLine()) {
|
while (socket->canReadLine()) {
|
||||||
auto msg = socket->readLine();
|
auto msg = socket->readLine();
|
||||||
|
msg = aesDecrypt(msg);
|
||||||
if (msg.startsWith("Compressed")) {
|
if (msg.startsWith("Compressed")) {
|
||||||
msg = msg.sliced(10);
|
msg = msg.sliced(10);
|
||||||
msg = qUncompress(QByteArray::fromBase64(msg));
|
msg = qUncompress(QByteArray::fromBase64(msg));
|
||||||
|
@ -36,18 +42,22 @@ void ClientSocket::getMessage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientSocket::disconnectFromHost() { socket->disconnectFromHost(); }
|
void ClientSocket::disconnectFromHost() {
|
||||||
|
aes_ready = false;
|
||||||
|
socket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
|
||||||
void ClientSocket::send(const QByteArray &msg) {
|
void ClientSocket::send(const QByteArray &msg) {
|
||||||
|
QByteArray _msg;
|
||||||
if (msg.length() >= 1024) {
|
if (msg.length() >= 1024) {
|
||||||
auto comp = qCompress(msg);
|
auto comp = qCompress(msg);
|
||||||
auto _msg = "Compressed" + comp.toBase64() + "\n";
|
_msg = "Compressed" + comp.toBase64();
|
||||||
socket->write(_msg);
|
_msg = aesEncrypt(_msg) + "\n";
|
||||||
socket->flush();
|
} else {
|
||||||
|
_msg = aesEncrypt(msg) + "\n";
|
||||||
}
|
}
|
||||||
socket->write(msg);
|
|
||||||
if (!msg.endsWith("\n"))
|
socket->write(_msg);
|
||||||
socket->write("\n");
|
|
||||||
socket->flush();
|
socket->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,3 +106,62 @@ void ClientSocket::raiseError(QAbstractSocket::SocketError socket_error) {
|
||||||
.arg(socket_error)
|
.arg(socket_error)
|
||||||
.arg(reason));
|
.arg(reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientSocket::installAESKey(const QByteArray &key) {
|
||||||
|
if (key.length() != 32) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto key_ = QByteArray::fromHex(key);
|
||||||
|
|
||||||
|
AES_set_encrypt_key((const unsigned char *)key_.data(), 16 * 8, &aes_key);
|
||||||
|
aes_ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray ClientSocket::aesEncrypt(const QByteArray &in) {
|
||||||
|
if (!aes_ready) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
int num = 0;
|
||||||
|
QByteArray out;
|
||||||
|
out.resize(in.length());
|
||||||
|
|
||||||
|
auto rand_generator = QRandomGenerator::securelySeeded();
|
||||||
|
|
||||||
|
QByteArray iv;
|
||||||
|
iv.append(QByteArray::number(rand_generator.generate64(), 16));
|
||||||
|
iv.append(QByteArray::number(rand_generator.generate64(), 16));
|
||||||
|
if (iv.length() < 32) {
|
||||||
|
iv.append(QByteArray("0").repeated(32 - iv.length()));
|
||||||
|
}
|
||||||
|
auto iv_raw = QByteArray::fromHex(iv);
|
||||||
|
|
||||||
|
unsigned char tempIv[16];
|
||||||
|
strncpy((char *)tempIv, iv_raw.constData(), 16);
|
||||||
|
AES_cfb128_encrypt((const unsigned char *)in.constData(),
|
||||||
|
(unsigned char *)out.data(), in.length(), &aes_key, tempIv,
|
||||||
|
&num, AES_ENCRYPT);
|
||||||
|
|
||||||
|
return iv + out.toBase64();
|
||||||
|
}
|
||||||
|
QByteArray ClientSocket::aesDecrypt(const QByteArray &in) {
|
||||||
|
if (!aes_ready) {
|
||||||
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num = 0;
|
||||||
|
auto iv = in.first(32);
|
||||||
|
auto aes_iv = QByteArray::fromHex(iv);
|
||||||
|
|
||||||
|
auto real_in = in;
|
||||||
|
real_in.remove(0, 32);
|
||||||
|
auto inenc = QByteArray::fromBase64(real_in);
|
||||||
|
QByteArray out;
|
||||||
|
out.resize(inenc.length());
|
||||||
|
unsigned char tempIv[16];
|
||||||
|
strncpy((char *)tempIv, aes_iv.constData(), 16);
|
||||||
|
AES_cfb128_encrypt((const unsigned char *)inenc.constData(),
|
||||||
|
(unsigned char *)out.data(), inenc.length(), &aes_key,
|
||||||
|
tempIv, &num, AES_DECRYPT);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#ifndef _CLIENT_SOCKET_H
|
#ifndef _CLIENT_SOCKET_H
|
||||||
#define _CLIENT_SOCKET_H
|
#define _CLIENT_SOCKET_H
|
||||||
|
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
|
||||||
class ClientSocket : public QObject {
|
class ClientSocket : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -13,6 +15,7 @@ public:
|
||||||
|
|
||||||
void connectToHost(const QString &address = "127.0.0.1", ushort port = 9527u);
|
void connectToHost(const QString &address = "127.0.0.1", ushort port = 9527u);
|
||||||
void disconnectFromHost();
|
void disconnectFromHost();
|
||||||
|
void installAESKey(const QByteArray &key);
|
||||||
void send(const QByteArray& msg);
|
void send(const QByteArray& msg);
|
||||||
bool isConnected() const;
|
bool isConnected() const;
|
||||||
QString peerName() const;
|
QString peerName() const;
|
||||||
|
@ -30,6 +33,10 @@ private slots:
|
||||||
void raiseError(QAbstractSocket::SocketError error);
|
void raiseError(QAbstractSocket::SocketError error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QByteArray aesEncrypt(const QByteArray &in);
|
||||||
|
QByteArray aesDecrypt(const QByteArray &out);
|
||||||
|
AES_KEY aes_key;
|
||||||
|
bool aes_ready;
|
||||||
QTcpSocket *socket;
|
QTcpSocket *socket;
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,6 +43,10 @@ void Router::setSocket(ClientSocket *socket) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Router::installAESKey(const QByteArray &key) {
|
||||||
|
socket->installAESKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef FK_CLIENT_ONLY
|
#ifndef FK_CLIENT_ONLY
|
||||||
void Router::setReplyReadySemaphore(QSemaphore *semaphore) {
|
void Router::setReplyReadySemaphore(QSemaphore *semaphore) {
|
||||||
extraReplyReadySemaphore = semaphore;
|
extraReplyReadySemaphore = semaphore;
|
||||||
|
|
|
@ -30,6 +30,7 @@ public:
|
||||||
|
|
||||||
ClientSocket *getSocket() const;
|
ClientSocket *getSocket() const;
|
||||||
void setSocket(ClientSocket *socket);
|
void setSocket(ClientSocket *socket);
|
||||||
|
void installAESKey(const QByteArray &key);
|
||||||
|
|
||||||
#ifndef FK_CLIENT_ONLY
|
#ifndef FK_CLIENT_ONLY
|
||||||
void setReplyReadySemaphore(QSemaphore *semaphore);
|
void setReplyReadySemaphore(QSemaphore *semaphore);
|
||||||
|
|
|
@ -227,6 +227,15 @@ void Server::handleNameAndPassword(ClientSocket *client, const QString &name,
|
||||||
buf, rsa, RSA_PKCS1_PADDING);
|
buf, rsa, RSA_PKCS1_PADDING);
|
||||||
auto decrypted_pw =
|
auto decrypted_pw =
|
||||||
QByteArray::fromRawData((const char *)buf, strlen((const char *)buf));
|
QByteArray::fromRawData((const char *)buf, strlen((const char *)buf));
|
||||||
|
|
||||||
|
if (decrypted_pw.length() > 32) {
|
||||||
|
auto aes_bytes = decrypted_pw.first(32);
|
||||||
|
client->installAESKey(aes_bytes);
|
||||||
|
decrypted_pw.remove(0, 32);
|
||||||
|
} else {
|
||||||
|
decrypted_pw = "\xFF";
|
||||||
|
}
|
||||||
|
|
||||||
bool passed = false;
|
bool passed = false;
|
||||||
QString error_msg;
|
QString error_msg;
|
||||||
QJsonArray result;
|
QJsonArray result;
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "qmlbackend.h"
|
#include "qmlbackend.h"
|
||||||
#include <QClipboard>
|
|
||||||
#include <QMediaPlayer>
|
|
||||||
#include <qaudiooutput.h>
|
#include <qaudiooutput.h>
|
||||||
#include <qmediaplayer.h>
|
#include <qmediaplayer.h>
|
||||||
#include <qrandom.h>
|
#include <qrandom.h>
|
||||||
|
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QMediaPlayer>
|
||||||
|
#include <cstdlib>
|
||||||
#ifndef Q_OS_WASM
|
#ifndef Q_OS_WASM
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -179,14 +182,29 @@ QString QmlBackend::callLuaFunction(const QString &func_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlBackend::pubEncrypt(const QString &key, const QString &data) {
|
QString QmlBackend::pubEncrypt(const QString &key, const QString &data) {
|
||||||
|
// 在用公钥加密口令时,也随机生成AES密钥/IV,并随着口令一起加密
|
||||||
|
// AES密钥和IV都是固定16字节的,所以可以放在开头
|
||||||
auto key_bytes = key.toLatin1();
|
auto key_bytes = key.toLatin1();
|
||||||
BIO *keyio = BIO_new_mem_buf(key_bytes.constData(), -1);
|
BIO *keyio = BIO_new_mem_buf(key_bytes.constData(), -1);
|
||||||
PEM_read_bio_RSAPublicKey(keyio, &rsa, NULL, NULL);
|
PEM_read_bio_RSAPublicKey(keyio, &rsa, NULL, NULL);
|
||||||
BIO_free_all(keyio);
|
BIO_free_all(keyio);
|
||||||
|
|
||||||
auto data_bytes = data.toUtf8();
|
auto data_bytes = data.toUtf8();
|
||||||
|
auto rand_generator = QRandomGenerator::securelySeeded();
|
||||||
|
QByteArray aes_key_;
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
aes_key_.append(QByteArray::number(rand_generator.generate64(), 16));
|
||||||
|
}
|
||||||
|
if (aes_key_.length() < 32) {
|
||||||
|
aes_key_.append(QByteArray("0").repeated(32 - aes_key_.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
aes_key = aes_key_;
|
||||||
|
|
||||||
|
data_bytes.prepend(aes_key_);
|
||||||
|
|
||||||
unsigned char buf[RSA_size(rsa)];
|
unsigned char buf[RSA_size(rsa)];
|
||||||
RSA_public_encrypt(data.length(),
|
RSA_public_encrypt(data.length() + 32,
|
||||||
(const unsigned char *)data_bytes.constData(), buf, rsa,
|
(const unsigned char *)data_bytes.constData(), buf, rsa,
|
||||||
RSA_PKCS1_PADDING);
|
RSA_PKCS1_PADDING);
|
||||||
return QByteArray::fromRawData((const char *)buf, RSA_size(rsa)).toBase64();
|
return QByteArray::fromRawData((const char *)buf, RSA_size(rsa)).toBase64();
|
||||||
|
@ -258,3 +276,11 @@ void QmlBackend::playSound(const QString &name, int index) {
|
||||||
void QmlBackend::copyToClipboard(const QString &s) {
|
void QmlBackend::copyToClipboard(const QString &s) {
|
||||||
QGuiApplication::clipboard()->setText(s);
|
QGuiApplication::clipboard()->setText(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlBackend::setAESKey(const QString &key) { aes_key = key; }
|
||||||
|
|
||||||
|
QString QmlBackend::getAESKey() const { return aes_key; }
|
||||||
|
|
||||||
|
void QmlBackend::installAESKey() {
|
||||||
|
ClientInstance->installAESKey(aes_key.toLatin1());
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#ifndef _QMLBACKEND_H
|
#ifndef _QMLBACKEND_H
|
||||||
#define _QMLBACKEND_H
|
#define _QMLBACKEND_H
|
||||||
|
|
||||||
|
#include <qtmetamacros.h>
|
||||||
class QmlBackend : public QObject {
|
class QmlBackend : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -42,12 +43,17 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE void copyToClipboard(const QString &s);
|
Q_INVOKABLE void copyToClipboard(const QString &s);
|
||||||
|
|
||||||
|
Q_INVOKABLE void setAESKey(const QString &key);
|
||||||
|
Q_INVOKABLE QString getAESKey() const;
|
||||||
|
Q_INVOKABLE void installAESKey();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void notifyUI(const QString &command, const QString &jsonData);
|
void notifyUI(const QString &command, const QString &jsonData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QQmlApplicationEngine *engine;
|
QQmlApplicationEngine *engine;
|
||||||
RSA *rsa;
|
RSA *rsa;
|
||||||
|
QString aes_key;
|
||||||
|
|
||||||
void pushLuaValue(lua_State *L, QVariant v);
|
void pushLuaValue(lua_State *L, QVariant v);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue