OpenSSL之RSA用法

Published on with 0 views and 0 comments

RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制 。在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK 。

正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长,一般推荐使用1024位。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要 。

RSA算法是一个广泛使用的公钥算法。其密钥包括公钥和私钥。它能用于数字签名、身份认证以及密钥交换。RSA密钥长度一般使用1024位或者更高。RSA密钥信息主要包括:

n:模数

e:公钥指数

d:私钥指数

p:最初的大素数

q:最初的大素数

其中,公钥为n和e;私钥为n和d。

本文假设你已经安装好了OpenSSL,并且持有一份1.1.1的源码。

RSA相关的头文件在rsa.h中、源文件在crypto/rsa目录中。

主要结构:

struct rsa_st {
    /*
     * The first parameter is used to pickup errors where this is passed
     * instead of an EVP_PKEY, it is set to 0
     */
    int pad;
    int32_t version;
    const RSA_METHOD *meth;
    /* functional reference if 'meth' is ENGINE-provided */
    ENGINE *engine;
    BIGNUM *n;
    BIGNUM *e;
    BIGNUM *d;
    BIGNUM *p;
    BIGNUM *q;
    BIGNUM *dmp1;
    BIGNUM *dmq1;
    BIGNUM *iqmp;
    /* for multi-prime RSA, defined in RFC 8017 */
    STACK_OF(RSA_PRIME_INFO) *prime_infos;
    /* If a PSS only key this contains the parameter restrictions */
    RSA_PSS_PARAMS *pss;
    /* be careful using this if the RSA structure is shared */
    CRYPTO_EX_DATA ex_data;
    CRYPTO_REF_COUNT references;
    int flags;
    /* Used to cache montgomery values */
    BN_MONT_CTX *_method_mod_n;
    BN_MONT_CTX *_method_mod_p;
    BN_MONT_CTX *_method_mod_q;
    /*
     * all BIGNUM values are actually in the following data, if it is not
     * NULL
     */
    char *bignum_data;
    BN_BLINDING *blinding;
    BN_BLINDING *mt_blinding;
    CRYPTO_RWLOCK *lock;
};
typedef struct rsa_st RSA;

这个结构定义了RSA内部数据信息。主要字段含义:

version —— 版本。

meth —— RSA运算抽象方法集合。

n,e,d,p,q,dmp1,dmq1,iqmp —— 密钥相关的大数。

