700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > MacOS下使用C语言基于openssl库进行RSA加密解密

MacOS下使用C语言基于openssl库进行RSA加密解密

时间:2018-09-27 06:38:54

相关推荐

MacOS下使用C语言基于openssl库进行RSA加密解密

MacOS下使用C语言基于openssl库进行RSA加密解密

1 安装openssl并生成密钥

首先当然要安装openssl(这里记得看一下安装路径,应该是/usr/local/Cellar/openssl@3之类的):

brew install openssl

安装完了以后执行:

cd /usr/local/includeln -s ../opt/openssl/include/openssl .

创建项目,生成公钥私钥:

openssl genrsa -out rsa_private_key.pem 1024openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

2 编写RSA加密解密代码

编写test.c文件:

// RSA 加密 ///#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <openssl/rsa.h>#include <openssl/pem.h>#include <openssl/err.h>#include <stdbool.h>#define PATH_TO_PRIVATE_KEY "rsa_private_key.pem"#define PATH_TO_PUBLIC_KEY "rsa_public_key.pem"#define BUFFSIZE 1024char *my_encrypt(char *str, char *path_key); //加密char *my_decrypt(char *str, char *path_key); //解密int main(void){char *original_text = "I hate coding!";char *ciphertext, *plaintext;printf("original_text is :%s\n", original_text);//1.加密ciphertext = my_encrypt(original_text, PATH_TO_PUBLIC_KEY);printf("ciphertext is :%s\n", ciphertext);//2.解密plaintext = my_decrypt(ciphertext, PATH_TO_PRIVATE_KEY);printf("plaintext is :%s\n", plaintext);if(ciphertext)free(ciphertext);if(plaintext)free(plaintext);return 0;}//加密char *my_encrypt(char *str, char *path_key){char *p_en = NULL;RSA *p_rsa = NULL;FILE *file = NULL;int rsa_len = 0; //flen为源文件长度, rsa_len为秘钥长度// printf("文件名:%s\n", path_key);//1.打开秘钥文件if((file = fopen(path_key, "rb")) == NULL){perror("fopen() rsa_public_key error \n ");goto End;}//2.从公钥中获取 加密的秘钥if((p_rsa = PEM_read_RSA_PUBKEY(file, NULL,NULL,NULL )) == NULL){ERR_print_errors_fp(stdout);goto End;}//3.获取秘钥的长度rsa_len = RSA_size(p_rsa);//4.为加密后的内容 申请空间(根据秘钥的长度+1)p_en = (char *)malloc(rsa_len + 1);if(!p_en){perror("malloc() error\n");goto End;}memset(p_en, 0, rsa_len + 1);//5.对内容进行加密if(RSA_public_encrypt(rsa_len, (unsigned char*)str, (unsigned char*)p_en, p_rsa, RSA_NO_PADDING) < 0){perror("RSA_public_encrypt() error\n");goto End;}End://6.释放秘钥空间, 关闭文件if(p_rsa) RSA_free(p_rsa);if(file)fclose(file);return p_en;}//解密char *my_decrypt(char *str, char *path_key){char *p_de = NULL;RSA *p_rsa = NULL;FILE *file = NULL;int rsa_len = 0;// printf("文件名:%s\n", path_key);//1.打开秘钥文件file = fopen(path_key, "rb");if(!file){perror("fopen() rsa_private_key error \n ");goto End;}//2.从私钥中获取 解密的秘钥if((p_rsa = PEM_read_RSAPrivateKey(file, NULL,NULL,NULL )) == NULL){ERR_print_errors_fp(stdout);goto End;}//3.获取秘钥的长度,rsa_len = RSA_size(p_rsa);//4.为加密后的内容 申请空间(根据秘钥的长度+1)p_de = (char *)malloc(rsa_len + 1);if(!p_de){perror("malloc() error \n");goto End;}memset(p_de, 0, rsa_len + 1);//5.对内容进行加密if(RSA_private_decrypt(rsa_len, (unsigned char*)str, (unsigned char*)p_de, p_rsa, RSA_NO_PADDING) < 0){perror("RSA_public_encrypt() error \n");goto End;}End://6.释放秘钥空间, 关闭文件if(p_rsa) RSA_free(p_rsa);if(file)fclose(file);return p_de;}

编写makefile文件:

