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

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

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

  1. 自己的java框架_手把手教你如何设计一个简单的Java框架

    您可能对框架如何工作感到好奇?这里将通过一个简单的框架示例来说明框架的思想. 框架目标 首先,为什么我们需要一个除普通库以外的框架?框架的目标是定义一个过程,使开发人员可以根据个人需求实现某些功能.换 ...

  2. python编程例子 输入 输出-推荐 :手把手教你用Python创建简单的神经网络(附代码)...

    原标题:推荐 :手把手教你用Python创建简单的神经网络(附代码) 作者:Michael J.Garbade:翻译:陈之炎:校对:丁楠雅 本文共2000字,9分钟. 本文将为你演示如何创建一个神经网 ...

  3. 手把手教你做第一个RPA机器人流程

    手把手教你做第一个RPA机器人流程 第一步:下载&安装RPA工具 第二步:新建第一个自动化流程 第三步:开始详细配置流程 简单介绍一下艺赛旗RPA界面 开始流程配置 第四步:总结 第一步:下载 ...

  4. 手把手教你快速搭建一个代码在线编辑预览工具

    简介 大家好,今天我跟大家分享的是一个代码在线编辑预览工具的实现教程,手把手教你完成这样一个项目. 目前这类工具使用很广泛,常见于各种文档网站及代码分享场景,相关工具也比较多,如codepen.jsr ...

  5. 手把手教你如何搭建一个自己的安卓快速开发框架之带你做自己的APP(二)

    ####点击查看上一篇文章:手把手教你如何搭建一个自己的安卓快速开发框架之BaseActivity(一) 继上一篇我实现了基本的BaseActivity,包含 ToolBar 透明状态栏 生命周期监控 ...

  6. php如果实现日历的制作,教你如何制作一个简单的PHP日历

    PHP是一款功能强大的后端编程软件,我们在学习PHP的过程中要经过很多实际的战斗,现在让我们做一个日历来巩固PHP的基础,今天爱站技术频道小编为大家整理了教你如何制作一个简单的PHP日历,希望能帮到大 ...

  7. 智能机器人c语言编程,【图片】教你快速制作一个简单的人工智能机器人(懂编程的人进来看)【科幻吧】_百度贴吧...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 教你快速制作一个简单的人工智能机器人(懂编程的人进来看) 本文我首发于"人工智能吧",叫做<机器人理解人类语言>和< ...

  8. python数据预测代码_手把手教你用Python玩转时序数据,从采样、预测到聚类丨代码...

    原标题:手把手教你用Python玩转时序数据,从采样.预测到聚类丨代码 原作 Arnaud Zinflou 郭一璞 编译 时序数据,也就是时间序列的数据. 像股票价格.每日天气.体重变化这一类,都是时 ...

  9. cmd 将文件夹下文件剪切到另外一个文件_手把手教你运行第一个 Java 程序,看不懂你来骂我!...

    码字不易,对你有帮助 **点赞 /转发↪️/关注 ** 支持一下作者 微信搜公众号:不会编程的程序圆br/>看更多干货,获取第一时间更新 在运行第一个 java 程序之前,你需要先将 java ...

最新文章

  1. 前端思想实现:面向UI编程_____前端框架设计开发
  2. 科学解析2021年AI领域的10个大胆预测
  3. golang中的strings.ContainsRune
  4. IIS 6.0的web园 最大工作进程数
  5. PCL:PCL可视化显示点云
  6. spark广播变量的使用(转)
  7. what is the location of js when using run as server in Eclipse
  8. iphone固件降级_我在iPhone上装了个安卓
  9. Xamarin和Java开发安卓_将原生移动开发与Xamarin相结合
  10. 【论文阅读】Efficient Net
  11. C语言练手题(52个小练习)
  12. 爱思助手更新后无法连接服务器,爱思助手出现无法连接或连接超时的操作教程...
  13. HTML 表单发送邮件
  14. UE4 Slate四 SlateUI如何做动画
  15. SQL Server报错:Arithmetic overflow error converting expression to data type int.
  16. KPM算法——数据结构|复习局|串|复杂模式匹配算法|二维数组解决KPM
  17. 读书笔记:《好团队激活个人--猫鼬教你如何带团队》
  18. Kubernetes 集群基于 Rook 的 Ceph 存储之块设备、文件系统、对象存储
  19. 数学测试卷软件,小学数学练习机_随机出数学练习题软件 50.0官方版
  20. Fast Global Registration(快速全局配准)

热门文章

  1. xeon bronze 3106
  2. java客户端发消息到kafka
  3. 【Java泛型】泛型方法
  4. USB会议摄像机的重要的网络特性
  5. 算法 64式 4、回溯算法整理__第1部分_1到13题
  6. 均匀节点插值与切比雪夫插值以及龙格现象
  7. Mysql索引Hash和BTree的区别
  8. Python版本与Matlab版本的对应关系
  9. 保护Excel表格的4种常用方法
  10. STM32 内存分布探究