OpenSSL之RSA用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenSSL之RSA用法相关的知识,希望对你有一定的参考价值。

参考技术A 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目录中。

这个结构定义了RSA内部数据信息。主要字段含义:
version —— 版本。
meth —— RSA运算抽象方法集合。
n,e,d,p,q,dmp1,dmq1,iqmp —— 密钥相关的大数。

这个结构定义了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填充方式,取值:

其中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。

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

输出:

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

输出:
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]

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

输出:
ret:1
RSA_sign() ret:1
sign 64
4ec0af099c49646b72fda88a4fb11e8deb3898da9c3f611a5f25f05d9d005631858239bbb732cd5060dbc975363fc1b9cdfdc5a04554115a916f06f98163189f
RSA_verify() ret:1

OpenSSL之genrsa&rsa&req&x509子命令用法

参考技术A genrsa、rsa、req、x509子命令主要用于RSA密钥的生成和处理,以及证书的申请和制作。

genrsa子命令主要用于生成RSA私钥。

openssl genrsa [args] [numbits]

-des 使用des cbc模式对私钥文件进行加密。
-des3 使用des3 cbc模式对私钥文件进行加密。
-idea 使用idea cbc模式对私钥文件进行加密。
-aes128, -aes192, -aes256 使用aes cbc模式对私钥文件进行加密。
-out file 指定输出私钥文件名。
-f4 指定F4做为E值,默认。
-3 指定3做为E值。
-seed arg 指定cbc的随机种子。
-rand file:file 指定随机数种子文件。

rsa子命令主要用于处理RSA公私钥文件。

openssl rsa [options] <infile >outfile

-inform arg 指定输入文件格式,可以为DER或PEM,默认为PEM。
-outform arg 指定输出文件格式,可以为DER或PEM,默认为PEM。
-in arg 指定输入文件。
-out arg 指定输出文件。
-pubin 指定输入文件为公钥,默认为私钥。
-pubout 指定输出文件为公钥,默认为私钥。
-passin arg 指定输入文件的口令保护来源。
-passout arg 指定输出文件的口令保护来源。
-des 使用des cbc模式对输出文件进行加密。
-des3 使用des3 cbc模式对输出文件进行加密。
-idea 使用idea cbc模式对输出文件进行加密。
-aes128, -aes192, -aes256 使用aes cbc模式对输出文件进行加密。
-text 打印密钥信息。
-noout 不向控制台打印密钥信息。
-modulus 打印RSA的模数信息。
-check 检查RSA私钥的有效性。

req子命令主要用于创建证书请求文件。

openssl req [options] <infile >outfile

-inform arg 指定输入文件格式,可以为DER或PEM,默认为PEM。
-outform arg 指定输出文件格式,可以为DER或PEM,默认为PEM。
-in arg 指定输入文件。
-out arg 指定输出文件。
-new 创建新的证书请求文件。
-key file 指定创建证书请求的私钥文件。
-keyform arg 指定创建证书请求的私钥文件的格式,可以为DER或PEM,默认为PEM。
-passin arg 指定私钥文件的口令保护来源。
-verify 校验证书请求文件的主体签名是否有效。
-noout 不打印证书请求信息。
-text 文本打印证书请求文件。
-modulus 输出证书请求的模数信息。
-subject 输出证书请求主体信息。
-subj arg 设置或修改证书请求的主体信息。
-multivalue-rdn 设置或修改证书请求的主体信息时,允许多RDN格式。
-utf8 输入字符为utf8编码,默认输入为ASCII编码。
-[digest] 指定创建证书请求的摘要算法。
-pubkey 提取证书请求文件中的公钥。

x509命令主要用于创建、修改x509证书。

openssl x509 [options] <infile >outfile

-inform arg 指定输入文件格式,可以为DER或PEM,默认为PEM。
-outform arg 指定输出文件格式,可以为DER或PEM,默认为PEM。
-keyform arg 指定私钥文件格式,可以为DER或PEM,默认为PEM。
-CAform arg 指定CA文件格式,可以为DER或PEM,默认为PEM。
-CAkeyform arg 指定CA私钥文件格式,可以为DER或PEM,默认为PEM。
-in arg 指定输入文件,默认为标准输入。
-out arg 指定输出文件,默认为标准输出。
-passin arg 指定私钥文件的口令保护来源。
-pubkey 提取持有者公钥。
-trustout 提取可信任证书。
-noout 不向控制台输出证书信息。
-text 打印证书信息。
-C 以C证言格式打印证书信息。
-serial 打印证书的序列号。
-subject_hash 打印持有者的摘要。
-issuer_hash 打印颁发者的摘要。
-hash 等同于-subject_hash。
-subject 打印持有者的DN信息。
-issuer 打印颁发者的DN信息。
-email 打印email地址。
-startdate 打印证书的生效时间。
-enddate 打印证书的失效时间。
-dates 打印证书的有效期。
-purpose 打印证书用途。
-modulus 打印证书中的RSA模数。
-fingerprint 打印证书微缩图。
-alias 打印证书别名。
-ocspid 打印持有者和公钥的OCSP摘要值。
-clrtrust 清除证书附加项里所有有关用途允许的内容。
-clrreject 清除证书附加项里所有有关用途禁止的内容。
-addtrust arg 添加证书附加项里所有有关用途允许的内容。
-addreject arg 添加证书附加项里所有有关用途禁止的内容。
-setalias arg 设置证书别名。
-days arg 设置证书有效期,默认30天。
-checkend arg 检查证书在给定的arg秒后是否还有效。
-signkey arg 指定自签名私钥文件。
-x509toreq 根据证书来生成证书请求,需要指定签名私钥。
-req 输入文件为证书请求。
-CA arg 设置CA文件,必须为PEM格式。
-CAkey arg 设置CA私钥文件,必须为PEM格式。
-CAcreateserial 创建序列号文件。
-CAserial arg 指定序列号文件。
-set_serial 设置证书序列号。
-<dgst> 指定使用的摘要算法,缺省为MD5。

从自己编写程序实现以上子命令的角度考虑,涉及RSA生成、存取API,涉及PEM读写,以及X509相关的数据格式的理解,总体来说要求还是挺高的,有兴趣的朋友可以尝试下。

以上是关于OpenSSL之RSA用法的主要内容,如果未能解决你的问题,请参考以下文章

openssl rsa/pkey

OpenSSL之随机数用法

2.openssl rsa/pkey

Openssl命令行用法简介

非对称加密算法之RSA介绍及OpenSSL中RSA常用函数使用举例

6.openssl rsautl和openssl pkeyutl