RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,常用于数据的加密和数字签名。在C++中,可以使用OpenSSL库来实现RSA的签名和验签功能。以下是一个简单的示例代码,演示如何使用OpenSSL库进行RSA签名和验签:
示例代码:
```cpp
#include <iostream>
#include <string>
#include <vector>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
// 生成RSA密钥对
RSA* generateRSAKey(int keyLength) {
RSA* rsa = RSA_new();
BIGNUM* bne = BN_new();
unsigned long e = RSA_F4;
if (BN_set_word(bne, e) != 1) {
std::cerr << "Failed to set RSA exponent.\n";
return nullptr;
}
if (RSA_generate_key_ex(rsa, keyLength, bne, NULL) != 1) {
std::cerr << "Failed to generate RSA key pair.\n";
RSA_free(rsa);
BN_free(bne);
return nullptr;
}
BN_free(bne);
return rsa;
}
// RSA签名
std::string rsaSign(RSA* rsa, const std::vector<unsigned char>& data) {
unsigned int siglen;
unsigned char sigbuf[RSA_size(rsa)];
if (RSA_sign(NID_sha256, data.data(), data.size(), sigbuf, &siglen, rsa) != 1) {
std::cerr << "Failed to sign data.\n";
return "";
}
return std::string(reinterpret_cast<char*>(sigbuf), siglen);
}
// RSA验签
bool rsaVerify(RSA* rsa, const std::vector<unsigned char>& data, const std::string& signature) {
int ret = RSA_verify(NID_sha256, data.data(), data.size(), reinterpret_cast<const unsigned char*>(signature.c_str()), signature.length(), rsa);
if (ret != 1) {
std::cerr << "RSA verification failed.\n";
return false;
}
return true;
}
int main() {
// 生成RSA密钥对(实际应用中,应从文件或安全存储中加载)
RSA* rsa = generateRSAKey(2048);
if (!rsa) {
std::cerr << "Failed to generate RSA key pair.\n";
return 1;
}
// 要签名的数据
std::string data = "Hello, RSA!";
std::vector<unsigned char> dataVec(data.begin(), data.end());
// RSA签名
std::string signature = rsaSign(rsa, dataVec);
if (signature.empty()) {
RSA_free(rsa);
return 1;
}
std::cout << "Signature: " << signature << std::endl;
// RSA验签
bool verified = rsaVerify(rsa, dataVec, signature);
if (verified) {
std::cout << "Signature verified successfully.\n";
} else {
std::cerr << "Signature verification failed.\n";
}
RSA_free(rsa);
return 0;
}
注意事项:
安装 OpenSSL 库:确保系统中安装了 OpenSSL 库及其开发包。在 Ubuntu 中可以通过 sudo apt install libssl-dev 安装。
错误处理:示例中使用了简单的错误处理,实际应用中应根据情况增强错误检测和处理,特别是在处理加密和签名时。
密钥管理:在实际应用中,RSA 密钥对的生成和存储需要特别小心,通常会从安全的存储或密钥管理系统中加载和使用密钥。
签名算法:示例中使用了 SHA256 算法进行签名,可以根据需求选择其他哈希算法。
这段代码演示了RSA的基本签名和验签过程。在实际应用中,需要考虑到数据的安全传输、密钥的保护和管理,以及合理的错误处理机制。
不用OpenSSL :
如果你不想使用OpenSSL,完全可以自己实现RSA算法的签名和验签功能。RSA算法本身是公开的,关键在于理解其数学原理并正确地实现。下面我简要介绍一下如何用C++从头实现RSA签名和验签功能。
步骤概述:
生成RSA密钥对:使用大数运算库生成RSA公钥和私钥。
RSA签名:使用私钥对数据进行签名。
RSA验签:使用公钥对签名进行验证。
实现步骤:
1. 大数运算库选择
RSA涉及大数运算,需要使用支持大数的库。可以选择以下库之一:
GMP(GNU Multiple Precision Arithmetic Library)
Crypto++
这些库可以帮助处理大数运算,因为RSA算法中涉及到大整数的加密、解密、签名和验签操作。
2. 生成RSA密钥对
RSA密钥对由公钥和私钥组成。私钥用于签名,公钥用于验签。
```cpp
cpp
// 生成RSA密钥对
std::pair<BigInt, BigInt> generateRSAKeyPair(int keyLength) {
BigInt p = generateLargePrime(keyLength / 2); // 生成大素数 p
BigInt q = generateLargePrime(keyLength / 2); // 生成大素数 q
BigInt n = p * q; // 计算 n = p * q
BigInt phi = (p - 1) * (q - 1); // 计算 φ(n) = (p-1) * (q-1)
BigInt e = generatePublicKeyExponent(phi); // 生成公钥指数 e
BigInt d = modularInverse(e, phi); // 计算私钥 d,使得 (e * d) % phi == 1
return std::make_pair(e, d);
}
3. RSA签名
使用私钥对数据进行签名。
cpp
// RSA签名
std::string rsaSign(const BigInt& privateKey, const std::vector<unsigned char>& data) {
BigInt m = BigInt(data.data(), data.size()); // 将数据转换为大整数 m
BigInt signature = modExp(m, privateKey, n); // 计算签名 s = m^d mod n
return signature.toString(); // 返回签名的字符串表示
}
4. RSA验签
使用公钥对签名进行验证。
cpp
// RSA验签
bool rsaVerify(const BigInt& publicKey, const std::string& signatureStr, const std::vector<unsigned char>& data) {
BigInt signature(signatureStr); // 将签名字符串转换为大整数
BigInt m = BigInt(data.data(), data.size()); // 将数据转换为大整数 m
BigInt decrypted = modExp(signature, publicKey, n); // 计算解密后的值
BigInt original(m); // 原始消息 m
return decrypted == original; // 比较解密后的值与原始消息
}
- 大数运算函数实现
你需要实现一些大数运算函数,如生成大素数、模幂运算(用于RSA的加密、解密和签名)、模逆运算等。这些函数通常是RSA算法实现的核心部分。
注意事项:
大数运算的精度:确保实现的大数运算库支持足够大的数值,以适应RSA算法的需求。
安全性考量:RSA算法的安全性依赖于生成安全的大素数和正确实现算法。
调试和测试:由于RSA算法涉及复杂的数学运算,调试和测试是非常重要的步骤。
总结
通过以上步骤,你可以开始从头实现RSA的签名和验签功能。这需要一定的数学和编程技能,但是理解了RSA的数学原理和正确实现后,你就可以不依赖外部库完整实现RSA功能
每次编译出可执行文件都需要签名可能并不必要,通常是在发布、部署或者升级时才进行签名。签名的目的是确保文件的完整性和来源可信。接下来我会给出一个简单的示例代码,展示如何在C++中使用 OpenSSL 库进行 RSA 数字签名和验证的过程。
签名过程示例(使用 OpenSSL 库):
```cpp
cpp
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
// 函数声明
bool generateRSAKey(RSA *&rsa, int bits);
bool signData(const std::string &data, RSA *rsa, std::string &signature);
bool verifySignature(const std::string &data, const std::string &signature, RSA *rsa);
int main() {
RSA *rsa = nullptr;
std::string data = "Hello, world!";
std::string signature;
// 生成 RSA 密钥对
if (!generateRSAKey(rsa, 2048)) {
std::cerr << "Failed to generate RSA key pair." << std::endl;
return 1;
}
// 签名数据
if (!signData(data, rsa, signature)) {
std::cerr << "Failed to sign data." << std::endl;
RSA_free(rsa);
return 1;
}
// 输出签名结果
std::cout << "Signature: " << signature << std::endl;
// 验证签名
if (verifySignature(data, signature, rsa)) {
std::cout << "Signature is valid." << std::endl;
} else {
std::cout << "Signature is invalid." << std::endl;
}
RSA_free(rsa);
return 0;
}
bool generateRSAKey(RSA *&rsa, int bits) {
BIGNUM *e = BN_new();
RSA *temp_rsa = RSA_new();
// 设置公钥指数 e
if (!BN_set_word(e, RSA_F4)) {
BN_free(e);
return false;
}
// 生成 RSA 密钥对
if (!RSA_generate_key_ex(temp_rsa, bits, e, nullptr)) {
BN_free(e);
RSA_free(temp_rsa);
return false;
}
rsa = temp_rsa;
BN_free(e);
return true;
}
bool signData(const std::string &data, RSA *rsa, std::string &signature) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(data.c_str()), data.length(), hash);
unsigned int sig_len;
unsigned char sig_out[RSA_size(rsa)];
// 使用私钥签名
if (!RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, sig_out, &sig_len, rsa)) {
return false;
}
// 将签名转换为字符串
signature.assign(reinterpret_cast<const char *>(sig_out), sig_len);
return true;
}
bool verifySignature(const std::string &data, const std::string &signature, RSA *rsa) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(data.c_str()), data.length(), hash);
// 将签名字符串转换为 unsigned char*
const unsigned char *sig = reinterpret_cast<const unsigned char *>(signature.c_str());
// 使用公钥验证签名
int result = RSA_verify(NID_sha256, hash, SHA256_DIGEST_LENGTH, sig, signature.length(), rsa);
if (result == 1) {
return true; // 验证通过
} else if (result == 0) {
return false; // 签名不匹配
} else {
return false; // 出现错误
}
}
示例解释:
generateRSAKey:生成 RSA 密钥对的函数。
signData:签名数据的函数,使用 SHA-256 哈希算法和 RSA 私钥。
verifySignature:验证签名的函数,使用 SHA-256 哈希算法和 RSA 公钥。
这段代码演示了如何使用 OpenSSL 库来进行 RSA 签名和验证操作。在实际应用中,你可以根据自己的需要进行调整和扩展,以适应你的具体场景和文件类型。