使用 openssl 进行 RSA 加解密
在我之前的一篇博客中 RSA 公钥加密原理 中, 对 RSA 非对称加密原理做了简单的阐述。这篇博客主要聊如何使用 OPENSSL 进行密钥对的生成,以及非对称加解密。
一. 生成密钥对
在 OPENSSL 中, RSA 是一个很重要的结构体。它的定义在 rsa_locl.h 中,面包含了在原理中提到的所有重要的变量 随机质数 p, q, 公钥指数 e, 私钥指数 d, 以及模数 n
1 | struct rsa_st { |
生成密钥函数:
1 | int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); |
-
bits密钥的规模(modulus)。小于 1028 位的密钥是不安全的,小于 512 则会返回 0 -
e公开的指数。它应该是一个奇数(odd number), 一般是3, 17或65537 -
cb生成大随机数的回调函数。一般使用 NULL 即可, 默认为BN_GENCB_call()
生成公私钥并写入文件的代码示例:
1 |
|
二. 公私钥加解密
公私钥加解密两个步骤, 一是载入密钥, 二是加解密。
载入密钥使用 API :
1 | PEM_read_RSAPublicKey() |
当载入失败时返回 NULL。
而加解密中两个重要的 API 是:
1 | int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding); |
-
flen是输入数据的长度,必须小于等于modulus = RSA_size(rsa)个字节, 且和参数padding相关。当 flen 不满足要求时,将会出现"data too small for key size"或"data too large for key size"错误。 flen 与 padding 的对应关系如下:-
RSA_PKCS1_PADDING, flen <= modulus - 11 -
RSA_SSLV23_PADDING, flen <= modulus - 11 -
RSA_NO_PADDING, flen = modulus -
RSA_PKCS1_OAEP_PADDING, flen <= modulus - 41 (2 倍的 SHA1 长度 + 1)
-
-
padding是填充模式,当 flen 满足上述关系时,将会进行填充:-
RSA_PKCS1_PADDING, 最常用的模式,使用 PKCS #1 v1.5 标准,前两字节填充0x00, 0x02,接着的modulus - flen - 3字节使用随机非 '\0'值填充,接着填充一个字节的0x00, 然后是from数据 -
RSA_SSLV23_PADDING, 前两个字节填充0x00,0x02, 接着的modulus - flen - 3 - 8字节填充随机非 '\0'值,然后填充 8 个0x03, 接着填充一个字节的0x00,然后是from数据 -
RSA_NO_PADDING, 不需要填充 -
RSA_PKCS1_OAEP_PADDING, 前20字节使用 SHA1 填充, 接着填充至少 20 字节的0x00, 最后填充0x01,接着是from数据
-
如图所示:

公私钥加解密示例:
1 |
|
三. Tips
1. 在 Windows 下运行出现崩溃 "no OPENSSL_Applink"
多半是因为代码运行库不匹配导致的。在Windows 中,运行时库有这几种:
-
Single Threaded
/ML- MS VC++ often defaults to this for the release version of a new project. -
Debug Single Threaded
/MLd- MS VC++ often defaults to this for the debug version of a new project. -
Multithreaded
/MT -
Debug Multithreaded
/MTd -
Multithreaded DLL
/MD- OpenSSL defaults to this. -
Debug Multithreaded DLL
/MDd
运行库不一致可能导致程序崩溃(通常是在进行IO操作时)。这种情况下可以重新编译 OPENSSL, 或者修改程序的运行库。更简单的办法,可以尝试添加一个文件引用:
1 |