手把手教你如何实现一个简单的数据加密算法

2023-05-16

0. 前言

之前写过一篇关于MD5摘要算法的文章,很多老铁说能否出一篇关于加密的文章吗?

《C语言实现MD5,竟如此简单!》

一口君的字典里没有"不行"这两个字!必须安排!

关于加密的一些基本概念,大家可以参考下面这一篇文章:
《公钥密码学简介》

本文,一口君带着大家自己实现一个简单但也很实用的加密方法,

让大家了解实际项目开发中数据加密的流程。

一、一种常见的网络通信的加密流程

关于加密的算法很多,实际实现过程千差万别,

下图是一个常见的网络通信加密的应用场景。

密码机的一些说明:

  • 客户端服务器端都可以设置密码机(可以是软件、也可以是一个硬件,只要能够产生密钥即可)
  • keygen和同步码都会影响到密码机生成的密钥序列
  • 密码机在keygen和同步码相同的情况下,会产生相同的密钥序列,加解密双方需要记住产生密钥的顺序,解密多少数据就申请多少密钥

    如上图所示,基于C/S架构的服务器和客户端通信模型,

下面以客户端如果要发送一段加密的密文给服务器,C/S需要交互的流程。

1 服务器端发送密钥密文

  • 首先服务器端、客户端都保存了一个默认的密钥
  • 服务器端随机生成密钥keygen,并使用该默认密钥对keygen加密,生成密钥密文
  • 客户端可以通过命令定期请求该密钥密文或者服务器定时下发
  • 客户端收到密钥密文后,也可以通过默认密钥进行解密得到明文的keygen

2. 客户端对数据加密

  • 客户端在发送数据之前,首先生成一个同步码
  • 将同步码和keygen设置给密码机,然后向密码机申请一定长度的密钥
  • 将明文和密钥通过一定的算法进行加密(通常是异或),生成数据密文

3. 客户端发送同步码和数据密文

  • 客户端将数据密文和同步码明文一起发送给服务器
  • 服务器提取出同步码

4. 服务器端接收数据并解密

  • 服务器将keygen和同步码设置给密码机,同时申请一定数量的密钥
  • 服务器根据密钥对密文进行解密,即得到对应的明文

因为服务器和客户端此时都使用了相同的keygen,和同步码,所以双方申请的密钥序列一定是一样的。

二、函数实现

下面是一口君实现的加密算法的一些函数原型以及功能说明,这些函数基本实现了第一节的功能。

1. 申请加密密钥函数request_key

int request_key(int sync,int key_num,char key[])
功能:
	向密码机申请一定数量的用于加密数据的密钥,如果不设置新的keygen,那么生成的密码会顺序产生下去,每次申请密钥都会记录上次生成的密钥的偏移,下次在申请的时候,都会从上一位置继续分配密钥
参数:
	sync:同步码,密码机依据此同步产生随机序列的密钥
	key_num:申请的密钥个数
	key:申请的密钥存储的缓存
返回值:
	实际返回密钥个数

2. 设置密钥序列函数set_keygen

void set_keygen(int key)
功能:
	向密码机设置keygen,设置后会影响产生的随机密钥序列
参数:
	key:密钥
返回值:

3. 产生随机数born_seed

int born_seed(int sync,int key)
功能:
	根据同步码和keygen生成随机密钥种子
参数:
    sync:同步码 
	key:密钥
返回值:
	种子

4. 重置keygen reset_keygen()

void reset_keygen()
功能:
	重置keygen,会影响生成的随机数序列

三、测试代码实例

最终文件如下:

key.c  key.h  main.c

示例1 检测产生的随机序列

int main(int argc, char *argv[])
{
	int i;
	unsigned int len;
	int j, r, key_num;
	unsigned int sync = 0;
	unsigned char key[MAX_KEY_REQUEST];


	key_num = 10;

	printf("\n--------------采用默认keygen 同步码=0 产生密文----------------\n");
	reset_keygen();

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);

	print_array("密钥0-9:",key,len);

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);

	print_array("密钥10-19:",key,len);

	printf("\n--------------采用keygen=1234 同步码=0 产生密文----------------\n");
	set_keygen(1234);

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);

	print_array("密钥0-9:",key,len);

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);

	print_array("密钥10-19:",key,len);
}