CC = gccCFLAGS = -Wall -gLDFLAGS =SRC_DIR = ./srcINC_DIR = ./includeOBJ_DIR = ./objSRC = $(wildcard *.c) $(wildcard $(SRC_DIR)/*.c)INC = $(wildcard *.h) $(wildcard $(INC_DIR)/*.h)INCLUDE = -I$(INC_DIR)#DIR = $(notdir$(SRC))OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(patsubst %.c,%.o,$(SRC))))# 寻找文件的顺序VPATH = $(SRC_DIR):$(INC_DIR)TARGET = testall: $(TARGET)$(TARGET):$(OBJ)$(CC) $^ -o $@$(OBJ_DIR)/%.o:$(SRC)mkdir -p $(OBJ_DIR)$(CC) $(INCLUDE) -c $(CFLAGS) $< -o $@clean:rm -rf $(OBJ_DIR)rm -f $(TARGET)

目录结构:

执行make命令,报错如下:

ld: symbol(s) not found for architecture x86_64clang: error: linker command failed with exit code 1 (use -v to see invocation)make: *** [test] Error 1

出现这个错误的原因是我们没有把openssl库链接过来,需要修改makefile文件:

CC = gccCFLAGS = -Wall -gLDFLAGS =LIBS = -lssl -lcryptoLIBPATH = -L /usr/local/Cellar/openssl@3/3.0.0_1/libSRC_DIR = ./srcINC_DIR = ./includeOBJ_DIR = ./objSRC = $(wildcard *.c) $(wildcard $(SRC_DIR)/*.c)INC = $(wildcard *.h) $(wildcard $(INC_DIR)/*.h)INCLUDE = -I$(INC_DIR)#DIR = $(notdir$(SRC))OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(patsubst %.c,%.o,$(SRC))))# 寻找文件的顺序VPATH = $(SRC_DIR):$(INC_DIR)TARGET = testall: $(TARGET)$(TARGET):$(OBJ)**$(CC) $^ -o $@ $(LIBPATH) $(LIBS)**$(OBJ_DIR)/%.o:$(SRC)mkdir -p $(OBJ_DIR)$(CC) $(INCLUDE) -c $(CFLAGS) $< -o $@clean:rm -rf $(OBJ_DIR)rm -f $(TARGET)

重新编译,可以通过了。程序运行结果如下:

$ ./testoriginal_text is :I hate coding!ciphertext is :<�?"��h~��}oPeQ�Vh��s�4��W��"s�0+�L�o�T��n�w���A�+��~��?k6�5�plaintext is :I hate coding!

3 Base64 编解码

接下来,为程序增加base64编解码函数(这里我在网上找的老哥代码里面decode的时候设置了不换行,encode的时候却没有设置不换行,坑死我了):

int base64_encode(char *in_str, int in_len, char *out_str){BIO *b64, *bio;BUF_MEM *bptr = NULL;int size = 0;if (in_str == NULL || out_str == NULL)return -1;b64 = BIO_new(BIO_f_base64());BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);//不换行!bio = BIO_new(BIO_s_mem());bio = BIO_push(b64, bio);BIO_write(bio, in_str, in_len);BIO_flush(bio);BIO_get_mem_ptr(bio, &bptr);memcpy(out_str, bptr->data, bptr->length);out_str[bptr->length] = '\0';size = bptr->length;BIO_free_all(bio);return size;}int base64_decode(char *in_str, int in_len, char *out_str) {BIO *b64, *bio;// BUF_MEM *bptr = NULL;// int counts;int size = 0;if (in_str == NULL || out_str == NULL)return -1;b64 = BIO_new(BIO_f_base64());BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);//不换行!bio = BIO_new_mem_buf(in_str, in_len);bio = BIO_push(b64, bio);size = BIO_read(bio, out_str, in_len);out_str[size] = '\0';BIO_free_all(bio);return size;}

修改main函数:

int main(void){char *original_text = "I hate coding!";char *ciphertext, *plaintext;printf("original_text is :%s\n", original_text);//1.加密ciphertext = my_encrypt(original_text, PATH_TO_PUBLIC_KEY);printf("ciphertext is :%s\n", ciphertext);//2.base64编码int length = strlen(ciphertext);char* str_after_encode = (char*)malloc(1024);base64_encode(ciphertext, length, str_after_encode);printf("base64编码结果: %s\n", str_after_encode);//3.base64解码int length2 = strlen(str_after_encode);char* str_after_decode = (char*)malloc(1024);base64_decode(str_after_encode, length2, str_after_decode);printf("base64解码结果: %s\n", str_after_decode);//4.解密plaintext = my_decrypt(str_after_decode, PATH_TO_PRIVATE_KEY);printf("plaintext is :%s\n", plaintext);if(ciphertext)free(ciphertext);if(plaintext)free(plaintext);if(str_after_encode)free(str_after_encode);if(str_after_decode)free(str_after_decode);return 0;}

运行结果:

$ ./testoriginal_text is :I hate coding!ciphertext is :Q���R�kq�H�&$5i�[�nS���L+�i���0� w+��$�����:�R�]/�!>nDZS2p��=�9���:<�5`��т�`F��ï������k$��;]5����(sF3�����U%3base64编码结果: UZuO5FLva3GrSIwmDBokNWm2W9ZuU9nE4EwrD8VprNjyMOoOCXcWK83sJMGkrImROgoc4FLwHF0vtCE+bsexUx0ycO29up097Ls5jufjrjo8rDVgk+fRgogQYEaUHMzDr5rp+6P972sMJKmRO101g7+ish8oc0Yzttb3qMBVJTM=base64解码结果: Q���R�kq�H�&$5i�[�nS���L+�i���0� w+��$�����:�R�]/�!>nDZS2p��=�9���:<�5`��т�`F��ï������k$��;]5����(sF3�����U%3plaintext is :I hate coding!

4 移植到Linux

系统信息:

$ lsb_release -aNo LSB modules are available.Distributor ID:UbuntuDescription:Ubuntu 18.04.4 LTSRelease:18.04Codename:bionic

首先,我们从源码编译一下openssl:

wget /source/old/3.0/openssl-3.0.0.tar.gztar -zvxf openssl-3.0.0.tar.gzcd openssl-3.0.0/./config -fPIC no-sharedmake

编译完了以后应该能在当前目录下看见libssl.alibcrypto.a文件:

在我们之前的项目文件夹下,新建一个lib文件夹,并将库文件拷贝进来,此外还要拷贝一下openssl用到的头文件:

mkdir libcd [path to openssl-3.0.0]cp libssl.a libcrypto.a [path to your project/lib]cp -r ./inlucde/openssl [path to your project/lib]

回到项目文件夹,修改makefile文件:

CC = gccCFLAGS = -Wall -gLDFLAGS =LIBS = -lssl -lcrypto -lpthread -ldlLIBPATH = -L ./libSRC_DIR = ./srcINC_DIR = ./includeOBJ_DIR = ./objSRC = $(wildcard *.c) $(wildcard $(SRC_DIR)/*.c)INC = $(wildcard *.h) $(wildcard $(INC_DIR)/*.h)INCLUDE = -I$(INC_DIR)#DIR = $(notdir$(SRC))OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(patsubst %.c,%.o,$(SRC))))# 寻找文件的顺序VPATH = $(SRC_DIR):$(INC_DIR)TARGET = testall: $(TARGET)$(TARGET):$(OBJ)$(CC) $^ -o $@ $(LIBPATH) $(LIBS)$(OBJ_DIR)/%.o:$(SRC)mkdir -p $(OBJ_DIR)$(CC) $(INCLUDE) -c $(CFLAGS) $< -o $@clean:rm -rf $(OBJ_DIR)rm -f $(TARGET)

这里一定要注意,链接库的顺序千万不能乱动,因为链接的时候是有着严格的依赖顺序的,在链接库时函数是向后查找的,具体的排序应该是调用库,被调用库,被被调用库

看一下现在的项目结构:

$ tree -L 2.├── include│ └── openssl├── lib│ ├── libcrypto.a│ └── libssl.a├── makefile├── rsa_private_key.pem├── rsa_public_key.pem└── src└── test.c

现在编译应该已经可以成功了,程序输出结果也是正确的:

$ ./testoriginal_text is :I hate coding!ciphertext is :Q���R�kq�H�&$5i�[�nS���L+�i���0�w+��$�����:�R�]/�!>nDZS2p����=�9���:<�5`��т�`F��ï�����k$��;]5����(sF3����U%3base64编码结果: UZuO5FLva3GrSIwmDBokNWm2W9ZuU9nE4EwrD8VprNjyMOoOCXcWK83sJMGkrImROgoc4FLwHF0vtCE+bsexUx0ycO29up097Ls5jufjrjo8rDVgk+fRgogQYEaUHMzDr5rp+6P972sMJKmRO101g7+ish8oc0Yzttb3qMBVJTM=base64解码结果: Q���R�kq�H�&$5i�[�nS���L+�i���0�w+��$�����:�R�]/�!>nDZS2p����=�9���:<�5`��т�`F��ï�����k$��;]5����(sF3����U%3plaintext is :I hate coding!

参考文章

openssl C语言编码实现rsa加密 - 路之遥_其漫漫 - 博客园

OpenSSL静态库编译及使用(linux环境)

ld: library not found for -lgsl

RSA加密(3.0)

加密算法和文件格式RSA、X509、PKCSXX?

Base64编码、解码 C语言例子(使用OpenSSL库)_Leon-CSDN博客_base64库 c语言

链接时库的顺序

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。