QT使用OpenSSL的接口实现RSA2的签名和验签
QT使用OpenSSL的接口实现RSA2的签名和验签
加密和签名在RSA加密算法中是两个不同的概念,虽然它们都涉及RSA密钥对的使用,但目的和应用场景有所不同。
- 加密 (encrypt/decrypt):
- 加密:使用接收方的公钥对数据进行加密,只有拥有相应私钥的接收方才能解密数据。
- 解密:使用接收方的私钥对加密数据进行解密,从而获得原始数据。
- 加密用于保护数据的机密性,确保只有授权的人能够解密和读取数据。
- 签名 (sign/verify):
- 签名:使用发送方的私钥对数据进行签名,产生一个数字签名。
- 验证签名:使用发送方的公钥对数字签名进行验证,以确保数据的完整性和认证发送方身份。
- 签名用于验证数据的完整性和真实性,确保数据在传输过程中没有被篡改。
在RSA加密算法中,加密和签名使用了相同的RSA密钥对,但是应用场景和目的不同。加密是为了保护数据的机密性,而签名是为了验证数据的完整性和真实性。
所以,虽然在技术上可以使用RSA密钥对进行加密和签名,但是在实际应用中,通常会根据具体的需求和安全要求来选择是使用加密还是签名功能。
#include <QCoreApplication>
#include <QDebug>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
// 加密函数
QByteArray encryptData(const QByteArray &data, RSA *publicKey) {
int rsaLen = RSA_size(publicKey);
unsigned char *encryptBuffer = new unsigned char[rsaLen];
int result = RSA_public_encrypt(data.size(), reinterpret_cast<const unsigned char*>(data.constData()), encryptBuffer, publicKey, RSA_PKCS1_PADDING);
if (result == -1) {
qWarning() << "Encryption failed.";
return QByteArray();
}
return QByteArray(reinterpret_cast<char*>(encryptBuffer), result);
}
// 解密函数
QByteArray decryptData(const QByteArray &data, RSA *privateKey) {
int rsaLen = RSA_size(privateKey);
unsigned char *decryptBuffer = new unsigned char[rsaLen];
int result = RSA_private_decrypt(data.size(), reinterpret_cast<const unsigned char*>(data.constData()), decryptBuffer, privateKey, RSA_PKCS1_PADDING);
if (result == -1) {
qWarning() << "Decryption failed.";
return QByteArray();
}
return QByteArray(reinterpret_cast<char*>(decryptBuffer), result);
}
RSA* createRSAFromPEM(const char* key, bool isPublicKey) {
BIO *bio = BIO_new_mem_buf((void*)key, -1);
if (bio == NULL) {
qWarning() << "Failed to create BIO";
return NULL;
}
RSA *rsa = NULL;
if (isPublicKey) {
rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL);
} else {
rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
}
BIO_free(bio);
return rsa;
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
#if 0
// 初始化 OpenSSL
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
// 生成RSA密钥对
RSA *rsaKeyPair = RSA_generate_key(2048, RSA_F4, NULL, NULL);
if (!rsaKeyPair) {
qWarning() << "Failed to generate RSA key pair.";
return 1;
}
// 获取公钥
BIO *bioPub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPublicKey(bioPub, rsaKeyPair);
char *pubKeyBuffer;
long pubKeyLength = BIO_get_mem_data(bioPub, &pubKeyBuffer);
qDebug() << "Public Key: " << QByteArray(pubKeyBuffer, pubKeyLength);
// 获取私钥
BIO *bioPriv = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(bioPriv, rsaKeyPair, NULL, NULL, 0, NULL, NULL);
char *privKeyBuffer;
long privKeyLength = BIO_get_mem_data(bioPriv, &privKeyBuffer);
qDebug() << "Private Key: " << QByteArray(privKeyBuffer, privKeyLength);
// 待签名的数据
const char *data = "Hello, world!";
int dataSize = strlen(data);
// 签名
unsigned char signature[256]; // 2048 bit key size
unsigned int signatureLength;
if (RSA_sign(NID_sha256, (const unsigned char*)data, dataSize, signature, &signatureLength, rsaKeyPair) != 1) {
qWarning() << "Failed to sign data.";
return 1;
}
qDebug() << "Signature: " << QByteArray(reinterpret_cast<char*>(signature), signatureLength).toBase64();
// 验证签名
if (RSA_verify(NID_sha256, (const unsigned char*)data, dataSize, signature, signatureLength, rsaKeyPair) != 1) {
qDebug() << "Signature is invalid!";
} else {
qDebug() << "Signature is valid!";
}
// 释放资源
RSA_free(rsaKeyPair);
BIO_free(bioPub);
BIO_free(bioPriv);
EVP_cleanup();
#endif
/*
支付宝的RSA2签名算法,支付宝开放平台SDK(https://docs.open.alipay.com/54)封装的签名工具类进行签名,一般的流程如下:
签名 (RSA2 Sign):
使用商户私钥对数据进行签名,生成数字签名。
将数字签名与数据一起发送给支付宝或其他服务端。
验证签名 (RSA2 Verify):
支付宝或服务端使用商户提供的公钥对接收到的数据和签名进行验证。
验证签名的有效性,以确保数据的完整性和真实性。
在这种情况下,商户通常会使用支付宝提供的公钥对支付宝返回的数据进行验签,以确保数据的完整性和真实性,防止数据被篡改
*/
// 商户提供的公钥和私钥
const char *pubKeyStr = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArtwVzIpLvzzGxQ074EYCIyNj0k16YukrF27rEu7JFndms6FWWzLwX3QxTiQSN6tfbEwV5K67H5cCc4yesOJWdVA3ft023+V2I3hDS2jdRvQU5Rwju4mUisi12/aE5c1N6jkxpjzDGiUNYdwHEHzj+9awBlMusJ3B2U1fZDO5hoU39bxWJ9xgsEOmKT1VJBYeteIAyf0jwyeDBxIfw15NU+H31QRS4xbCDJ4DPKn3jjpvfBd/6h6fFT1Yj/FHbvzfabRZjnEAciNhUj+cOw6O5bYKnyNcNt1bjvhGBSVc3p+FaUKfkdGwNOA+haXraN+F+BBLuyTapSReawQo/BErIQIDAQAB\n-----END PUBLIC KEY-----";
const char *privKeyStr = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCu3BXMiku/PMbFDTvgRgIjI2PSTXpi6SsXbusS7skWd2azoVZbMvBfdDFOJBI3q19sTBXkrrsflwJzjJ6w4lZ1UDd+3Tbf5XYjeENLaN1G9BTlHCO7iZSKyLXb9oTlzU3qOTGmPMMaJQ1h3AcQfOP71rAGUy6wncHZTV9kM7mGhTf1vFYn3GCwQ6YpPVUkFh614gDJ/SPDJ4MHEh/DXk1T4ffVBFLjFsIMngM8qfeOOm98F3/qHp8VPViP8Udu/N9ptFmOcQByI2FSP5w7Do7ltgqfI1w23VuO+EYFJVzen4VpQp+R0bA04D6Fpeto34X4EEu7JNqlJF5rBCj8ESshAgMBAAECggEAStXGPpOxd1b7ern/NizAHWm3/vlJt6sy1gSSdrfbN9JCEf6qhr12QmPn9hlZ8plVbXPiqsxdKVfnpKw5/lnfxrVeCt2B7rC1rth5dHyctxEfIC663Dg1anAb5NfMaM1E20k/BnZayYWyBH+2RkgtCksHaq2O/eeGXwnOGYRJklgZnO8inITJiSnnvuVbN9W+JvHCTcuHjKp/YOAXBJGAWDsuBbIaaeYAlXhrzSeUvBlQSljp7JZyauQ3hTXDZzAJ9HYergWMWkg/iCo6iOw5NulkNtiWosTO+A8wWHFgN+vok8itIDyXMpNCcZBz8EPDug/dBH1L2yPp+nln+YGvQQKBgQD7cf7BwgtlTqtEeLDtqMrhqCqcU+e8N4w7DHj2VzuYFnpTIHXqn4SWSP0gjF/os04NtHcEMIX8l8Ihtl4iu6ivvcvTjf0s1/gD2BD8m08EHACi9bf4if/3Q7tBTzgiRasFbS9WNDprycp9uKweB+zByPp+rYahJoWJyUd3M0U5CwKBgQCyBvJNdtW+8Ph27jOrHyMGLK07SIpUfGZz1O0PYrYoqj33WnOJKIz2y26jQiXS8nPvi/XgAEYiQkbD+uVIXGgJXoJFH8+78i/Ne42q/GtCniqR3SUrWRUD8GvRrLXyzytnmX1yLJSSHeICw7/Gp48iQCN2tOFlz/bX2/lsPrSAAwKBgGoACJHOJ9exbmoTJyNJgR3YMv5sMMkb8bYC8AuJgsn+z9qzWIJsdQyWAH/0LYp/7GvCpFnTyuhNYb2sj8q8qcRMktzAgvagpSGZuK+FGa51z57jT4crRgkLOKmzp8pq7EoBWW9R3T8Ldp3BeG3AkYKwI0m8BYFyJ+GKROJvbsM5AoGAA1J73RQ1ou2ORXHmhu/60FevF+cfpbn4k3rKvbnC2nlq1J3cgBfAoa5kLynB2PDrVvIOsZJvvJ3uAiRBeRs4Wcxos++HCePYHoaKu0Ego0qeUsCEvA1ahgtLh8soThKtpa5ImAPa9esW16RdhNCFrEb0Inf3qNW7roWNXwbAiY8CgYEA7B4NzyR47a2/QBHU7y20JpgLTkhwCHQRsmdqcuLXKQxM3+Twe3HHy7VV9JmL6XBo3yPP9ArmpbiP8z0XGainXR977eAmBALX55HBWvoNU0xzASKbMjEIHjOMa7KHl3cA1OkQMNHfk5x3gFt8io9ChTlMdbQEES3elg3ITkELnNI=\n-----END PRIVATE KEY-----";
// 从字符串中加载公钥和私钥
RSA *publicKey = createRSAFromPEM(pubKeyStr, true);
RSA *privateKey = createRSAFromPEM(privKeyStr, false);
// 加密和解密测试
QByteArray originalData = "Hello, RSA2!";
QByteArray encryptedData = encryptData(originalData, publicKey);
QByteArray decryptedData = decryptData(encryptedData, privateKey);
qDebug() << "Original Data: " << originalData;
qDebug() << "Encrypted Data: " << encryptedData.toBase64();
qDebug() << "Decrypted Data: " << decryptedData;
// 待签名的数据
const char *data = "Hello, world!";
int dataSize = strlen(data);
// 签名
unsigned char signature[256]; // 2048 bit key size
unsigned int signatureLength;
if (RSA_sign(NID_sha256, (const unsigned char*)data, dataSize, signature, &signatureLength, privateKey) != 1) {
qWarning() << "Failed to sign data.";
return 1;
}
qDebug() << "Signature: " << QByteArray(reinterpret_cast<char*>(signature), signatureLength).toBase64();
// 验证签名
if (RSA_verify(NID_sha256, (const unsigned char*)data, dataSize, signature, signatureLength, publicKey) != 1) {
qDebug() << "Signature is invalid!";
} else {
qDebug() << "Signature is valid!";
}
// 释放资源
RSA_free(publicKey);
RSA_free(privateKey);
EVP_cleanup();
return app.exec();
}