【RSA加密算法进行数字签名并验签--C++】

RSA加密算法进行数字签名并验签--C++

  • 前言
  • RSA加密算法
    • 什么是RSA加密算法
    • 公钥加密私钥解密or私钥加密公钥解密?
      • 公钥加密,私钥解密(常见用法):
      • 私钥加密,公钥解密(较少用法,本次使用):
    • 密钥生成
      • 原理
      • 密钥参数解释
      • 使用openssl命令行生成密钥
    • 加密
      • 公钥加密
      • 私钥加密
    • 解密
      • 私钥解密
      • 公钥解密
    • RSA_2048和RSA_3072
      • 密钥长度
  • 哈希函数(SHA-256)
    • 什么是SHA-256
    • SHA-256的基本性质
    • SHA-256基本原理
      • 一、常量初始化
      • 二、信息预处理(pre-processing)
      • 三、逻辑运算
      • 四、计算消息摘要
  • 数字签名
    • 签名过程(A发送方)
    • 验证过程(B接收方)
    • 数字签名的特性
  • 代码实现(openssl)
    • 生成消息摘要
    • 创建密钥对
    • 私钥加密
      • 使用私钥文件(.pem)
      • 使用N,E,D,的值进行加密
    • 公钥解密
      • 使用公钥文件(.pem)
      • 使用公钥NE值进行解密
    • 验签
  • 写在最后

前言

干货满满!!!收藏加关注从此不迷路!
首先会介绍一下RSA算法和数字签名的相关内容,然后使用C++ Qt实现RSA加密解密以及生成密钥对,同时也会说到使用SHA256计算文件的哈希值等。带好小板凳,准备上车!!!
【RSA加密算法进行数字签名并验签--C++】_第1张图片

RSA加密算法

什么是RSA加密算法

RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,用于保护数据的机密性。非对称加密意味着它使用一对密钥:一个用于加密,另一个用于解密。其中一个密钥是公开的(公钥),而另一个是私有的(私钥)。

公钥加密私钥解密or私钥加密公钥解密?

公钥加密,私钥解密(常见用法):

公钥加密: 发送方使用接收方的公钥对数据进行加密,然后发送加密后的数据。
私钥解密: 接收方使用自己的私钥对接收到的加密数据进行解密,还原为原始数据。
这是非对称加密的主要用法,用于保护数据在网络中的传输安全。公钥是公开的,用于加密数据,而私钥保持私密,只有接收方可以解密。

私钥加密,公钥解密(较少用法,本次使用):

私钥加密: 发送方使用自己的私钥对数据进行加密,然后发送加密后的数据。
公钥解密: 任何拥有接收方公钥的人都可以使用该公钥对数据进行解密。
这种方式的安全性较弱,因为私钥通常应该保持秘密,但在某些特殊情况下,例如数字签名等用途,可能会使用这种方式。
在实际应用中,私钥加密、公钥解密的使用场景相对有限,因为公钥加密、私钥解密提供了更好的安全性,确保了数据的机密性。私钥加密可能被用于数字签名等情况,但在这种情况下,通常还会结合散列函数等技术。

密钥生成

原理

1、选择两个大素数,称为 p 和 q。
2、计算 N = pq,这将是加密和解密过程中使用的模数。
3、计算欧拉函数 φ(N) = (p-1)(q-1)。
4、选择一个整数 e,1 < e < φ(N),使得 e 与 φ(N) 互质。e 将成为公钥的一部分。
5、计算 d,使得 de ≡ 1 (mod φ(N))。d 将成为私钥的一部分。

密钥参数解释

1、N(Modulus):
N 是两个大素数p和q的乘积。
N的位数决定了密钥的长度,通常表示为N的二进制位数。例如,2048位的RSA密钥将产生一个2048位的N。

2、E(Public Exponent):
E 是公钥的一部分,用于加密。
E必须是与φ(N)(欧拉函数,即(N)的正整数减一)互质的正整数。通常选择小的质数作为E,常见的选择包括65537。

