ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-09 16:30:49  阅读:223  来源: 互联网

标签:MacOS OBJ rsa openssl char str C语言 DIR


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

1 安装openssl并生成密钥

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

brew install openssl

安装完了以后执行:

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

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

openssl genrsa -out rsa_private_key.pem 1024
openssl 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   1024

char *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 = gcc

CFLAGS =  -Wall -g
LDFLAGS =

SRC_DIR = ./src
INC_DIR = ./include
OBJ_DIR = ./obj

SRC = $(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 = test

all: $(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_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [test] Error 1

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

CC = gcc

CFLAGS =  -Wall -g
LDFLAGS =
LIBS = -lssl -lcrypto
LIBPATH = -L /usr/local/Cellar/openssl@3/3.0.0_1/lib

SRC_DIR = ./src
INC_DIR = ./include
OBJ_DIR = ./obj

SRC = $(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 = test

all: $(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)

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

$ ./test
original_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;

}

运行结果:

$ ./test
original_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%3
base64编码结果: 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%3
plaintext is :I hate coding!

4 移植到Linux

系统信息:

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.4 LTS
Release:	18.04
Codename:	bionic

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

wget https://www.openssl.org/source/old/3.0/openssl-3.0.0.tar.gz
tar -zvxf openssl-3.0.0.tar.gz
cd openssl-3.0.0/
./config -fPIC no-shared
make

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

在这里插入图片描述

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

mkdir lib
cd [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 = gcc

CFLAGS =  -Wall -g
LDFLAGS =
LIBS = -lssl -lcrypto -lpthread -ldl
LIBPATH = -L ./lib

SRC_DIR = ./src
INC_DIR = ./include
OBJ_DIR = ./obj

SRC = $(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 = test

all: $(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

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

$ ./test
original_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%3
base64编码结果: 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%3
plaintext 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语言

链接时库的顺序

标签:MacOS,OBJ,rsa,openssl,char,str,C语言,DIR
来源: https://blog.csdn.net/imba_wolf/article/details/122395231

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有