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