3、D(Private Exponent):
D 是私钥的一部分,用于解密。
D是E在模φ(N)下的乘法逆元,即 (E * D) mod φ(N) ≡ 1。
计算D时,通常使用扩展欧几里得算法。

一个冷知识(冷知识:你全家都是冷知识):
E常常被选择为10001,或者更准确地说,是65537。这并非是一个随机的选择,而是出于一些特定的数学和计算考虑,以确保RSA算法的性能和安全性。
互质性: 选择一个与欧拉函数φ(N)(N的素因子之积减一)互质的E是关键的。这样,E与φ(N)之间就不存在共同的因子,确保了在计算过程中不会出现问题。65537是一个相对小的质数,而且它的二进制表示中包含较少的1位和0位,这有助于提高加密操作的效率。
安全性: 尽管65537看起来是一个相对小的值,但它足够大,以提供足够的安全性。它被认为是一个安全的选择,因为它满足了互质性的要求,并且在加密操作中提供了较好的性能。

使用openssl命令行生成密钥

1、生成RSA私钥文件

openssl genrsa -out rsa_private_key.pem 2048

2、生成RSA公钥文件

openssl rsa -in rsa_private_key.pem  -pubout -out rsa_public_key.pem

加密

公钥加密

1、发送方使用接收方的公钥(N, e)对明文数据M进行加密。
2、加密过程:C ≡ M^e (mod N),得到加密后的密文C。
3、发送密文C给接收方。

私钥加密

1、发送方使用自己的私钥(N, d)对明文数据M进行加密。
2、加密过程:C ≡ M^d (mod N),得到加密后的密文C。
3、发送密文C给接收方。

解密

私钥解密

1、接收方使用自己的私钥(N, d)对接收到的密文C进行解密。
2、解密过程:M ≡ C^d (mod N),得到原始明文数据M。

公钥解密

1、任何拥有发送方的公钥(N, e)的人都可以使用该公钥对接收到的密文C进行解密。
2、解密过程:M ≡ C^e (mod N),得到原始明文数据M。

RSA_2048和RSA_3072

密钥长度

RSA 密钥的长度是由 N 的比特数决定的,其中 N 是 RSA 模数(Modulus)。密钥长度直接影响到 RSA 算法的安全性,一般来说,密钥长度越长,算法越难被破解,但同时也导致加密和解密操作所需的计算量增加。
RSA-2048:
密钥长度为 2048 比特。(256字节)
RSA-2048 是过去常用的密钥长度,提供了较好的安全性。

RSA-3072:
密钥长度为 3072 比特。(384字节)
RSA-3072 提供了更高的安全性,对于一些对安全性要求更高的应用,例如政府、金融领域,可能会选择使用更长的密钥长度。

需要注意的是,随着计算机计算能力的提升,对于相同的安全强度,推荐使用更长的密钥长度。在当前情况下,RSA-2048 仍然是许多应用的合适选择,但在对安全性要求更高的场景,可以考虑使用更长的密钥长度,如 RSA-3072 或者更长。

哈希函数(SHA-256)

什么是SHA-256

SHA-256(Secure Hash Algorithm 256-bit)是SHA-2(Secure Hash Algorithm 2系列)中的一种哈希函数。SHA-256能够将输入数据生成一个256位(32字节)的哈希值,通常以64个十六进制字符表示。这个哈希值是唯一的,即使输入的数据只有微小的变化,输出的哈希值也会显著不同。

SHA-256的基本性质

不可逆性: 无法从哈希值反推出原始数据。因为SHA-256是一个单向函数,即给定输入,容易生成哈希值,但从哈希值推导出原始输入是困难的。

唯一性: 即便输入数据发生微小变化,SHA-256生成的哈希值也会大不相同,这使得它在校验数据完整性上非常有用。

固定长度: 无论输入数据的大小如何,SHA-256始终产生一个256位的哈希值。

