
本文,一口君带大家实现了一种简单而实用的加密方法,
让您了解实际项目开发中数据加密的过程。
一、网络通信常用的加密过程
关于加密的算法很多,实际实现过程千差万别,
下图是网络通信加密的常见应用场景。
密码机的一些说明:
- 客户端服务器端可以设置密码机(可以是软件,也可以是硬件,只要能在本地或服务器上生成密钥)
- keygen同步码会影响密码机生成的密钥序列
- 密码机在keygen在与同步码相同的情况下,会产生相同的密钥序列。加解密方需要记住产生密钥的顺序,并申请解密数据的密钥

如上图所示,基于C/S架构服务器和客户端通信模型,
如果客户端想向服务器发送加密密文,C/S需要交互的过程。
1 服务器端发送密钥密文
首先,服务器端和客户端务器端和客户端
服务器端随机生成密钥keygen,并使用默认密钥对keygen加密,生成密钥密文
客户端可以通过命令定期请求该密钥密文或者服务器定时下发
客户端收到密钥密文后,也可以通过默认密钥解密获得明文keygen
2. 客户端加密数据
在发送数据之前,客户端首先生成同步码
将同步码和keygen设置密码机,然后向密码机申请一定长度的密钥
通过一定的算法加密明文和密钥(通常是异或),生成数据密文
3. 客户端发送同步码和数据密文
客户端向服务器发送数据密文和同步码明文
服务器提取同步码
4. 服务器端接收数据并解密
服务器将keygen与密码机设置同步码,同时申请一定数量的密钥
服务器根据密钥解密,即获得相应的明文
此时服务器和客户端使用相同的服务器keygen,与同步码相同,因此双方申请的密钥序列必须相同。
二、函数实现
以下是加密算法的一些函数原型和功能描述,基本实现了第一节的功能。
1. 申请加密密钥函数request_key
intrequest_key(intsync,intkey_num,charkey[])功能:如果不设置新的密码,向密码机申请一定数量的加密数据密钥keygen,然后生成的密码将按顺序生成。每次申请密钥时,都会记录上次生成的密钥偏移。下次申请时,密钥将继续从上一个位置分配参数:sync:密码机根据此同步生成随机序列的密钥key_num:申请的密钥个数key:申请的密钥存储缓存返回值:实际返回密钥数量2. 设置密钥序列函数set_keygen
voidset_keygen(intkey)功能:设置密码机keygen,设置后会影响随机密钥序列参数:key:密钥返回值:无3. 产生随机数born_seed
intborn_seed(intsync,intkey)功能:根据同步码和keygen生成随机密钥种子参数:sync:同步码key:密钥返回值:种子4. 重置keygen reset_keygen()
voidreset_keygen()功能:重置keygen,随机数序列会影响生成三、测试代码实例
最终文件如下:
key.ckey.hmain.c示例1 检测产生的随机序列
intmain(intargc,char*argv[]){inti;unsignedintlen;intj,r,key_num;unsignedintsync=0;unsignedcharkey[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);}执行结果:
密钥0-9:a552c8145df7465b8942密钥10-19:38696fa608d26939cd29密钥0-9:0e830b73ecf54b4a7435密钥10-19:e7f10641c86baadf0c3d可以看到不同的用途keygen随机序列不同。
如果设置不同的同步码,序列仍然会不同。
例2 默认使用keygen,加解密
chardata0[10]={0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0x10,};intmain(intargc,char*argv[]){inti;unsignedintlen;intj,r,key_num;unsignedintsync=0;unsignedcharkey[MAX_KEY_REQUEST];charbuf[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);}测试结果
明文:01020304050607080910密钥:a552c8145df7465b8942密文:a450cb1058f141538052明文:01020304050607080910示例3 用不同的keygen加解密同步码
intmain(intargc,char*argv[]){inti;unsignedintlen;intj,r,key_num;unsignedintsync=0;unsignedcharkey[MAX_KEY_REQUEST];charbuf[120]={0};unsignedintmykeygen;if(argc!=4){fprintf(stderr,"Usage:%s<seed><keynum><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);}执行结果如下:
明文:01020304050607080910密钥:530029cd27ebcc801ad7密文:52022ac922edcb8813c7明文:01020304050607080910可见我们的确实现了数据的加密和解密。
四、实际使用数据加密
假设我们使用上述实例代码将相应的功能移植到C/S两端,
完整的数据加密和数据传输参考流程如下:

记住,只要双方设置相同的设置keygen密码机吐出的密钥与同步码相同,
每次客户发送报纸,都会将自己的明文同步码发送给服务器,
根据提前发送给客户端的服务器keygen解密操作可以通过同步码实现,
虽然可以看到明文的同步码,
但是,还需要解决服务器发布的密码算法和算法keygen密文。
五、 原理
实现加密算法的主要问题是如何产生随机序列作为密钥。
本例是借用库函数rand() 原型如下:
#includeintrand(void);函数rand() 虽然可以产生随机序列,但每次产生的序列实际上是一样的。
#include<stdio.h>main(){inti=0;for(i=0;i<10;i ){printf("%d",rand());}putchar('\n');}运行结果如下:
peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$./a.out180428938384693088616816927771714636915195774779342423833571988538616497604925965166491189641421peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$./a.out180428938384693088616816927771714636915195774779342423833571988538616497604925965166491189641421每次都要产生不同的随机序列怎么办?需要借助srand()函数
voidsrand(unsignedintseed);种子只需要通过这个函数设置,生成的序列就会完全不同,
通常我们用time()返回值作为种子,
在这里,我们随便写几个数据来测试函数
#include<stdio.h>main(){inti=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.out1629905861708017477122501007114444113324837614211227311711663845131539134273188303981877918990613837119248824326741555165704133486349514746795546767966451547219795348682851892754119100411878输入不同的种子会产生不同的序列。
函数原型如下:
图片本例原理比较简单,不考虑太复杂的应用(如多路密钥管理)和数据安全性,
这种加密算法属于对称加密,相对简单,或者相对容易破解,仅用于学习和理解加密过程。

目前,专业公司和团队在市场上实现加解密功能。
本文转载自微信公众号「一口Linux」,请注意以下二维码。请联系本文Linux公众号。