struct rsa_meth_st {
    char *name;
    int (*rsa_pub_enc) (int flen, const unsigned char *from,
                        unsigned char *to, RSA *rsa, int padding);
    int (*rsa_pub_dec) (int flen, const unsigned char *from,
                        unsigned char *to, RSA *rsa, int padding);
    int (*rsa_priv_enc) (int flen, const unsigned char *from,
                         unsigned char *to, RSA *rsa, int padding);
    int (*rsa_priv_dec) (int flen, const unsigned char *from,
                         unsigned char *to, RSA *rsa, int padding);
    /* Can be null */
    int (*rsa_mod_exp) (BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
    /* Can be null */
    int (*bn_mod_exp) (BIGNUM *r, const BIGNUM *a, const BIGNUM *p, 
                       const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
    /* called at new */
    int (*init) (RSA *rsa);
    /* called at free */
    int (*finish) (RSA *rsa);
    /* RSA_METHOD_FLAG_* things */
    int flags;
    /* may be needed! */
    char *app_data;
    /*  
     * New sign and verify functions: some libraries don't allow arbitrary
     * data to be signed/verified: this allows them to be used. Note: for
     * this to work the RSA_public_decrypt() and RSA_private_encrypt() should
     * *NOT* be used RSA_sign(), RSA_verify() should be used instead.
     */
    int (*rsa_sign) (int type,
                     const unsigned char *m, unsigned int m_length,
                     unsigned char *sigret, unsigned int *siglen,
                     const RSA *rsa);
    int (*rsa_verify) (int dtype, const unsigned char *m, 
                       unsigned int m_length, const unsigned char *sigbuf,
                       unsigned int siglen, const RSA *rsa);
    /*  
     * If this callback is NULL, the builtin software RSA key-gen will be
     * used. This is for behavioural compatibility whilst the code gets
     * rewired, but one day it would be nice to assume there are no such
     * things as "builtin software" implementations.
     */
    int (*rsa_keygen) (RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
    int (*rsa_multi_prime_keygen) (RSA *rsa, int bits, int primes,
                                   BIGNUM *e, BN_GENCB *cb);
};
typedef struct rsa_meth_st RSA_METHOD;

这个结构定义了RSA内部各种运算抽象方法集合。主要字段含义:

name —— 名称描述。

rsa_pub_enc —— 公钥加密方法。

rsa_pub_dec —— 公钥解密方法。

rsa_priv_enc —— 私钥加密方法。

rsa_priv_dec —— 公钥解密方法。

rsa_sign —— 签名方法。

rsa_verify —— 验签方法。

rsa_keygen —— 生成密钥对方法。

在1.1.1中,大多数的数据结构已经不再向使用者开放,从封装的角度来看,这是更合理的。如果你在头文件中找不到结构定义,不妨去源码中搜一搜。

主要函数:

RSA *RSA_new(void);

生成一个RSA密钥结构,采用默认的rsa_pkcs1_ossl_meth方法。

void RSA_free(RSA *r);

释放RSA结构。

RSA *RSA_generate_key(int bits, unsigned long e, void (*callback) (int, int, void *), void *cb_arg);

生成RSA密钥(旧版本)。

bits为密钥位数,e为公钥指数。

callback为密钥生成过程中的干预回调函数,通常传入NULL。cb_arg为回调参数。

成功返回RSA指针,失败返回NULL。

int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);

生成RSA密钥(新版本)。

rsa为RSA对象指针。bits为密钥位置,e为公钥指数的大数形式指针。cb为干预回调函数,通常传入NULL。

成功返回1,失败返回0。

关于公钥指数e,主要有两个取值:

define RSA_3 0x3L

define RSA_F4 0x10001L

RSA *RSAPublicKey_dup(RSA *rsa);

复制RSA公钥部分。

成功返回RSA指针,失败返回NULL。

RSA *RSAPrivateKey_dup(RSA *rsa);

复制RSA私钥部分。

成功返回RSA指针,失败返回NULL。

int RSA_bits(const RSA *rsa);

获取RSA密钥位数。

int RSA_size(const RSA *rsa);

获取RSA密钥长度。

int RSA_check_key(const RSA *);

int RSA_check_key_ex(const RSA *, BN_GENCB *cb);

检查RSA的有效性,必须为完整的密钥对。

成功返回1,失败返回0。

int RSA_print(BIO *bp, const RSA *r, int offset);

int RSA_print_fp(FILE *fp, const RSA *r, int offset);

将RSA信息输出到bp/fp中,off为输出信息在bp/fp中的偏移量,比如是屏幕bp/fp,则表示打印信息的位置离左边屏幕边缘的距离。

int RSA_public_encrypt(int flen, const unsigned char *from,

unsigned char *to, RSA *rsa, int padding);

RSA公钥加密。

成功返回密文的长度,失败返回-1。

int RSA_public_decrypt(int flen, const unsigned char *from,

unsigned char *to, RSA *rsa, int padding);

RSA公钥解密。

成功返回明文的长度,失败返回-1。

int RSA_private_encrypt(int flen, const unsigned char *from,

unsigned char *to, RSA *rsa, int padding);

RSA私钥加密。

成功返回密文的长度,失败返回-1。

int RSA_private_decrypt(int flen, const unsigned char *from,

unsigned char *to, RSA *rsa, int padding);

RSA私钥解密。

成功返回明文的长度,失败返回-1。

关于padding填充方式,取值:

# define RSA_PKCS1_PADDING       1
# define RSA_SSLV23_PADDING      2
# define RSA_NO_PADDING          3
# define RSA_PKCS1_OAEP_PADDING  4
# define RSA_X931_PADDING        5
/* EVP_PKEY_ only */
# define RSA_PKCS1_PSS_PADDING   6

其中PKCS1填充大小为11字节,所以加密明文长度必须不大于(密钥大小-11字节)。

define RSA_PKCS1_PADDING_SIZE 11

int RSA_sign(int type, const unsigned char *m, unsigned int m_length,

unsigned char *sigret, unsigned int *siglen, RSA *rsa);

对数据m生成RSA签名,生成的签名长度与key的长度相同,如512位密钥生成64字节签名。

type指定摘要算法的NID,如NID_sha1。

成功返回1,失败返回0。

int RSA_verify(int type, const unsigned char *m, unsigned int m_length,

const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);

对数据m验证RSA签名。

type指定摘要算法的NID,如NID_sha1。

成功返回1,失败返回0。

公私钥的编码转换:

以下函数在x509.h中定义:

int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa)

{

return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);

}