密码学安全性: SHA-256是一种强密码学哈希函数,目前尚未发现有效的碰撞攻击,即找到两个不同的输入产生相同的哈希值。

SHA-256基本原理

参考:SHA256算法原理详解

一、常量初始化

SHA256算法中用到了8个哈希初值以及64个哈希常量。
其中,SHA256算法的8个哈希初值如下:

h0 := 0x6a09e667
h1 := 0xbb67ae85
h2 := 0x3c6ef372
h3 := 0xa54ff53a
h4 := 0x510e527f
h5 := 0x9b05688c
h6 := 0x1f83d9ab
h7 := 0x5be0cd19

这些初值是对自然数中前8个质数(2,3,5,7,11,13,17,19)的平方根的小数部分取前32bit而来。
64个常量如下:

428a2f98 71374491 b5c0fbcf e9b5dba5
3956c25b 59f111f1 923f82a4 ab1c5ed5
d807aa98 12835b01 243185be 550c7dc3
72be5d74 80deb1fe 9bdc06a7 c19bf174
e49b69c1 efbe4786 0fc19dc6 240ca1cc
2de92c6f 4a7484aa 5cb0a9dc 76f988da
983e5152 a831c66d b00327c8 bf597fc7
c6e00bf3 d5a79147 06ca6351 14292967
27b70a85 2e1b2138 4d2c6dfc 53380d13
650a7354 766a0abb 81c2c92e 92722c85
a2bfe8a1 a81a664b c24b8b70 c76c51a3
d192e819 d6990624 f40e3585 106aa070
19a4c116 1e376c08 2748774c 34b0bcb5
391c0cb3 4ed8aa4a 5b9cca4f 682e6ff3
748f82ee 78a5636f 84c87814 8cc70208
90befffa a4506ceb bef9a3f7 c67178f2

和8个哈希初值类似,这些常量是对自然数中前64个质数(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97…)的立方根的小数部分取前32bit而来。

二、信息预处理(pre-processing)

SHA-256的信息预处理(Message Preprocessing)是指在对输入数据进行哈希计算之前,对输入数据进行一系列步骤的处理。这个过程包括填充、添加长度信息等步骤,以确保输入数据的长度和格式满足SHA-256算法的要求。下面是SHA-256信息预处理的主要步骤:

1、填充(Padding): SHA-256要求输入数据的长度是512位块的整数倍。因此,如果输入数据的位数不足以构成一个完整的块,就需要进行填充。填充过程包括在数据后添加一个1比特,然后添加足够数量的0比特,直到满足长度要求。

2、添加长度信息: 在填充后,需要将原始消息的长度添加到消息的末尾。这是为了确保消息的完整性和唯一性。SHA-256使用64位的整数来表示原始消息的比特长度,这个长度信息会被追加到填充后的消息末尾。

三、逻辑运算

SHA-256(Secure Hash Algorithm 256-bit)涉及到一系列逻辑运算,这些运算是在信息预处理和压缩函数中完成的。SHA-256使用了比特级的逻辑运算,其中包括位移操作、按位逻辑运算等。下面是SHA-256中涉及的主要逻辑运算:
【RSA加密算法进行数字签名并验签--C++】_第2张图片

四、计算消息摘要

计算SHA-256消息摘要的过程涉及到信息预处理和迭代的压缩函数。下面是一个简化的步骤:
信息预处理:
对输入数据进行填充,确保其长度是512位块的整数倍。
在数据的末尾添加一个1比特,然后添加足够数量的0比特,直到满足长度要求。
将原始消息的长度(以比特为单位)追加到填充后的消息末尾,通常使用64位整数表示。
划分为块:
将填充和添加长度信息后的消息划分为512位的块。
初始值:
SHA-256使用一组初始的256位值作为内部状态的起始点。这些初始值是预定的常数,通过哈希算法的每个块进行迭代更新。
迭代压缩函数:
对每个512位的块进行迭代的压缩函数。
每个块都与上一次迭代的结果进行混合,然后通过一系列的轮进行处理,产生一个新的256位哈希值。
迭代会一直进行,直到所有的块都被处理完毕。
最终哈希值:
当所有块都被处理后,最终的256位哈希值即为消息的摘要。

