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;
}

标签: OpenSSL, RSA, 加密, 解密, 公钥, 私钥

添加新评论