将RSA公钥转换为DER编码,并写入到bp抽象IO中。

成功返回1,失败返回0。

RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa)

{

return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);

}

从bp抽象IO中读取DER编码,并转换为rsa结构私钥。

成功返回有效指定,失败返回NULL。

int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa)

{

return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);

}

将RSA公钥转换为DER编码,并写入到bp抽象IO中。

成功返回1,失败返回0。

RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa)

{

return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);

}

从bp抽象IO中读取DER编码,并转换为rsa结构公钥。

成功返回有效指定,失败返回NULL。

使用举例1:

下面这个例子演示了RSA密钥对的生成、公私钥的复制、公钥加密和私钥解密的用法。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <openssl/rsa.h>
#include <openssl/err.h>

namespace dakuang {}

int main(int argc, char* argv[])
{
    ERR_load_RSA_strings();

    RSA* pRSA = RSA_generate_key(512, RSA_3, NULL, NULL);
    RSA_print_fp(stdout, pRSA , 0);
    RSA_free(pRSA);

    pRSA = RSA_new();
    BIGNUM* pBNe = BN_new();
    BN_set_word(pBNe, RSA_3);
    int ret = RSA_generate_key_ex(pRSA, 512, pBNe, NULL);
    printf("RSA_generate_key_ex() ret:%d \n", ret);
    BN_free(pBNe);
    RSA_print_fp(stdout, pRSA , 0);

    RSA* pRSApub = RSAPublicKey_dup(pRSA);
    printf("copy pub key:%p \n", pRSApub);
    RSA_print_fp(stdout, pRSApub , 0);
    RSA_free(pRSApub);
    RSA* pRSApri = RSAPrivateKey_dup(pRSA);
    printf("copy pri key:%p \n", pRSApri);
    RSA_print_fp(stdout, pRSApri , 0);
    RSA_free(pRSApri);

    int bits = RSA_bits(pRSA);
    printf("bits:%d \n", bits);
    int bytes = RSA_size(pRSA);
    printf("bytes:%d \n", bytes);

    ret = RSA_check_key(pRSA);
    printf("RSA_check_key() ret:%d \n", ret);

    char sText[] = "1234567890";

    unsigned char* pCipher = (unsigned char*)malloc(bytes);
    ret = RSA_public_encrypt(strlen(sText), (const unsigned char*)sText, pCipher, pRSA, RSA_PKCS1_PADDING);
    printf("RSA_public_encrypt() ret:%d \n", ret);
    if (ret <= 0)
    {
        unsigned long err = ERR_get_error();
        printf("err:[%ld] \n", err);
        char sBuf[128] = {0};
        char* pErrStr = ERR_error_string(err, sBuf);
        printf("errstr:[%s] \n", pErrStr);
    }

    unsigned char* pText = (unsigned char*)malloc(bytes);
    ret = RSA_private_decrypt(ret, (const unsigned char*)pCipher, pText, pRSA, RSA_PKCS1_PADDING);
    printf("RSA_private_decrypt() ret:%d \n", ret);
    if (ret > 0)
    {
        printf("text:[%s] \n", pText);
    }

    free(pCipher);
    free(pText);

    RSA_free(pRSA);

    return 0;
}

输出:

RSA Private-Key: (512 bit, 2 primes)
modulus:
    00:9f:d4:b7:53:c9:22:30:8d:52:31:13:67:61:ce:
    12:bc:25:85:44:94:0e:87:e2:b9:8c:87:dd:ca:d0:
    df:1c:84:51:c7:ac:ec:a3:3f:2b:48:81:74:18:22:
    9a:c2:a8:11:03:8c:19:b6:a6:45:2d:81:d4:18:65:
    bb:90:59:e6:d5
publicExponent: 3 (0x3)
privateExponent:
    6a:8d:cf:8d:30:c1:75:b3:8c:20:b7:9a:41:34:0c:
    7d:6e:58:d8:62:b4:5a:97:26:5d:af:e9:31:e0:94:
    bd:ac:7d:e2:9e:a3:b3:4c:e9:23:41:bf:3c:ca:4d:
    3e:ee:b6:f5:36:1c:7a:9c:2d:70:e3:20:94:53:b6:
    e9:0a:13:eb
prime1:
    00:d3:69:55:a1:b4:24:1d:11:56:18:3e:b4:bf:06:
    23:05:69:d2:12:78:1e:b5:45:47:8c:3f:8a:6e:02:
    48:d5:4d
prime2:
    00:c1:8a:69:55:62:27:b0:82:48:bc:fe:3e:67:de:
    1e:f9:29:e8:dc:86:9d:4b:be:e5:96:fa:5d:bb:30:
    81:f3:a9
exponent1:
    00:8c:f0:e3:c1:22:c2:be:0b:8e:ba:d4:78:7f:59:
    6c:ae:46:8c:0c:50:14:78:d8:da:5d:7f:b1:9e:ac:
    30:8e:33
exponent2:
    00:81:06:f0:e3:96:c5:20:56:db:28:a9:7e:ef:e9:
    69:fb:71:45:e8:59:be:32:7f:43:b9:fc:3e:7c:cb:
    01:4d:1b
coefficient:
    00:cb:09:a1:95:b6:64:0c:d0:50:50:58:cb:20:fd:
    bc:7c:e6:fb:56:22:73:75:34:7b:44:6d:a5:94:87:
    59:8f:58
RSA_generate_key_ex() ret:1 
RSA Private-Key: (512 bit, 2 primes)
modulus:
    00:ac:3b:05:ad:53:48:42:fb:8e:a0:52:53:29:71:
    3b:30:a6:47:74:99:7b:9f:94:48:93:92:1f:57:78:
    01:07:6c:db:bd:34:f0:c9:35:42:7e:20:c1:ec:94:
    7d:0b:cc:c7:70:56:52:87:cc:04:66:30:4b:06:fb:
    49:ee:78:eb:af
publicExponent: 3 (0x3)
privateExponent:
    72:d2:03:c8:e2:30:2c:a7:b4:6a:e1:8c:c6:4b:7c:
    cb:19:84:f8:66:52:6a:62:db:0d:0c:14:e4:fa:ab:
    5a:47:7a:64:2a:7b:1c:27:0b:c2:37:a0:7f:52:fc:
    53:17:3e:ba:9f:cb:0b:4d:5b:94:0f:38:f1:97:67:
    eb:d7:a3:ab
prime1:
    00:d8:79:81:07:43:58:8f:a7:ab:db:04:bf:e5:a0:
    03:35:7c:13:76:5b:22:2c:de:e0:c7:29:4b:66:65:
    e3:aa:ef
prime2:
    00:cb:ad:74:30:db:a2:21:33:21:76:28:d8:1c:ef:
    26:b3:dc:53:2b:9b:b5:ce:29:38:ae:73:4c:c7:a6:
    d1:cb:41
exponent1:
    00:90:51:00:af:82:3b:0a:6f:c7:e7:58:7f:ee:6a:
    ac:ce:52:b7:a4:3c:c1:73:3f:40:84:c6:32:44:43:
    ed:1c:9f
exponent2:
    00:87:c8:f8:20:92:6c:16:22:16:4e:c5:e5:68:9f:
    6f:22:92:e2:1d:12:79:34:1b:7b:1e:f7:88:85:19:
    e1:32:2b