执行结果:

--------------采用默认keygen 同步码=0 产生密文----------------
密钥0-9: ----[10]
a5 52 c8 14 5d f7 46 5b 89 42 
密钥10-19: ----[10]
38 69 6f a6 08 d2 69 39 cd 29 

--------------采用keygen=1234 同步码=0 产生密文----------------
密钥0-9: ----[10]
0e 83 0b 73 ec f5 4b 4a 74 35 
密钥10-19: ----[10]
e7 f1 06 41 c8 6b aa df 0c 3d 

可以看到采用不同的keygen产生的随机序列是不一样的。

如果设置不同的同步码,仍然序列还会不一样。

示例2 用默认keygen,加解密

char data0[10]={
	0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0x10,
};
int main(int argc, char *argv[])
{
	int i;
	unsigned int len;
	int j, r, key_num;
	unsigned int sync = 0;
	unsigned char key[MAX_KEY_REQUEST];
	char buf[120]={0};

	key_num = 10;
	printf("\n--------------采用默认keygen开始加密----------------\n");
	reset_keygen();
	print_array("\n明文:",data0,key_num);

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);

	print_array("密钥:",key,len);
	for(i=0;i<len;i++)
	{
		buf[i] = data0[i]^key[i];
	}
	print_array("\n密文:",buf,len);
	
	printf("\n--------------------开始解密--------------------\n");
	reset_keygen();

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);

	
	for(i=0;i<len;i++)
	{
		buf[i] = buf[i]^key[i];
	}

	print_array("\n明文:",buf,len);
}

测试结果

--------------采用默认keygen开始加密----------------

明文: ----[10]
01 02 03 04 05 06 07 08 09 10 
密钥: ----[10]
a5 52 c8 14 5d f7 46 5b 89 42 

密文: ----[10]
a4 50 cb 10 58 f1 41 53 80 52 

--------------------开始解密--------------------

明文: ----[10]
01 02 03 04 05 06 07 08 09 10 

示例3 用不同的keygen和同步码加解密