数字签名

数字签名是一种用于确保消息的完整性、验证消息来源以及防止抵赖的加密技术。数字签名使用公钥密码学(非对称加密)来实现,通常涉及到两个主要步骤:签名和验证。

签名过程(A发送方)

A(发送方)的操作
1、创建消息: A创建一条消息,要发送给B。
2、哈希消息: A使用哈希函数对消息进行哈希运算,生成消息摘要。这个摘要通常是一个固定长度的二进制字符串,代表了消息的内容。
3、使用私钥进行签名: A使用自己的私钥对消息摘要进行数字签名。这涉及将消息摘要加密(使用私钥)生成数字签名。具体的签名算法(例如RSA、ECDSA等)将哈希值和私钥转换为数字签名。
4、发送消息和数字签名: A将原始消息和数字签名一起发送给B。这两者可以被同时发送,也可以分开发送。

验证过程(B接收方)

B(接收方)的操作:
1、接收消息和数字签名: B收到A发送的消息和数字签名。
2、哈希接收到的消息: B使用相同的哈希函数对接收到的消息进行哈希运算,得到接收到的消息摘要。
3、使用A的公钥验证签名: B使用A的公钥对接收到的数字签名进行解密。如果解密成功,将得到一个数字签名的副本。
4、比较哈希值: B将使用公钥解密得到的数字签名与自己计算的消息摘要进行比较。如果两者匹配,说明数字签名是有效的。

数字签名的特性

1、完整性(Integrity): 数字签名用于验证消息的完整性,确保消息在传输或存储过程中没有被篡改。如果消息被修改,数字签名的验证将失败。
2、身份验证(Authentication): 数字签名可以验证消息的来源,确保消息确实是由声明的发送方(签名私钥持有者)生成的。只有私钥持有者才能生成有效的数字签名。
3、不可抵赖性(Non-repudiation): 数字签名防止了消息的抵赖,即消息的生成者无法否认其生成了特定的消息。因为数字签名使用私钥进行签名,只有私钥持有者才能生成有效的签名,从而防止了发信人的抵赖。
4、时效性: 数字签名可以包含时间戳,确保签名的时间是可验证的。这对于确保信息在特定时间内有效或证明某个事件发生的时间很重要。
5、可验证性: 数字签名的有效性可以通过使用相应的公钥进行验证,而无需私钥。这使得接收方能够轻松地验证签名,而无需了解签名的生成过程。
6、抗篡改性: 数字签名的抗篡改性表明,除非私钥泄漏,否则签名不能被伪造或篡改。即使签名是公开可见的,也不能通过已知的信息重新生成有效的签名。
7、灵活性: 数字签名可以用于任何形式的数字数据,包括文本、文件、消息等。这使得数字签名具有广泛的适用性。
这些特性使得数字签名成为安全通信、数字证书、电子商务等领域中确保信息完整性和身份验证的强大工具。数字签名的广泛应用有助于保障信息的安全性和可信度。

代码实现(openssl)

生成消息摘要

后续选择RSA2048或RSA3072加密算法进行无填充加密,所以需要自己填充至密钥长度大小,2048填充至256字节,3072填充至384字节。

QByteArray cmacopenssl::calculateSHA256(const QString &filePath)
{
    QFile file(filePath);
    QByteArray result;
    const qint64 targetSize = ui->comboBox->currentText()=="RSA-2048"?256:384;  // 256 bytes
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open file:" << file.errorString();
        return result;
    }

    QCryptographicHash hash(QCryptographicHash::Sha256);
    if (hash.addData(&file)) {
        result = hash.result();
        if (result.size() < targetSize) {
            result.append(QByteArray(targetSize - result.size(), 0));
         }
        qDebug()<<result.toHex();
        return result;
    }

    file.close();
    return result;
}