coefficient:
    00:bd:69:e1:82:71:0e:e3:e6:bb:c3:55:2a:10:f7:
    b1:26:1e:c2:9a:d7:44:9f:88:be:aa:3e:7d:d1:7c:
    c0:94:ba
copy pub key:0x203f770 
RSA Public-Key: (512 bit)
Modulus:
    00:ac:3b:05:ad:53:48:42:fb:8e:a0:52:53:29:71:
    3b:30:a6:47:74:99:7b:9f:94:48:93:92:1f:57:78:
    01:07:6c:db:bd:34:f0:c9:35:42:7e:20:c1:ec:94:
    7d:0b:cc:c7:70:56:52:87:cc:04:66:30:4b:06:fb:
    49:ee:78:eb:af
Exponent: 3 (0x3)
copy pri key:0x203f770 
RSA Private-Key: (512 bit, 2 primes)
modulus:
    00:ac:3b:05:ad:53:48:42:fb:8e:a0:52:53:29:71:
    3b:30:a6:47:74:99:7b:9f:94:48:93:92:1f:57:78:
    01:07:6c:db:bd:34:f0:c9:35:42:7e:20:c1:ec:94:
    7d:0b:cc:c7:70:56:52:87:cc:04:66:30:4b:06:fb:
    49:ee:78:eb:af
publicExponent: 3 (0x3)
privateExponent:
    72:d2:03:c8:e2:30:2c:a7:b4:6a:e1:8c:c6:4b:7c:
    cb:19:84:f8:66:52:6a:62:db:0d:0c:14:e4:fa:ab:
    5a:47:7a:64:2a:7b:1c:27:0b:c2:37:a0:7f:52:fc:
    53:17:3e:ba:9f:cb:0b:4d:5b:94:0f:38:f1:97:67:
    eb:d7:a3:ab
prime1:
    00:d8:79:81:07:43:58:8f:a7:ab:db:04:bf:e5:a0:
    03:35:7c:13:76:5b:22:2c:de:e0:c7:29:4b:66:65:
    e3:aa:ef
prime2:
    00:cb:ad:74:30:db:a2:21:33:21:76:28:d8:1c:ef:
    26:b3:dc:53:2b:9b:b5:ce:29:38:ae:73:4c:c7:a6:
    d1:cb:41
exponent1:
    00:90:51:00:af:82:3b:0a:6f:c7:e7:58:7f:ee:6a:
    ac:ce:52:b7:a4:3c:c1:73:3f:40:84:c6:32:44:43:
    ed:1c:9f
exponent2:
    00:87:c8:f8:20:92:6c:16:22:16:4e:c5:e5:68:9f:
    6f:22:92:e2:1d:12:79:34:1b:7b:1e:f7:88:85:19:
    e1:32:2b
coefficient:
    00:bd:69:e1:82:71:0e:e3:e6:bb:c3:55:2a:10:f7:
    b1:26:1e:c2:9a:d7:44:9f:88:be:aa:3e:7d:d1:7c:
    c0:94:ba
bits:512 
bytes:64 
RSA_check_key() ret:1 
RSA_public_encrypt() ret:64 
RSA_private_decrypt() ret:10 
text:[1234567890]

使用举例2:

下面这个例子演示了公私钥的分开保存、读取,以及使用公私钥加解密。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/x509.h>

namespace dakuang {}