int main(int argc, char *argv[])
{
	int i;
	unsigned int len;
	int j, r, key_num;
	unsigned int sync = 0;
	unsigned char key[MAX_KEY_REQUEST];
	char buf[120]={0};
	unsigned int mykeygen;


	if (argc != 4) {
		fprintf(stderr, "Usage: %s <seed> <key num> <keygen>\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	sync = atoi(argv[1]);
	key_num = atoi(argv[2]);
	mykeygen = atoi(argv[3]);

	printf("\n--------------采用自定义的keygen、同步码开始加密----------------\n");
	set_keygen(mykeygen);
	print_array("\n明文:",data0,key_num);

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);
	print_array("密钥:",key,len);

	for(i=0;i<len;i++)
	{
		buf[i] = data0[i]^key[i];
	}
	print_array("\n密文:",buf,len);
	

	printf("\n--------------------开始解密--------------------\n");
	set_keygen(mykeygen);

	memset(key,0,sizeof(key));
	len = request_key(sync,key_num,key);
	for(i=0;i<len;i++)
	{
		buf[i] = buf[i]^key[i];
	}
	print_array("\n明文:",buf,len);
	exit(EXIT_SUCCESS);
}

执行结果如下:

--------------采用自定义的keygen、同步码开始加密----------------

明文: ----[10]
01 02 03 04 05 06 07 08 09 10 
密钥: ----[10]
53 00 29 cd 27 eb cc 80 1a d7 

密文: ----[10]
52 02 2a c9 22 ed cb 88 13 c7 

--------------------开始解密--------------------

明文: ----[10]
01 02 03 04 05 06 07 08 09 10 

可见我们的确实现了数据的加密和解密。

四、数据加密的实际使用

假定我们使用上述实例代码,把对应的功能移植到C/S两端,

那么一次完整的数据加密以及数据的传输参考流程如下:


记住一点,只要双方设置相同的keygen和同步码,那么密码机吐出来的密钥就是相同序列,

客户端发送每发送一个报文,就把自己的明文同步码一起发送给服务器,

服务器根据提前发送给客户端的keygen和同步码就可以实现解密操作,

虽然你可以看到明文的同步码,

但是还需要破解密码机算法、服务器下发的keygen密文。

五、 原理

实现加密算法的主要问题是如何产生随机序列作为密钥。

本例是借用库函数rand()
原型如下:

#include <stdlib.h>

int rand(void);

函数rand() 虽然可以产生随机序列,但是每次产生的序列其实顺序是一样的。

#include <stdio.h>

main()
{
	int i = 0;

	for(i=0;i<10;i++)
	{
		printf("%d ",rand());
	}
	putchar('\n');
}

运行结果如下:

peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$ ./a.out 
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 
peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$ ./a.out 
1804289383 846930886 1681692777 1714636915 1957747793 424238335 719885386 1649760492 596516649 1189641421 

要想每次都产生不一样的随机序列应该怎么办呢?
需要借助srand()函数

void srand(unsigned int seed);

只需要通过该函数设置一个种子,那么产生的序列,就会完全不一样,

通常我们用time()返回值作为种子,

在此我们随便写入几个数据,来测试下该函数

#include <stdio.h>

main()
{
	int i = 0;

	srand(111);
	for(i=0;i<10;i++)
	{
		printf("%d ",rand());
	}
	putchar('\n');
	srand(1111);
	for(i=0;i<10;i++)
	{
		printf("%d ",rand());
	}
	putchar('\n');
}

执行结果如下:

peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$ ./a.out 
1629905861 708017477 1225010071 14444113 324837614 2112273117 1166384513 1539134273 1883039818 779189906 
1383711924 882432674 1555165704 1334863495 1474679554 676796645 154721979 534868285 1892754119 100411878 

可见输入不同的种子就会产生不同的序列。

函数原型如下:


本例原理比较简单,没有考虑太复杂的应用(比如多路密钥的管理)和数据安全性,

只阐述加解密的流程,仅作为学习理解加解密流程用,此种加密算法属于对称加密,相对比较简单,还是比较容易破解。

目前市场上都是由专业的公司和团队实现加解密功能。

一口君之前曾写过聊天室的一个小项目,

《从0实现基于Linux socket聊天室》

后面一口君会基于该加密机制,将聊天室所有客户端与服务器所有交互数据进行加密处理,请大家持续关注:一口Linux。

本文完整代码下载地址:
链接:https://pan.baidu.com/s/1VvGNlNGEUWWZHQZ1_gYU7A 提取码:o9se

后台回复:数据加密,即可获得全部源码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

手把手教你如何实现一个简单的数据加密算法 的相关文章

随机推荐

  • 使用conda时出现Solving environment: failed错误

    一 问题 win10系统下 xff0c 在安装anaconda后 xff0c 执行conda install mingw libpython时报错如图 D anaconda Scripts gt conda install mingw li
  • 政务外网后端接口PUT和DELETE不通

    政务外网后端接口PUT和DELETE不通 错误信息 解决思路 1 xff0c 首先排查政务内网环境下接口是否能通 2 查看nginx反向代理问题 3 查看接口是否调通后端 xff0c 后端是否有相应信息 4 排查端口是否对外开放 5 关闭防
  • 安装Anaconda3后缺失大量文件的解决方法:安装旧的版本再升级

    项目场景 xff1a 安装Anaconda3 项目场景 xff1a 安装Anaconda3后缺失大量文件 问题描述 安装Anaconda3后缺失大量文件 正确安装后的样子 xff1a 原因分析 xff1a 找了很多帖子 xff0c 也尝试了
  • IOS开发 汉化

    UIImagePicker TZImagePicker选择图片时默认是英文 只需要修改xcode本地设置即可 xff0c 具体操作如图示 1 选择info 2 添加Localizations 3 将English改成Chinese 2 iO
  • WSL2 Linux搭建xfce4桌面和使用xrdp远程连接

    基于Ubuntu20 04测试 1 安装 span class token function sudo span apt span class token function install span xfce4 xrdp y 如果遇到下面页
  • 修改 WSL2 可用内存大小和交换分区大小

    WSL2默认可以使用的内存大小为主机的80 对于Linux而言即使装了桌面 一般的开发也没必要给这么多内存 分多了 反而有可能卡主机的Windows 操作 1 打开Windows资源管理器 地址栏输入 UserProfile 回车 在该目录
  • C++代码: Linux下获取基本设备信息

    测试环境 基于C 43 43 20构建测试 g 43 43 10 2 1 CMakeLists txt 设置用于构建该项目的最低cmake版本 cmake minimum required VERSION 3 1 设置项目名称和编程语言 p
  • VMware虚拟机Ubuntu无法使用摄像头的问题

    注 之前我在使用Ubuntu的虚拟机中 搞OpenCV开发 需要使用摄像头 遇到了摄像头无法使用的问题 后面折腾了很久才发现 USB3 1 兼容设置的问题 刚才又用新的虚拟机配置环境 又遇到了之前的问题 因此做个记录 1 摄像头未连接到虚拟
  • 一文搞懂光纤的方方面面

    光纤 一直以为光纤模块会非常贵 xff0c 呃 xff0c 只能说没有想象中的贵 xff0c 相比网线还是贵上不少 一个常见的光纤系统通常会包括收发器 xff0c 光电转换器还有光纤收发器 通常简单的入门级一套下来可能也在200 300左右
  • msys2配置cmake构建环境

    注 本人主要在Linux下搞开发 使用msys2是为了方便移植部分程序到Windows下 做以下纪录方便环境配置 1 换源 span class token comment 更新本地软件数据库 span pacman Sy 2 安装开发工具
  • Windows 10安装 WSL2 (Ubuntu 20.04)

    条件 对于 x64 系统 xff1a 版本 1903 或更高版本 xff0c 采用 内部版本 18362 或更高版本 对于 ARM64 系统 xff1a 版本 2004 或更高版本 xff0c 采用 内部版本 19041 或更高版本 低于
  • Ubuntu 20.04 server 切换中文语言

    1 安装区域设置 locales Ubuntu 一般是预装了的 Kali Linux 和 Debian可能没有 就需要安装 更新索引 sudo apt update span class token comment 安装locales sp
  • 全新安装的Termux配置Ubuntu环境

    基于 Termux 0 101 测试 换国内源 默认官方源在国外速度慢 有梯子的话也可以不换 这里换清华源为例 更多 执行命令 span class token function sed span i span class token st
  • 1g 路由器使用

    前言 xff08 1 xff09 首次使用以及断网后配置都可参看本文 xff08 2 xff09 简谈 xff0c 创翼实际登录拨号的账号其实并不是 电话 64 cqit xff0c 而是在这个账号前面根据拨号时间生成一个随机字符串 xff
  • 基于随机森林的手写数字识别 (OpenCV)

    OpenCV 4 5 1 C 43 43 20 Ubuntu 20 04 素材 来源 基于 K近邻博文 中原5000个手写数字得到的按行排列的手写数字数据以及对应行的标签 保存为图片后直接放到这里使用 避免重复数据处理 右键图片另存为 行数
  • 使用支持向量机分类 (OpenCV)

    OpenCV 4 5 1 C 43 43 20 Ubuntu 20 04 素材 像素点和分类标签 组态档 设置用于构建该项目的最低cmake版本 cmake minimum required VERSION 3 1 设置项目名称和编程语言
  • 退出该博客平台声明

    试用c s d n快三个月了 xff0c 最不满的就是审核的问题 1 我自己写的东西因为有误修改了一下再提交就说我的博文已有相似的 xff0c 审核不通过 xff0c 不止一次 2 反而好奇有人抄了我的却发出去了 这应该是最后一次在这里发文
  • CMake Error at CMakeLists.txt:11 (find_package): Found package configuration file: /home/luw

    参考资料 xff1a https www cnblogs com newneul p 8364924 html CMake Error at CMakeLists txt 11 find package Found package conf
  • LPC1768学习笔记

    LPC1768学习笔记 xff1a IAP升级 1 需求 xff1a 通过串口给主机升级 xff0c 主机的通信串口与升级串口相同 2 方法 xff1a 要完成APP与IAP程序的切换判断 xff0c 我们需要一个flag update单独
  • 手把手教你如何实现一个简单的数据加密算法

    0 前言 之前写过一篇关于MD5摘要算法的文章 xff0c 很多老铁说能否出一篇关于加密的文章吗 xff1f C语言实现MD5 xff0c 竟如此简单 xff01 一口君的字典里没有 34 不行 34 这两个字 xff01 必须安排 xff