RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。本文介绍如何使用openssl命令和C代码实现基础的RSA加/解密和签名/验签功能。
一、openssl命令实现RSA加解密
1、生成私钥和公钥
- 生成私钥
openssl genrsa -out private.key 2048 #生成私钥
- 使用私钥生成公钥
openssl rsa -pubout -in private.key -out public.key #私钥生成公钥
2、签名、验签
- 使用private.key私钥签名data.txt,生成data.sign
openssl rsautl -sign -inkey private.key -keyform PEM -in data.txt -out data.sign #签名
- 使用公钥验签verify.key
openssl rsautl -verify -inkey public.key -pubin -in data.sign #验签
注意:执行生成密钥对和验签命令时,一定要注意文件名后面是否有空格符或tab符,否则会出现"No such file or directory"的报错
可以看到验签后,打印信息与签名前的文件内容相同,签名、验签测试OK。
3、加密、解密
- 使用公钥加密 data.txt 生成 data.encrypt
openssl rsautl -encrypt -pubin -inkey public.key -in data.txt -out data.encrypt
注意:每次用公钥加密生成的加密文件内容都会变化
- 使用私钥解密 data.encrypt
openssl rsautl -decrypt -inkey private.key -in data.encrypt
如果要存到文件,解密命令后面加 "-out data.decrypt"
4、其他openssl命令
- 从certificate.crt证书提取公钥到public_key.pem
openssl x509 -pubkey -noout -in certificate.crt > public_key.pem
- 直接使用证书验签(从证书获取公钥,使用公钥验签)
openssl rsautl -verify -inkey certificate.crt -certin -in data.sign
二、C语言实现RSA非对称加解密
下面使用的密钥对openssl命令生成的 private.key 和 public.key
1、签名、验签
1.1 C代码实现
代码下载链接:https://download.csdn.net/download/hinewcc/89484338
- openssl_rsa.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <error.h>
#include "openssl_rsa.h"void rsa_init(void)
{printf("rsa init ... \n");OpenSSL_add_all_algorithms();
}/*
*****************************************************************************************
* 函 数 名: rsa_sign
* 功能说明: RSA使用私钥签名
* 形 参: key : 私钥
* file_in : 输入需要签名的文件
* file_out : 签名后生成的文件
* 返 回 值: 0:成功, 其他:失败
*****************************************************************************************
*/
int rsa_sign(const char *key, const char *file_in, const char *file_out)
{int ret = -1;int keysize = 0;RSA *rsa = NULL;BIO *in = NULL, *out = NULL;unsigned char *rsa_in = NULL, *rsa_out = NULL;int rsa_inlen = 0, rsa_outlen = 0, len = 0;/* 从私钥提取 RSA */FILE *fp = fopen(key, "r");if (NULL == fp) {perror("Open Key Error: \n");return -1;}rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL,NULL);if (!rsa) {perror("EVP_PKEY_get1_RSA Error: \n");goto error;}/* 打开file_in文件内容,创建file_out文件 */in = BIO_new_file(file_in, "rb");if (NULL == in) {printf("BIO_new_file: open source file fail\n");goto error;}out = BIO_new_file(file_out, "wb");if (NULL == out) {printf("BIO_new_file: open file_out file fail\n");goto error;}keysize = RSA_size(rsa);if (keysize < 0) {printf("RSA_size key size is %d\n", keysize);goto error;}rsa_in =(unsigned char *)OPENSSL_malloc(keysize * 2);if (rsa_in == NULL){perror("OPENSSL_malloc ras in fail\n");goto error;}rsa_out =(unsigned char *)OPENSSL_malloc(keysize);if (rsa_out == NULL){perror("OPENSSL_malloc ras out fail\n");goto error;}rsa_inlen = BIO_read(in, rsa_in, keysize * 2);if (rsa_inlen < 0) {perror("BIO_read Fail: \n");goto error;}/* 使用私钥验签,写入file_out文件 */len = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, RSA_PKCS1_PADDING);if (len < 0) {perror("RSA_encrypt Fail: \n");goto error;}rsa_outlen = BIO_write(out, rsa_out, len);if (rsa_outlen < 0) {perror("BIO_write Fail: \n");goto error;}ret = 0;printf("sign success!\n");error:if (NULL != fp) fclose(fp);if (rsa) RSA_free(rsa);if (in) BIO_free(in);if (out) BIO_free_all(out);if (rsa_in) OPENSSL_free(rsa_in);if (rsa_out) OPENSSL_free(rsa_out);return ret;
}/*
*****************************************************************************************
* 函 数 名: rsa_verify
* 功能说明: RSA使用公钥验签
* 形 参: key : 私钥
* file_in : 输入需要签名的文件
* file_out : 签名后生成的文件
* 返 回 值: 0:成功, 其他:失败
*****************************************************************************************
*/
int rsa_verify(const char *public, const char *file_in,const char *file_out)
{int ret = ERR_NONE;int keysize = 0;RSA* rsa = NULL;BIO* in = NULL, *out = NULL;unsigned char* rsa_in = NULL, *rsa_out = NULL;int rsa_inlen = 0, rsa_outlen = 0, len = 0;/* 从公钥提取 RSA */FILE *fp = fopen(public, "rb");if (NULL == fp) {perror("Open Key Error: \n");return -1;}if(NULL == (rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL,NULL))){printf( "PEM_read_RSAPrivateKey error\n");fclose(fp);goto error;}/* 打开file_in文件内容,创建file_out文件 */in = BIO_new_file(file_in, "rb");if (NULL == in) {printf("BIO_new_file: open file_in file fail\n");ret = ERR_KEY_EN_OPEN;goto error;}out = BIO_new_file(file_out, "wb");if (NULL == out) {printf("BIO_new_file: open file_out file fail\n");ret = ERR_KEY_DE_OPEN;goto error;}keysize = RSA_size(rsa);if (keysize < 0) {printf("RSA_size key size is %d\n", keysize);ret = ERR_RSA_SIZE;goto error;}rsa_in = (unsigned char *)OPENSSL_malloc(keysize * 2);if (rsa_in == NULL){perror("OPENSSL_malloc ras in fail\n");ret = ERR_RSAIN_MALLOC;goto error;}rsa_out = (unsigned char *)OPENSSL_malloc(keysize);if (rsa_out == NULL) {perror("OPENSSL_malloc ras out fail\n");ret = ERR_RSAOUT_MALLOC;goto error;}// Read ENCYRPTED_FILErsa_inlen = BIO_read(in, rsa_in, keysize * 2);if (rsa_inlen < 0) {perror("BIO_read Fail: \n");ret = ERR_KEY_EN_R;goto error;}/* 使用公钥验签,写入file_out文件 */len = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, RSA_PKCS1_PADDING);if (len < 0) {perror("Decrypt Fail: \n");ret = ERR_KEY_DE;goto error;}// Write DECRYPTED_FILErsa_outlen = BIO_write(out, rsa_out, len);if (rsa_outlen < 0) {perror("BIO_write Fail: \n");ret = ERR_KEY_DE_W;goto error;}printf("verify success!\n");error:if (NULL != fp) fclose(fp);if (rsa) RSA_free(rsa);if (in) BIO_free(in);if (out) BIO_free_all(out);if (rsa_in) OPENSSL_free(rsa_in);if (rsa_out) OPENSSL_free(rsa_out);return ret;
}
- openssl_rsa.h
#ifndef _OPENSSL_RSA_H_
#define _OPENSSL_RSA_H_#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/err.h>#define ERR_NONE 0// DECRYPT
#define ERR_EMMC_KEY_OPEN 0x01
#define ERR_EMMC_KEY_WRITE 0x02
#define ERR_EMMC_KEY_SIZE 0x03
#define ERR_FILE_KEY_OPEN 0x03
#define ERR_FILE_KEY_READ 0x04
#define ERR_KEY_EN_OPEN 0x05
#define ERR_KEY_DE_OPEN 0x06
#define ERR_RSA_SIZE 0x07
#define ERR_RSAIN_MALLOC 0x08
#define ERR_RSAOUT_MALLOC 0x09
#define ERR_KEY_DE 0x0A
#define ERR_KEY_EN_R 0x0B
#define ERR_KEY_DE_W 0x0C
#define ERR_AES_TK 0x0D
#define ERR_FILE_EN_OPEN 0x0E
#define ERR_FILE_DE_INIT 0x0F
#define ERR_FILE_DE_UPDATE 0x10
#define ERR_FILE_DE_OPEN 0x11
#define ERR_FILE_DE_W 0x12
#define ERR_FILE_DE_FINAL 0x13void rsa_init(void);
int rsa_sign(const char *key, const char *file_in, const char *file_out);
int rsa_verify(const char *public, const char *file_in,const char *file_out);#endif
- main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl_rsa.h"int main(int argc, char **argv)
{int i;char acOpt[96] = {0};char acKey[96] = {0};char acFile_in[96] = {0};char acFile_Out[96] = {0};if (argc != 5) {printf("usage: ./app -sign|-verify key in out");return -1;}strcpy(acKey, argv[2]);strcpy(acFile_in, argv[3]);strcpy(acFile_Out, argv[4]);printf("key: %s\n", acKey);printf("input file: %s\n", acFile_in);printf("output file: %s\n", acFile_Out);if (strcmp(argv[1], "-sign") == 0) {rsa_sign(acKey, acFile_in, acFile_Out);} else if (strcmp(argv[1], "-verify") == 0) {rsa_verify(acKey, acFile_in, acFile_Out);} else {printf("usage: ./app -sign|-verify key in out");return -1;}return 0;
}
1.2 编译
$ gcc -o rsa_test main.c openssl_rsa.c -lcrypto
编译生成可执行程序 rsa_test
1.3 测试验证
$ ./rsa_test -sign private.key file.txt file.sign #签名
使用private.key私钥对file.txt文件签名,生成file.sign
$ ./rsa_test -verify public.key file.sign out.txt #验签
使用public.key公钥对file.sign签名文件验签,将输出的文件打印出来,内容与签名前的file.txt相同,验证OK。
2、加密、解密
2.1 C代码实现
代码下载链接:https://download.csdn.net/download/hinewcc/89484462
加密、解密 与 签名、验签 的代码基本相同,差异地方如下:
1)公钥能实现验签/加密功能,加密、验签调用的函数不同:
- RSA_public_decrypt:用公钥解密(验签)
- RSA_public_encrypt:用公钥加密
2)私钥能实现签名/解密功能,签名、解密调用的函数不同:
- RSA_private_encrypt:用私钥加密(签名)
- RSA_private_decrypt:用私钥解密
openssl_rsa.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <error.h>
#include "openssl_rsa.h"void rsa_init(void)
{printf("rsa init ... \n");OpenSSL_add_all_algorithms();
}/*
*****************************************************************************************
* 函 数 名: rsa_decrypt
* 功能说明: RSA使用私钥解密
* 形 参: key : 私钥
* file_in : 输入需要签名的文件
* file_out : 签名后生成的文件
* 返 回 值: 0:成功, 其他:失败
*****************************************************************************************
*/
int rsa_decrypt(const char *key, const char *file_in, const char *file_out)
{int ret = -1;int keysize = 0;RSA *rsa = NULL;BIO *in = NULL, *out = NULL;unsigned char *rsa_in = NULL, *rsa_out = NULL;int rsa_inlen = 0, rsa_outlen = 0, len = 0;/* 从私钥提取 RSA */FILE *fp = fopen(key, "r");if (NULL == fp) {perror("Open Key Error: \n");return -1;}rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL,NULL);if (!rsa) {perror("EVP_PKEY_get1_RSA Error: \n");goto error;}/* 打开file_in文件内容,创建file_out文件 */in = BIO_new_file(file_in, "rb");if (NULL == in) {printf("BIO_new_file: open source file fail\n");goto error;}out = BIO_new_file(file_out, "wb");if (NULL == out) {printf("BIO_new_file: open file_out file fail\n");goto error;}keysize = RSA_size(rsa);if (keysize < 0) {printf("RSA_size key size is %d\n", keysize);goto error;}rsa_in =(unsigned char *)OPENSSL_malloc(keysize * 2);if (rsa_in == NULL){perror("OPENSSL_malloc ras in fail\n");goto error;}rsa_out =(unsigned char *)OPENSSL_malloc(keysize);if (rsa_out == NULL){perror("OPENSSL_malloc ras out fail\n");goto error;}rsa_inlen = BIO_read(in, rsa_in, keysize * 2);if (rsa_inlen < 0) {perror("BIO_read Fail: \n");goto error;}/* 使用私钥解密,写入file_out文件 */len = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, RSA_PKCS1_PADDING);if (len < 0) {perror("RSA_encrypt Fail: \n");goto error;}rsa_outlen = BIO_write(out, rsa_out, len);if (rsa_outlen < 0) {perror("BIO_write Fail: \n");goto error;}ret = 0;printf("sign success!\n");error:if (NULL != fp) fclose(fp);if (rsa) RSA_free(rsa);if (in) BIO_free(in);if (out) BIO_free_all(out);if (rsa_in) OPENSSL_free(rsa_in);if (rsa_out) OPENSSL_free(rsa_out);return ret;
}/*
*****************************************************************************************
* 函 数 名: rsa_encrypt
* 功能说明: RSA使用公钥加密
* 形 参: key : 公钥
* file_in : 输入需要签名的文件
* file_out : 签名后生成的文件
* 返 回 值: 0:成功, 其他:失败
*****************************************************************************************
*/
int rsa_encrypt(const char *public, const char *file_in,const char *file_out)
{int ret = ERR_NONE;int keysize = 0;RSA* rsa = NULL;BIO* in = NULL, *out = NULL;unsigned char* rsa_in = NULL, *rsa_out = NULL;int rsa_inlen = 0, rsa_outlen = 0, len = 0;/* 从公钥提取 RSA */FILE *fp = fopen(public, "rb");if (NULL == fp) {perror("Open Key Error: \n");return -1;}if(NULL == (rsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL,NULL))){printf( "PEM_read_RSAPrivateKey error\n");fclose(fp);goto error;}/* 打开file_in文件内容,创建file_out文件 */in = BIO_new_file(file_in, "rb");if (NULL == in) {printf("BIO_new_file: open file_in file fail\n");ret = ERR_KEY_EN_OPEN;goto error;}out = BIO_new_file(file_out, "wb");if (NULL == out) {printf("BIO_new_file: open file_out file fail\n");ret = ERR_KEY_DE_OPEN;goto error;}keysize = RSA_size(rsa);if (keysize < 0) {printf("RSA_size key size is %d\n", keysize);ret = ERR_RSA_SIZE;goto error;}rsa_in = (unsigned char *)OPENSSL_malloc(keysize * 2);if (rsa_in == NULL){perror("OPENSSL_malloc ras in fail\n");ret = ERR_RSAIN_MALLOC;goto error;}rsa_out = (unsigned char *)OPENSSL_malloc(keysize);if (rsa_out == NULL) {perror("OPENSSL_malloc ras out fail\n");ret = ERR_RSAOUT_MALLOC;goto error;}// Read ENCYRPTED_FILErsa_inlen = BIO_read(in, rsa_in, keysize * 2);if (rsa_inlen < 0) {perror("BIO_read Fail: \n");ret = ERR_KEY_EN_R;goto error;}/* 使用公钥加密,写入file_out文件 */len = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, RSA_PKCS1_PADDING);if (len < 0) {perror("Decrypt Fail: \n");ret = ERR_KEY_DE;goto error;}// Write DECRYPTED_FILErsa_outlen = BIO_write(out, rsa_out, len);if (rsa_outlen < 0) {perror("BIO_write Fail: \n");ret = ERR_KEY_DE_W;goto error;}printf("verify success!\n");error:if (NULL != fp) fclose(fp);if (rsa) RSA_free(rsa);if (in) BIO_free(in);if (out) BIO_free_all(out);if (rsa_in) OPENSSL_free(rsa_in);if (rsa_out) OPENSSL_free(rsa_out);return ret;
}
openssl_rsa.h
#ifndef _OPENSSL_RSA_H_
#define _OPENSSL_RSA_H_#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/pem.h>
#include <openssl/err.h>#define ERR_NONE 0// DECRYPT
#define ERR_EMMC_KEY_OPEN 0x01
#define ERR_EMMC_KEY_WRITE 0x02
#define ERR_EMMC_KEY_SIZE 0x03
#define ERR_FILE_KEY_OPEN 0x03
#define ERR_FILE_KEY_READ 0x04
#define ERR_KEY_EN_OPEN 0x05
#define ERR_KEY_DE_OPEN 0x06
#define ERR_RSA_SIZE 0x07
#define ERR_RSAIN_MALLOC 0x08
#define ERR_RSAOUT_MALLOC 0x09
#define ERR_KEY_DE 0x0A
#define ERR_KEY_EN_R 0x0B
#define ERR_KEY_DE_W 0x0C
#define ERR_AES_TK 0x0D
#define ERR_FILE_EN_OPEN 0x0E
#define ERR_FILE_DE_INIT 0x0F
#define ERR_FILE_DE_UPDATE 0x10
#define ERR_FILE_DE_OPEN 0x11
#define ERR_FILE_DE_W 0x12
#define ERR_FILE_DE_FINAL 0x13void rsa_init(void);
int rsa_decrypt(const char *key, const char *file_in, const char *file_out);
int rsa_encrypt(const char *public, const char *file_in,const char *file_out);#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl_rsa.h"int main(int argc, char **argv)
{int i;char acOpt[96] = {0};char acKey[96] = {0};char acFile_in[96] = {0};char acFile_Out[96] = {0};if (argc != 5) {printf("usage: ./app -encrypt|-decrypt key in out");return -1;}strcpy(acKey, argv[2]);strcpy(acFile_in, argv[3]);strcpy(acFile_Out, argv[4]);printf("key: %s\n", acKey);printf("input file: %s\n", acFile_in);printf("output file: %s\n", acFile_Out);if (strcmp(argv[1], "-encrypt") == 0) { //加密rsa_encrypt(acKey, acFile_in, acFile_Out);} else if (strcmp(argv[1], "-decrypt") == 0) {rsa_decrypt(acKey, acFile_in, acFile_Out);} else {printf("usage: ./app -encrypt|-decrypt key in out");return -1;}printf("success!!!\n");return 0;
}
2.2 编译
$ gcc -o rsa_test main.c openssl_rsa.c -lcrypto
2.3 测试过程
同上,不再赘述