创建密钥对

void cmacopenssl::generateRSAKeyPair(const QString &publicKeyFilePath, const QString &privateKeyFilePath) {
    RSA *rsa = RSA_new();

    // 设置 RSA 密钥参数
    BIGNUM *e = BN_new();
    BN_set_word(e, RSA_F4); // 公共指数,通常为 65537
    int rsaKeyLength=2048;
    if (ui->comboBox->currentText() == "RSA-2048") {
        rsaKeyLength = 2048;
    } else if (ui->comboBox->currentText() == "RSA-3072") {
        rsaKeyLength = 3072;
    }
    RSA_generate_key_ex(rsa, rsaKeyLength, e, nullptr);
    //RSA_generate_key_ex(rsa, 2048, e, nullptr);

    // 创建用于写入公钥和私钥的 BIO
    BIO *publicBio = BIO_new_file(publicKeyFilePath.toStdString().c_str(), "w");
    BIO *privateBio = BIO_new_file(privateKeyFilePath.toStdString().c_str(), "w");

    // 写入公钥
    PEM_write_bio_RSAPublicKey(publicBio, rsa);

    // 写入私钥
    PEM_write_bio_RSAPrivateKey(privateBio, rsa, nullptr, nullptr, 0, nullptr, nullptr);

    // 输出 N、E 和 D
    //getRSAKeyComponents(rsa);

    // 清理资源
    RSA_free(rsa);
    BN_free(e);
    BIO_free(publicBio);
    BIO_free(privateBio);
}

私钥加密

使用私钥文件(.pem)

QByteArray cmacopenssl::rsaEncrypt(const QByteArray &data) {
    QByteArray result;
    QString file;
    // 加载私钥
    file = ui->privatePath->text();
    FILE *privateKeyFile = fopen(file.toStdString().c_str(), "rb");
    if (!privateKeyFile) {
        qDebug() << "Failed to open private key file";
        return result;
    }
    qDebug() << file;
    RSA *privateKey = PEM_read_RSAPrivateKey(privateKeyFile, nullptr, nullptr, nullptr);
    fclose(privateKeyFile);
    if (!privateKey) {
        qDebug() << "Failed to read private key";
        QMessageBox::critical(nullptr, "Error", "读取私钥失败!");
        ERR_print_errors_fp(stderr);
        return result;
    }
    // 进行加密操作
    int keySize = RSA_size(privateKey);
    result.resize(keySize);
    if(data.size()!=keySize){
        qDebug() << " data should as same as key size.";
        QMessageBox::critical(nullptr,"error","数据大小要等于密钥大小,请选择正确的加密算法!");
        RSA_free(privateKey);
        return result;
    }
    int encryptSize = RSA_private_encrypt(data.size(), reinterpret_cast<const unsigned char *>(data.constData()), reinterpret_cast<unsigned char *>(result.data()), privateKey, RSA_NO_PADDING);
    if (encryptSize == -1) {
        qDebug() << "Encryption failed";
        QMessageBox::critical(nullptr, "Error", "加密失败!");
        ERR_print_errors_fp(stderr);
        result.clear();
    }
    // 释放私钥资源
    RSA_free(privateKey);
    return result;
}

使用N,E,D,的值进行加密

