alin的学习之路:RSA非对称加密算法哈希算法demo

alin的学习之路:RSA非对称加密算法哈希算法demo

demo代码

.h 头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <QCryptographicHash>
#include <QDebug>
#include <QFile>
#include <QDir>



namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    //hash test
    void hashTest();

    //非对称加密
    void generateRsa();

    //公钥加密
    QString rsaPublicEncrypt(QString msg);

    //私钥解密
    QString rsaPrivateDecrypt(QString msg);

    //数字签名与校验
    bool rsaSignAndVerify();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

.cpp 源文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "rsacrypto.h"

extern "C"
{
// 在编译源文件的时候, applink.c也会参与到编译的过程中
#include <openssl/applink.c>
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //hashTest();
    //generateRsa();

//    QString sec = rsaPublicEncrypt("密文长度 == 秘钥长度== 分组的长度");
//    qDebug() << "解密后:" << rsaPrivateDecrypt(sec);

//    qDebug() << rsaSignAndVerify();
    rsacrypto rsa;
    rsa.generateRsakey(2048);
    QString msg = rsa.rsaPubKeyEncrypt("我爱学习");
    qDebug() << rsa.rsaPriKeyDecrypt(msg);

    // 数字签名
    QString text = "我特别爱学习";
    QString encStr = rsa.rsaSign(text, Level6);

    // 签名校验
    bool bl = rsa.rsaVerify(text, encStr, Level6);
    qDebug() << "签名校验结果: " << bl;

    // 获取私钥
    qDebug() << rsa.publicPemKey(PubFileName);
    // 获取公钥
    qDebug() << rsa.privatePemKey(PriFileName);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::hashTest()
{
    QCryptographicHash hash(QCryptographicHash::Sha224);
    //将字符串使用哈希函数转换为哈希值
    hash.addData("hello");
    hash.addData("world");

    QByteArray array = hash.result().toHex();
    qDebug() << "sha224:" << array;

    //直接将文件转换为哈希值
    //:/image-20200611153139152.png
    QFile file(":/image-20200611153139152.png");
    file.open(QFile::ReadOnly);
    hash.reset();
    hash.addData(&file);
    array = hash.result().toHex();
    qDebug() << "sha224:" << array;

    //使用静态函数直接将字符串转换为哈希值,不通过添加的方式
    array = QCryptographicHash::hash("helloworld", QCryptographicHash::Sha224).toHex();
    qDebug() << "sha224:" << array;

}

void MainWindow::generateRsa()
{
    //生成密钥对,并存储在内存中
    RSA* rsa = RSA_new();
    BIGNUM* e = BN_new();
    //初始化变量e
    BN_set_word(e, 12345);
    RSA_generate_key_ex(rsa, 1024, e, NULL);
#if 0
    //持久化存储密钥 方式1
    BIO* pubbio = BIO_new_file("public.pem", "w");
    PEM_write_bio_RSAPublicKey(pubbio, rsa);
    BIO* pribio = BIO_new_file("private.pem", "w");
    PEM_write_bio_RSAPrivateKey(pribio, rsa, NULL, NULL, 0, NULL, NULL);
    BIO_free(pubbio);
    BIO_free(pribio);
#else
    FILE* publicfile = fopen("public2.pem", "w");
    PEM_write_RSAPublicKey(publicfile, rsa);
    FILE* privatefile = fopen("private2.pem", "w");
    PEM_write_RSAPrivateKey(privatefile, rsa, NULL, NULL, 0, NULL, NULL);
    fclose(publicfile);
    fclose(privatefile);
#endif
    //释放内存
    RSA_free(rsa);
    BN_free(e);
}

QString MainWindow::rsaPublicEncrypt(QString msg)
{
    BIO* bio = BIO_new_file("public.pem", "r");
    RSA* rsa = RSA_new();
    //从磁盘文件中加载公钥,此时rsa中只有公钥
    if(PEM_read_bio_RSAPublicKey(bio, &rsa, NULL, NULL) == NULL)
    {
        qDebug() << "PEM_read_bio_RSAPublicKey() error" ;
        return QString();
    }

    //使用公钥对数据进行加密
    int keylen = RSA_size(rsa);
    QByteArray array = msg.toUtf8();
    unsigned char* to = new unsigned char[keylen];
    //公钥加密核心函数,返回的是密文的长度
    //参1是原始数据的长度
    int ret = RSA_public_encrypt(array.size(), (unsigned char*)array.data(), to, rsa, RSA_PKCS1_PADDING);

    //因为二进制的字符串中间可能有 '\0',所以不能用strlen求长度
    array = QByteArray((char*)to, ret).toBase64();

    BIO_free(bio);
    RSA_free(rsa);
    delete[] to;
    return array;

}

QString MainWindow::rsaPrivateDecrypt(QString msg)
{
    BIO* bio = BIO_new_file("private.pem", "r");
    RSA* rsa = RSA_new();
    //获得私钥
    if(PEM_read_bio_RSAPrivateKey(bio, &rsa, NULL, NULL) == NULL)
    {
        qDebug() << "PEM_read_bio_RSAPrivateKey() error" ;
        return QString();
    }

    //解码base64
    QByteArray array = msg.toUtf8();
    array = QByteArray::fromBase64(array);

    int keylen = RSA_size(rsa);
    //使用私钥解密
    unsigned char* to = new unsigned char[keylen];
    int ret = RSA_private_decrypt(array.size(), (unsigned char*)array.data(), to, rsa, RSA_PKCS1_PADDING);

    array = QByteArray((char*)to, ret);

    BIO_free(bio);
    RSA_free(rsa);
    delete[] to;
    return array;
}

bool MainWindow::rsaSignAndVerify()
{
    BIO* bio = BIO_new_file("private.pem", "r");
    RSA* rsa = RSA_new();

    if(PEM_read_bio_RSAPrivateKey(bio, &rsa, NULL, NULL) == NULL)
    {
        qDebug() << "PEM_read_bio_RSAPrivateKey() error" ;
        return false;
    }
    int keylen = RSA_size(rsa);
    unsigned char* sigret = new unsigned char[keylen];
    unsigned int siglen;

    QString msg = "密文长度 == 秘钥长度== 分组的长度";
    QByteArray array = msg.toUtf8();
    RSA_sign(NID_sha224, (unsigned char*)array.data(), array.size(), sigret, &siglen, rsa);

    //转base64
    QString value = QByteArray((char*)sigret, siglen).toBase64();
    //到此签名完成


    // 签名校验
    // 获取公钥
    bio = BIO_new_file("public.pem", "r");
    rsa = RSA_new();
    if(PEM_read_bio_RSAPublicKey(bio, &rsa, NULL, NULL) == NULL)
    {
        qDebug() << "PEM_read_bio_RSAPublicKey() error" ;
        return false;
    }

    //对数据进行base64解码
    QByteArray array1 = QByteArray::fromBase64(value.toUtf8());

    int ret = RSA_verify(NID_sha224, (unsigned char*)array.data(), array.size(), (unsigned char*)array1.data(), array1.size(), rsa);

    return ret == 1;
}

注意事项

  1. 在Qt中需要非常注意类型的转换,QByteArrayQStringstd::stringchar*之间的相互转换

  2. 数字签名的时候注意签名的数据的大小,不能大于密钥长度-11

  3. 密文长度 == 秘钥长度== 分组的长度

  4. 数字签名后得到的是一个二进制串,如果发生了数据中转,需要使用base64

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值