You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JS与QML中实现RSA密钥生成及P2P消息加解密?

我来帮你解决这个问题,在QML环境里用JS实现RSA加解密确实会遇到浏览器JS库的适配问题,这里有几个可行的方案,你可以根据项目需求选择:

方案1:改造jsencrypt适配QML环境

jsencrypt原本是为浏览器设计的,依赖window全局对象,而QML的JS运行环境没有这个对象,所以我们只需要修改库的全局绑定逻辑就能让它在QML里工作:

步骤:

  1. 下载jsencrypt的源码文件,打开jsencrypt.js

  2. 找到文件最外层的自执行函数:

    (function (window, undefined) {
        // 库代码...
        window.JSEncrypt = JSEncrypt;
    })(window);
    

    修改成:

    (function (global, undefined) {
        // 库代码...
        global.JSEncrypt = JSEncrypt;
    })(this);
    

    这样就能把JSEncrypt绑定到QML的全局JS环境中。

  3. 在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中使用,这是最可靠的方案:

步骤:

  1. 创建C++类封装RSA操作(需要链接OpenSSL库,Qt默认已经集成)
  2. 将类注册到QML环境
  3. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:48:05