QByteArray cmacopenssl::rsaEncrypt(const QByteArray& data, const QString &modulus, const QString &exponent, const QString &privateExponent){

    RSA *rsa = RSA_new();

    // 将16进制字符串转换为BIGNUM
    BIGNUM *n = BN_new();
    BIGNUM *d = BN_new();  // Private exponent
    BIGNUM *e = BN_new();
    qDebug()<<privateExponent;
    if (!BN_hex2bn(&n, modulus.toStdString().c_str()) || !BN_hex2bn(&e, exponent.toStdString().c_str()) || !BN_hex2bn(&d, privateExponent.toStdString().c_str())) {
        qDebug() << "无法转换16进制字符串为BIGNUM";
        BN_free(n);
        BN_free(d);
        RSA_free(rsa);
        return QByteArray();
    }
    // 使用 RSA_set0_key 设置 RSA 结构体中的 n 和 d(私钥指数)
    RSA_set0_key(rsa, n,e, d);

    // 检查是否成功设置 RSA 密钥
    if (!rsa) {
        qDebug() << "RSA key setup failed";
        BN_free(n);
        BN_free(d);
        RSA_free(rsa);
        return QByteArray();
    }

    // 检查输入数据的长度是否等于密钥长度
    int keySize = RSA_size(rsa);
    qDebug() << "Key size: " << keySize;
    if (data.size() != keySize) {
        qDebug() << "输入数据长度与密钥长度不匹配";
        QMessageBox::critical(nullptr,"error","数据大小要等于密钥大小,请选择正确的加密算法!");
        BN_free(n);
        BN_free(d);
        //RSA_free(rsa);
        qDebug() << " data should as same as key size.";
        return QByteArray();
    }
    // 使用私钥进行加密(不填充)
    int encrypt_len;
    unsigned char *encryptedData = new unsigned char[keySize];
    // 进行加密操作(使用 RSA_NO_PADDING)
    encrypt_len = RSA_private_encrypt(data.size(), reinterpret_cast<const unsigned char *>(data.constData()), encryptedData, rsa, RSA_NO_PADDING);
    if (encrypt_len == -1) {
        // 加密失败
        QString errorMessage = QString("Encryption failed:\n%1").arg(ERR_error_string(ERR_get_error(), nullptr));
        QMessageBox::critical(nullptr, "Error", errorMessage);
        delete[] encryptedData;
        BN_free(n);
        BN_free(e);
        BN_free(d);
        RSA_free(rsa);
        return QByteArray();
    }

    QByteArray encryptedBytes(reinterpret_cast<char *>(encryptedData), keySize);
    delete[] encryptedData;
    BN_free(n);
    BN_free(d);
    BN_free(e);
    //RSA_free(rsa);
    return encryptedBytes;
}

公钥解密

使用公钥文件(.pem)

QByteArray cmacopenssl::rsadecrypt(const QByteArray &plainData) {
    QByteArray result;
    QString file;
    // 加载公钥
    file = ui->publicPath->text();
    FILE *publicKeyFile = fopen(file.toStdString().c_str(), "rb");
    if (!publicKeyFile) {
        qDebug() << "Failed to open public key file";
        return result;
    }
    RSA *publicKey = PEM_read_RSAPublicKey(publicKeyFile, nullptr, nullptr, nullptr);
    fclose(publicKeyFile);
    if (!publicKey) {
        qDebug() << "Failed to read public key";
        return result;
    }
    // 进行解密操作
    int keySize = RSA_size(publicKey);
    result.resize(keySize);
    if(plainData.size()!=keySize){
        qDebug() << "Encrypted data should as same as key size.";
        QMessageBox::critical(nullptr,"error","密文大小要等于密钥大小");
        RSA_free(publicKey);
        return result;
    }
    int encryptSize = RSA_public_decrypt(plainData.size(), reinterpret_cast<const unsigned char *>(plainData.constData()), reinterpret_cast<unsigned char *>(result.data()), publicKey, RSA_NO_PADDING);
    if (encryptSize == -1) {
        qDebug() << "decryption failed";
        ERR_print_errors_fp(stderr);
        result.clear();
    }
    // 释放公钥资源
    RSA_free(publicKey);
    return result;
}

使用公钥NE值进行解密