int main(int argc, char* argv[])
{
    ERR_load_RSA_strings();

    RSA* pRSA = RSA_new();
    BIGNUM* pBNe = BN_new();
    BN_set_word(pBNe, RSA_3);
    int ret = RSA_generate_key_ex(pRSA, 512, pBNe, NULL);
    printf("RSA_generate_key_ex() ret:%d \n", ret);
    BN_free(pBNe);

    BIO* pBIOpri = BIO_new_file("rsa.key","w");
    BIO* pBIOpub = BIO_new_file("rsa.pub","w");
    ret = i2d_RSAPrivateKey_bio(pBIOpri, pRSA);
    printf("i2d_RSAPrivateKey_bio() ret:%d \n", ret);
    ret = i2d_RSAPublicKey_bio(pBIOpub, pRSA);
    printf("i2d_RSAPublicKey_bio() ret:%d \n", ret);
    BIO_free(pBIOpri);
    BIO_free(pBIOpub);

    RSA* pRSApri = RSA_new();
    RSA* pRSApub = RSA_new();
    BIO* pBIOpri2 = BIO_new_file("rsa.key","r");
    BIO* pBIOpub2 = BIO_new_file("rsa.pub","r");
    d2i_RSAPrivateKey_bio(pBIOpri2, &pRSApri);
    d2i_RSAPublicKey_bio(pBIOpub2, &pRSApub);
    BIO_free(pBIOpri2);
    BIO_free(pBIOpub2);

    int bytes = RSA_size(pRSApri);
    printf("copy' private key size:%d \n", bytes);
    int bytes2 = RSA_size(pRSApub);
    printf("copy' public key size:%d \n", bytes2);

    char sText[] = "1234567890";

    unsigned char* pCipher = (unsigned char*)malloc(bytes);
    ret = RSA_public_encrypt(strlen(sText), (const unsigned char*)sText, pCipher, pRSApub, RSA_PKCS1_PADDING);
    printf("RSA_public_encrypt() ret:%d \n", ret);
    if (ret <= 0)
    {
        unsigned long err = ERR_get_error();
        printf("err:[%ld] \n", err);
        char sBuf[128] = {0};
        char* pErrStr = ERR_error_string(err, sBuf);
        printf("errstr:[%s] \n", pErrStr);
    }

    unsigned char* pText = (unsigned char*)malloc(bytes);
    ret = RSA_private_decrypt(ret, (const unsigned char*)pCipher, pText, pRSApri, RSA_PKCS1_PADDING);
    printf("RSA_private_decrypt() ret:%d \n", ret);
    if (ret > 0)
    {
        printf("text:[%s] \n", pText);
    }
    free(pCipher);
    free(pText);

    RSA_free(pRSApri);
    RSA_free(pRSApub);
    RSA_free(pRSA);

    return 0;
}

输出:

RSA_generate_key_ex() ret:1

i2d_RSAPrivateKey_bio() ret:1

i2d_RSAPublicKey_bio() ret:1

copy' private key size:64

copy' public key size:64

RSA_public_encrypt() ret:64

RSA_private_decrypt() ret:10

text:[1234567890]

使用举例3:

下面这个例子演示了签名的生成和验证操作。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/objects.h>

namespace dakuang {}

void printHex(const unsigned char* pBuf, int nLen)
{
    for (int i = 0; i < nLen; ++i)
    {
        printf("%02x", pBuf[i]);
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
    ERR_load_RSA_strings();

    RSA* pRSA = RSA_new();
    BIGNUM* pBNe = BN_new();
    BN_set_word(pBNe, RSA_3);
    int ret = RSA_generate_key_ex(pRSA, 512, pBNe, NULL);
    printf("ret:%d \n", ret);
    BN_free(pBNe);

    char sData[] = "1234567890";
    char sSign[512] = {0};
    unsigned int nSignLen = 512;
    ret = RSA_sign(NID_sha1, (unsigned char *)sData, 10, (unsigned char *)sSign, &nSignLen, pRSA);
    printf("RSA_sign() ret:%d \n", ret);
    printf("sign %d \n", nSignLen);
    printHex((const unsigned char*)sSign, nSignLen);

    //sSign[0] = 0;
    ret = RSA_verify(NID_sha1, (unsigned char *)sData, 10, (unsigned char *)sSign, nSignLen, pRSA);
    printf("RSA_verify() ret:%d \n", ret);

    RSA_free(pRSA);

    return 0;
}

输出:

ret:1
RSA_sign() ret:1
sign 644ec0af099c49646b72fda88a4fb11e8deb3898da9c3f611a5f25f05d9d005631858239bbb732cd5060dbc975363fc1b9cdfdc5a04554115a916f06f98163189f
RSA_verify() ret:1

标题:OpenSSL之RSA用法
作者:woyehua
地址:https://blog.stormbirds.cn/articles/2022/01/12/1641966802915.html