如何在JS与QML中实现RSA密钥生成及P2P消息加解密?
我来帮你解决这个问题,在QML环境里用JS实现RSA加解密确实会遇到浏览器JS库的适配问题,这里有几个可行的方案,你可以根据项目需求选择:
方案1:改造jsencrypt适配QML环境
jsencrypt原本是为浏览器设计的,依赖window全局对象,而QML的JS运行环境没有这个对象,所以我们只需要修改库的全局绑定逻辑就能让它在QML里工作:
步骤:
下载jsencrypt的源码文件,打开
jsencrypt.js找到文件最外层的自执行函数:
(function (window, undefined) { // 库代码... window.JSEncrypt = JSEncrypt; })(window);修改成:
(function (global, undefined) { // 库代码... global.JSEncrypt = JSEncrypt; })(this);这样就能把
JSEncrypt绑定到QML的全局JS环境中。在QML里用
Qt.include()引入修改后的库,而不是import(import只适用于符合Qt规范的JS模块)
QML使用示例:
import QtQuick 2.15 Item { Component.onCompleted: { // 引入修改后的jsencrypt库 Qt.include("jsencrypt.js") // 创建加密实例并生成密钥对 const encryptor = new JSEncrypt() encryptor.generateKeyPair() const publicKey = encryptor.getPublicKey() const privateKey = encryptor.getPrivateKey() console.log("生成的公钥:", publicKey) console.log("生成的私钥:", privateKey) // 测试加解密 const plainText = "Hello QML RSA" const encryptedText = encryptor.encrypt(plainText) console.log("加密后内容:", encryptedText) const decryptedText = encryptor.decrypt(encryptedText) console.log("解密后内容:", decryptedText) } }
优缺点:
- ✅ 纯JS实现,不需要编写C++代码,适合快速原型开发
- ❌ 依赖第三方库,需要手动修改适配,性能不如原生Qt API
方案2:用C++封装Qt原生RSA能力(推荐生产环境)
如果你的项目需要稳定的加密能力,推荐用Qt自带的OpenSSL绑定来封装RSA功能,注册到QML中使用,这是最可靠的方案:
步骤:
- 创建C++类封装RSA操作(需要链接OpenSSL库,Qt默认已经集成)
- 将类注册到QML环境
- 在QML中直接调用类的方法
C++代码示例:
RsaCrypto.h
#ifndef RSACRYPTO_H #define RSACRYPTO_H #include <QObject> #include <QString> #include <QPair> class RsaCrypto : public QObject { Q_OBJECT public: explicit RsaCrypto(QObject *parent = nullptr); // 生成RSA密钥对,返回(公钥, 私钥) Q_INVOKABLE QPair<QString, QString> generateKeyPair(int keySize = 2048); // 用公钥加密文本 Q_INVOKABLE QString encrypt(const QString &plainText, const QString &publicKey); // 用私钥解密文本 Q_INVOKABLE QString decrypt(const QString &encryptedText, const QString &privateKey); }; #endif // RSACRYPTO_H
RsaCrypto.cpp
#include "RsaCrypto.h" #include <QSslKey> #include <QByteArray> #include <openssl/rsa.h> #include <openssl/pem.h> #include <openssl/err.h> #include <QDebug> RsaCrypto::RsaCrypto(QObject *parent) : QObject(parent) {} QPair<QString, QString> RsaCrypto::generateKeyPair(int keySize) { RSA *rsa = RSA_new(); BIGNUM *exponent = BN_new(); BN_set_word(exponent, RSA_F4); // 生成密钥对 RSA_generate_key_ex(rsa, keySize, exponent, nullptr); // 导出公钥为PEM格式 BIO *pubBio = BIO_new(BIO_s_mem()); PEM_write_bio_RSAPublicKey(pubBio, rsa); char *pubData; long pubLen = BIO_get_mem_data(pubBio, &pubData); QString publicKey = QString::fromUtf8(pubData, pubLen); // 导出私钥为PEM格式 BIO *privBio = BIO_new(BIO_s_mem()); PEM_write_bio_RSAPrivateKey(privBio, rsa, nullptr, nullptr, 0, nullptr, nullptr); char *privData; long privLen = BIO_get_mem_data(privBio, &privData); QString privateKey = QString::fromUtf8(privData, privLen); // 清理资源 BIO_free(pubBio); BIO_free(privBio); RSA_free(rsa); BN_free(exponent); return qMakePair(publicKey, privateKey); } QString RsaCrypto::encrypt(const QString &plainText, const QString &publicKey) { BIO *pubBio = BIO_new_mem_buf(publicKey.toUtf8().data(), publicKey.toUtf8().size()); RSA *rsa = PEM_read_bio_RSAPublicKey(pubBio, nullptr, nullptr, nullptr); BIO_free(pubBio); if (!rsa) { qDebug() << "Failed to load public key"; return ""; } int rsaSize = RSA_size(rsa); QByteArray plainData = plainText.toUtf8(); QByteArray encryptedData(rsaSize, 0); int encryptResult = RSA_public_encrypt(plainData.size(), reinterpret_cast<const unsigned char*>(plainData.data()), reinterpret_cast<unsigned char*>(encryptedData.data()), rsa, RSA_PKCS1_PADDING); RSA_free(rsa); if (encryptResult == -1) { qDebug() << "Encryption failed"; return ""; } return encryptedData.toBase64(); } QString RsaCrypto::decrypt(const QString &encryptedText, const QString &privateKey) { BIO *privBio = BIO_new_mem_buf(privateKey.toUtf8().data(), privateKey.toUtf8().size()); RSA *rsa = PEM_read_bio_RSAPrivateKey(privBio, nullptr, nullptr, nullptr); BIO_free(privBio); if (!rsa) { qDebug() << "Failed to load private key"; return ""; } int rsaSize = RSA_size(rsa); QByteArray encryptedData = QByteArray::fromBase64(encryptedText.toUtf8()); QByteArray decryptedData(rsaSize, 0); int decryptResult = RSA_private_decrypt(encryptedData.size(), reinterpret_cast<const unsigned char*>(encryptedData.data()), reinterpret_cast<unsigned char*>(decryptedData.data()), rsa, RSA_PKCS1_PADDING); RSA_free(rsa); if (decryptResult == -1) { qDebug() << "Decryption failed"; return ""; } return QString::fromUtf8(decryptedData.data(), decryptResult); }
main.cpp(注册到QML)
#include <QGuiApplication> #include <QQmlApplicationEngine> #include "RsaCrypto.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); // 注册RsaCrypto到QML,命名空间为com.example.rsacrypto,版本1.0 qmlRegisterType<RsaCrypto>("com.example.rsacrypto", 1, 0, "RsaCrypto"); QQmlApplicationEngine engine; const QUrl url(u"qrc:/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
QML使用示例:
import QtQuick 2.15 import com.example.rsacrypto 1.0 Item { // 创建RsaCrypto实例 RsaCrypto { id: rsaCrypto } Component.onCompleted: { // 生成2048位密钥对 const keyPair = rsaCrypto.generateKeyPair(2048) const publicKey = keyPair.first const privateKey = keyPair.second console.log("公钥:", publicKey) console.log("私钥:", privateKey) // 测试加解密 const message = "Hello from QML + C++ RSA" const encryptedMsg = rsaCrypto.encrypt(message, publicKey) console.log("加密后:", encryptedMsg) const decryptedMsg = rsaCrypto.decrypt(encryptedMsg, privateKey) console.log("解密后:", decryptedMsg) } }
优缺点:
- ✅ 基于Qt原生OpenSSL绑定,性能稳定,安全性高,适合生产环境
- ✅ 可以自定义扩展更多加密功能
- ❌ 需要编写C++代码,对Qt开发有一定基础要求
方案3:使用轻量级纯JS RSA实现
如果你不想修改第三方库,也可以找一些不依赖浏览器全局对象的纯JS RSA实现,比如一些开源的小型RSA库(比如仅实现核心加解密和密钥生成的版本),直接用Qt.include()引入QML即可使用。这类库通常体积小,没有额外依赖,适合简单场景。
内容的提问来源于stack exchange,提问作者TheMan68
相关产品推荐
相关产品推荐