QByteArray cmacopenssl::rsaDecryptNoPadding(const QByteArray &encryptedData, const QString &modulus, const QString &publicExponent) {
    RSA *rsa = RSA_new();

    // 将16进制字符串转换为BIGNUM
    BIGNUM *n = BN_new();
    BIGNUM *e = BN_new();

    if (!BN_hex2bn(&n, modulus.toStdString().c_str()) || !BN_hex2bn(&e, publicExponent.toStdString().c_str())) {
        qDebug() << "无法转换16进制字符串为BIGNUM";
        BN_free(n);
        BN_free(e);
        return QByteArray();
    }

    // 使用 RSA_set0_key 设置 RSA 结构体中的 n、e
    RSA_set0_key(rsa, n, e, nullptr);

    int dataSize = RSA_size(rsa);
    if (encryptedData.size() != dataSize) {
        qDebug() << "Encrypted data should as same as key size.";
        QMessageBox::critical(nullptr,"error","密文大小要等于密钥大小");
        RSA_free(rsa);
        return QByteArray();
    }

    unsigned char *decryptedData = new unsigned char[dataSize];

    int result = RSA_public_decrypt(encryptedData.size(), reinterpret_cast<const unsigned char *>(encryptedData.constData()), decryptedData, rsa, RSA_NO_PADDING);
    if (result == -1) {
        // 解密失败
        qDebug() << "Decryption failed";
        ERR_print_errors_fp(stderr);
        delete[] decryptedData;
        RSA_free(rsa);
        return QByteArray();
    }

    QByteArray decryptedBytes(reinterpret_cast<char *>(decryptedData), result);
    delete[] decryptedData;

    RSA_free(rsa);

    return decryptedBytes;
}

验签

//验签
void cmacopenssl::on_pushButton_versign_clicked()
{
    //对原始数据文件计算SHA256
    QByteArray SHA256Result;
    QByteArray encryptedData;
    QByteArray decryptedData;
    if(ui->filePath_ver->text().isEmpty()){
        QMessageBox::critical(nullptr,"error","请选择需要验证的文件!");
        return;
    }
    SHA256Result=calculateSHA256(ui->filePath_ver->text());
    //SHA256Result = cmacopenssl::calculateSHA256(cmacopenssl::filePath);
    QByteArray SHA256Result_swap = swapGroups(SHA256Result,4);
    //读取签名文件,并解密
    if(ui->filePath_sign->text().isEmpty()){
        QMessageBox::critical(nullptr,"error","请选择签名文件文件!");
        return;
    }
    QFile file(ui->filePath_sign->text());
    if(file.open(QIODevice::ReadOnly)){
        encryptedData=file.readAll();
        file.close();
    }
    qDebug()<<encryptedData.toHex();

    if(ui->comboBox_rsafile->currentText()==".pem"){
        if(!ui->publicPath->text().isEmpty()){
            decryptedData = rsadecrypt(encryptedData);//通过公钥文件进行解密
        }else{
            QMessageBox::critical(nullptr,"error","请先加载公钥文件!");
            return;
        }
    }else {
        if(ui->lineEdit_N->text().isEmpty()||ui->lineEdit_E->text().isEmpty()){
            QMessageBox::critical(nullptr,"error","请先输入N 和E的值!");
            return;
        }
        QString modulus = ui->lineEdit_N->text();
        QString exponent =ui->lineEdit_E->text();
        decryptedData=rsaDecryptNoPadding(encryptedData,modulus,exponent);//使用N,E值解密
    }
    if(SHA256Result_swap==decryptedData){
        ui->textEdit->append("验证成功:"+decryptedData.toHex());
        QMessageBox::information(this, "Success", "Verification succeeded.");
    }else{
        ui->textEdit->append("验证失败:"+decryptedData.toHex());
        QMessageBox::critical(this, "Failure", "Verification failed.");
    }
}

写在最后

【RSA加密算法进行数字签名并验签--C++】_第3张图片

在写代码的时候也遇到了很多很多坑,特别是在加密解密的过程中,时不时就程序崩掉,好在最后都找到了原因,我走过的坑,大家无需再踩了。最后,创作不易,大家点赞收藏加关注!!
【RSA加密算法进行数字签名并验签--C++】_第4张图片

你可能感兴趣的:(c++,java,开发语言,qt)