OpenSSL RSA 编程详解
OpenSSL RSA 编程详解及代码示例。
RSA PEM 文件格式
1.PEM 私钥格式文件
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
2.PEM 公钥格式文件
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
3.PEM RSAPublicKey 公钥格式文件
-----BEGIN RSA PUBLIC KEY-----
-----END RSA PUBLIC KEY-----
OpenSSL 密钥相关命令
1. 生成密钥
openssl genrsa -out key.pem 1024
-out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密
1024 生成密钥的长度
2.提取 PEM 格式公钥
openssl rsa -in key.pem -pubout -out pubkey.pem
-in 指定输入的密钥文件
-out 指定提取生成公钥的文件(PEM公钥格式)
3.提取 PEM RSA PublicKey 格式公钥
openssl rsa -in key.pem -RSAPublicKey_out -out pubkey.pem
-in 指定输入的密钥文件
-out 指定提取生成公钥的文件(PEM RSAPublicKey格式)
4.公钥加密文件
openssl rsautl -encrypt -in input.file -inkey pubkey.pem -pubin -out output.file
-in 指定被加密的文件
-inkey 指定加密公钥文件
-pubin 表面是用纯公钥文件加密
-out 指定加密后的文件
5. 私钥解密文件
openssl rsautl -decrypt -in input.file -inkey key.pem -out output.file
-in 指定需要解密的文件
-inkey 指定私钥文件
-out 指定解密后的文件
RSA 相关 API
1. 基本数据结构
struct {
BIGNUM *n; // public modulus
BIGNUM *e; // public exponent
BIGNUM *d; // private exponent
BIGNUM *p; // secret prime factor
BIGNUM *q; // secret prime factor
BIGNUM *dmp1; // d mod (p-1)
BIGNUM *dmq1; // d mod (q-1)
BIGNUM *iqmp; // q^-1 mod p
// ...
} RSA;
2. BN 大数系列函数
//新生成一个BIGNUM结构
BIGNUM *BN_new(void);
//释放一个BIGNUM结构,释放完后a=NULL;
void BN_free(BIGNUM *a);
//初始化所有项均为0,一般为BN_ init(&c)
void BN_init(BIGNUM *);
//将a中所有项均赋值为0,但是内存并没有释放
void BN_clear(BIGNUM *a);
//相当与将BN_free和BN_clear综合,要不就赋值0,要不就释放空间。
void BN_clear_free(BIGNUM *a);
//设置大数a为整数w
int BN_set_word(BIGNUM *a, unsigned long w);
//假如大数a能表示为long型,那么返回一个long型数
unsigned long BN_get_word(BIGNUM *a);
//产生一个加密用的强bits的伪随机数
//若top=-1,最高位为0,top=0,最高位为1,top=1,最高位和次高位为1,bottom为真,随机数为偶数
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom);
//将 a 转化为字符串存入to,to的空间必须大于BN_num_bytes(a)
int BN_bn2bin(const BIGNUM *a, unsigned char *to);
//将s中的len位的正整数转化为大数
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
//将大数转化为16进制字符串
char *BN_bn2hex(const BIGNUM *a);
//将大数转化为10进制字符串
char *BN_bn2dec(const BIGNUM *a);
//将16进制字符串转成大数
int BN_hex2bn(BIGNUM **a, const char *str);
//将10进制字符串传成大数
int BN_dec2bn(BIGNUM **a, const char *str);
3. RSA 系列函数
//初始化一个RSA结构
RSA * RSA_new(void);
//释放一个RSA结构
void RSA_free(RSA *rsa);
//RSA私钥产生函数
//产生一个模为num位的密钥对,e为公开的加密指数,一般为65537(0x10001)
RSA *RSA_generate_key(int num, unsigned long e,void (*callback)(int,int,void *), void *cb_arg);
//判断位数函数, 返回RSA模的位数
int RSA_size(const RSA *rsa);
//测试p、q是否为素数
int RSA_check_key(RSA *rsa);
4. PEM 系列函数
//从文件中加载RSAPublicKey格式公钥证书
RSA *PEM_read_RSAPublicKey(FILE *fp, RSA **x, pem_password_cb *cb, void *u);
//从BIO重加载RSAPublicKey格式公钥证书
RSA *PEM_read_bio_RSAPublicKey(BIO *bp, RSA **x, pem_password_cb *cb, void *u);
//输出RSAPublicKey公钥证书到文件
int PEM_write_RSAPublicKey(FILE *fp, RSA *x);
//输出RSAPublicKey公钥证书到BIO
int PEM_write_bio_RSAPublicKey(BIO *bp, RSA *x);
5. RSA 加密 API
int RSA_public_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding);
参数说明:
flen: 要加密信息长度
from: 要加密信息
to: 加密后的信息
padding: 采取的加密方案, 分为: RSA_PKCS1_PADDING, RSA_PKCS1_OAEP_PADDING, RSA_SSLV23_PADDING, RSA_NO_PADDING
6. RSA 解密 API
int RSA_private_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding);
参数说明:
flen: 要解密的信息长度
from: 要解密的信息
to: 解密后的信息
padding: 采取的解密方案
RSA 编程示例
rsasignature.h
#ifndef RSASIGNATURE_H
#define RSASIGNATURE_H
#include "openssl/rsa.h"
#include "openssl/pem.h"
#include "openssl/err.h"
#include <string>
#define RSA_KEY_LENGTH 256
// openssl.exe genrsa -out rsa_private_key.pem 1024
// openssl.exe rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
class RSASignature
{
public:
RSASignature();
// 生成 RSA 私钥公钥
bool generateRSAKey(std::string& priKey, std::string& pubKey);
// 将 PEM 转换为大数字符串(只支持公钥方法,私钥方法需要导出n,e,d,p,q,dmp1,dmq1,iqmp所以这里就不支持了)
bool PublicPemString2HexString(const std::string& key, std::string& modulus, std::string& exponent);
//bool PrivatePemString2HexString(const std::string& key, std::string& modulus, std::string& exponent, std::string& pri_exponent);
// 将大数字符串转换为 PEM 字符串
bool PublicHexString2PemString(const std::string& modulus, const std::string& exponent, std::string& key);
//bool PrivateHexString2PemString(const std::string& modulus, const std::string& exponent, const std::string& pri_exponent, std::string& key);
// 公钥加密
bool RsaPublicEncrypt(const std::string &plainText, const std::string &pubKey, std::string& cipherText);
// 私钥解密
bool RsaPrivateDecrypt(const std::string &cipherText, const std::string &priKey, std::string& plainText);
// 私钥加密
bool RsaPrivateEncrypt(const std::string &plainText, const std::string &priKey, std::string& cipherText);
// 公钥解密
bool RsaPublicDecrypt(const std::string &cipherText, const std::string &pubKey, std::string& plainText);
// 获取错误信息
std::string errorString();
};
#endif // RSASIGNATURE_H
rsasignature.cpp
#include "rsasignature.h"
RSASignature::RSASignature()
{
ERR_load_crypto_strings();
}
bool RSASignature::generateRSAKey(std::string &priKey, std::string &pubKey)
{
bool result = false;
// 生成密钥对
unsigned long e = RSA_3;
BIGNUM *bne = BN_new();
int ret = BN_set_word(bne, e);
RSA *keypair = RSA_new();
if (keypair)
{
ret = RSA_generate_key_ex(keypair, RSA_KEY_LENGTH, bne, NULL);
if (ret == 1)
{
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
if (pri != NULL && pub != NULL)
{
ret = PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
ret = PEM_write_bio_RSAPublicKey(pub, keypair);
// 获取长度
size_t pri_len;
size_t pub_len;
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
// 密钥对读取到字符串
char *pri_key = NULL;
char *pub_key = NULL;
pri_key = (char *)malloc(pri_len + 1);
pub_key = (char *)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
priKey = std::string(pri_key);
pubKey = std::string(pub_key);
free(pri_key);
free(pub_key);
result = true;
}
if (pri)
BIO_free_all(pri);
if (pub)
BIO_free_all(pub);
}
RSA_free(keypair);
}
return result;
}
bool RSASignature::PublicPemString2HexString(const std::string &key, std::string &modulus, std::string &exponent)
{
bool result = false;
BIO *keybio = BIO_new_mem_buf((unsigned char *)key.c_str(), -1);
if (keybio != NULL)
{
RSA* rsa = NULL;
rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
if (rsa)
{
modulus = std::string(BN_bn2hex(rsa->n));
exponent = std::string(BN_bn2hex(rsa->e));
result = true;
RSA_free(rsa);
}
BIO_free_all(keybio);
}
return result;
}
//bool RSASignature::PrivatePemString2HexString(const std::string &key, std::string &modulus, std::string &exponent, std::string &pri_exponent)
//{
// bool result = false;
// BIO *keybio = BIO_new_mem_buf((unsigned char *)key.c_str(), -1);
// if (keybio != NULL)
// {
// RSA* rsa = NULL;
// rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
// if (rsa)
// {
// modulus = std::string(BN_bn2hex(rsa->n));
// exponent = std::string(BN_bn2hex(rsa->e));
// pri_exponent = std::string(BN_bn2hex(rsa->d));
// result = true;
// RSA_free(rsa);
// }
// BIO_free_all(keybio);
// }
// return result;
//}
bool RSASignature::PublicHexString2PemString(const std::string &modulus, const std::string &exponent, std::string &key)
{
bool result = false;
RSA *rsa = RSA_new();
if (rsa)
{
rsa->n = BN_new();
rsa->e = BN_new();
BN_hex2bn(&rsa->n, modulus.c_str());
BN_hex2bn(&rsa->e, exponent.c_str());
BIO *bio = BIO_new(BIO_s_mem());
if (bio != NULL)
{
PEM_write_bio_RSAPublicKey(bio, rsa);
// 获取长度
size_t len = BIO_pending(bio);;
// 密钥对读取到字符串
char *buf = (char *)malloc(len + 1);
BIO_read(bio, buf, len);
buf[len] = '\0';
key = std::string(buf);
free(buf);
BIO_free_all(bio);
result = true;
}
RSA_free(rsa);
}
return result;
}
//bool RSASignature::PrivateHexString2PemString(const std::string &modulus, const std::string &exponent, const std::string& pri_exponent, std::string &key)
//{
// bool result = false;
// RSA *rsa = RSA_new();
// if (rsa)
// {
// BIO *keybio = BIO_new_mem_buf((unsigned char *)modulus.c_str(), -1);
// if (keybio != NULL)
// {
// RSA* rsa1 = NULL;
// rsa1 = PEM_read_bio_RSAPrivateKey(keybio, &rsa1, NULL, NULL);
// if (rsa1)
// {
// rsa->n = BN_new();
// rsa->e = BN_new();
// rsa->d = BN_new();
// rsa->p = BN_new();
// rsa->q = BN_new();
// rsa->dmp1 = BN_new();
// rsa->dmq1 = BN_new();
// rsa->iqmp = BN_new();
// BN_hex2bn(&rsa->n, BN_bn2hex(rsa1->n));
// BN_hex2bn(&rsa->e, BN_bn2hex(rsa1->e));
// BN_hex2bn(&rsa->d, BN_bn2hex(rsa1->d));
// BN_hex2bn(&rsa->p, BN_bn2hex(rsa1->p));
// BN_hex2bn(&rsa->q, BN_bn2hex(rsa1->q));
// BN_hex2bn(&rsa->dmp1, BN_bn2hex(rsa1->dmp1));
// BN_hex2bn(&rsa->dmq1, BN_bn2hex(rsa1->dmq1));
// BN_hex2bn(&rsa->iqmp, BN_bn2hex(rsa1->iqmp));
//qDebug() <<" 1111";
// qDebug() << BN_bn2hex(rsa1->d);
// qDebug() <<" 1111";
// qDebug() << BN_bn2hex(rsa1->p);
//qDebug() <<" 1111";
// qDebug() << BN_bn2hex(rsa1->q);
// qDebug() << BN_bn2hex(rsa1->dmp1);
//qDebug() <<" 1111";
// qDebug() << BN_bn2hex(rsa1->dmq1);
// qDebug() <<" 1111";
// qDebug() << BN_bn2hex(rsa1->iqmp);
//qDebug() <<" ";
// RSA_free(rsa1);
// }
// BIO_free_all(keybio);
// }
// //return result;
// //rsa->n = BN_new();
// //rsa->e = BN_new();
// //rsa->d = BN_new();
// //BN_hex2bn(&rsa->n, modulus.c_str());
// //BN_hex2bn(&rsa->e, exponent.c_str());
// //BN_hex2bn(&rsa->d, pri_exponent.c_str());
// BIO *bio = BIO_new(BIO_s_mem());
// if (bio != NULL)
// {
// PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);
// // 获取长度
// size_t len = BIO_pending(bio);;
// // 密钥对读取到字符串
// char *buf = (char *)malloc(len + 1);
// BIO_read(bio, buf, len);
// buf[len] = '\0';
// key = std::string(buf);
// free(buf);
// BIO_free_all(bio);
// result = true;
// }
// RSA_free(rsa);
// }
// return result;
//}
bool RSASignature::RsaPublicEncrypt(const std::string &plainText, const std::string &pubKey, std::string& cipherText)
{
cipherText.clear();
bool result = false;
BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
if (keybio != NULL)
{
RSA* rsa = NULL;
rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
if (rsa)
{
// 分段加密
// 根据密钥计算出RSA支持加密最大块长度
int rsa_len = RSA_size(rsa);
int rsa_block_len = rsa_len - RSA_PKCS1_PADDING_SIZE;
char *buf = (char *)malloc(rsa_len + 1);
memset(buf, 0, rsa_len + 1);
int from_len = plainText.length();
const char *from = plainText.c_str();
int offset = 0;
while ((from_len - offset) > 0)
{
int len = rsa_block_len;
if ((from_len - offset) < rsa_block_len)
len = (from_len - offset);
// 加密函数
int ret = RSA_public_encrypt(len, (const unsigned char*)(from+offset), (unsigned char*)buf, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
{
cipherText += std::string(buf, ret);
result = true;
}
else
{
result = false;
break;
}
offset += len;
}
// 释放内存
free(buf);
RSA_free(rsa);
}
BIO_free_all(keybio);
}
return result;
}
bool RSASignature::RsaPrivateDecrypt(const std::string &cipherText, const std::string &priKey, std::string &plainText)
{
plainText.clear();
bool result = false;
BIO *keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);
if (keybio != NULL)
{
RSA* rsa = NULL;
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if (rsa)
{
// 分段加密
// 根据密钥计算出RSA支持加密最大块长度
int rsa_len = RSA_size(rsa);
int rsa_block_len = rsa_len;
char *buf = (char *)malloc(rsa_len + 1);
memset(buf, 0, rsa_len + 1);
int from_len = cipherText.length();
const char *from = cipherText.c_str();
int offset = 0;
while ((from_len - offset) > 0)
{
int len = rsa_block_len;
if ((from_len - offset) < rsa_block_len)
len = (from_len - offset);
// 解密函数
int ret = RSA_private_decrypt(len, (const unsigned char*)(from+offset), (unsigned char*)buf, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
{
plainText += std::string(buf, ret);
result = true;
}
else
{
result = false;
break;
}
offset += len;
}
// 释放内存
free(buf);
RSA_free(rsa);
}
BIO_free_all(keybio);
}
return result;
}
bool RSASignature::RsaPrivateEncrypt(const std::string &plainText, const std::string &priKey, std::string &cipherText)
{
cipherText.clear();
bool result = false;
BIO *keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);
if (keybio != NULL)
{
RSA* rsa = NULL;
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if (rsa)
{
// 分段加密
// 根据密钥计算出RSA支持加密最大块长度
int rsa_len = RSA_size(rsa);
int rsa_block_len = rsa_len - RSA_PKCS1_PADDING_SIZE;
char *buf = (char *)malloc(rsa_len + 1);
memset(buf, 0, rsa_len + 1);
int from_len = plainText.length();
const char *from = plainText.c_str();
int offset = 0;
while ((from_len - offset) > 0)
{
int len = rsa_block_len;
if ((from_len - offset) < rsa_block_len)
len = (from_len - offset);
// 加密函数
int ret = RSA_private_encrypt(len, (const unsigned char*)(from+offset), (unsigned char*)buf, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
{
cipherText += std::string(buf, ret);
result = true;
}
else
{
result = false;
break;
}
offset += len;
}
// 释放内存
free(buf);
RSA_free(rsa);
}
BIO_free_all(keybio);
}
return result;
}
bool RSASignature::RsaPublicDecrypt(const std::string &cipherText, const std::string &pubKey, std::string &plainText)
{
plainText.clear();
bool result = false;
BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
if (keybio != NULL)
{
RSA* rsa = NULL;
rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
if (rsa)
{
// 分段加密
// 根据密钥计算出RSA支持加密最大块长度
int rsa_len = RSA_size(rsa);
int rsa_block_len = rsa_len;
char *buf = (char *)malloc(rsa_len + 1);
memset(buf, 0, rsa_len + 1);
int from_len = cipherText.length();
const char *from = cipherText.c_str();
int offset = 0;
while ((from_len - offset) > 0)
{
int len = rsa_block_len;
if ((from_len - offset) < rsa_block_len)
len = (from_len - offset);
// 解密函数
int ret = RSA_public_decrypt(len, (const unsigned char*)(from+offset), (unsigned char*)buf, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
{
plainText += std::string(buf, ret);
result = true;
}
else
{
result = false;
break;
}
offset += len;
}
// 释放内存
free(buf);
RSA_free(rsa);
}
BIO_free_all(keybio);
}
return result;
}
std::string RSASignature::errorString()
{
const char *err = ERR_reason_error_string(ERR_get_error());
return err;
}