2022_1_14_周汇报
- 一、进度
- 1.顶层设计(设计分为3部分)
- 2.系统初始化
- 3.自定义协议
- 4.通信
- 5.包格式细化
- 6.数据包步骤
- 7.如何实现udp可靠传输步骤(包如何发送既中间处理)
- 8.所需的函数
- 1.协议步骤涉及OpenSSL接口
- 2.数据包步骤函数
- Protocal_identifyWithExchange_first()
- Protocal_identifyWithExchange_second()
- Protocal_identifyWithExchange_third()
- Protocal_identifyWithExchange_fourth()
- Protocal_dhwithsm2_pre_first()
- Protocal_dhwithsm2_pre_second()
- Protocal_dhwithsm2_first()
- Protocal_dhwithsm2_second()
- Protocal_dhwithsm2_third()
- Protocal_dhwithsm2_forth()
- Encrypted_dialogue_first()
- Encrypted_dialogue_second()
- Protocal_endAsk_first()
- Protocal_endConfirm_second()
- Protocal_endConfirm_third()
- 3.步骤数据处理部分设计思考
- 4.步骤数据处理函数
- 5.异常中断处理
- 6.状态检测
- 9. 其他
- 二、遇到和解决的问题
- 三、下周计划
- 四、其他有价值的参考
一、进度
1.顶层设计(设计分为3部分)
-
系统初始化(用户注册+生成sm2证书)
-
自定义加密通信协议
-
通信
2.系统初始化
公证人T,通信双方A和B
T生成自己的sm2公私钥,形成自己的证书CertT
A选择IDA并生成自己的公私钥,形成自己的证书CertA,然后T给CertA签名并将CertT发给A
B选择IDB并生成自己的公私钥,形成自己的证书CertB,然后T给CertB签名并将CertT发给B
3.自定义协议
1.自定义协议步骤
-
-----身份鉴别并交换证书
-
A生成随机数R1,将R1+sm3(R1)+CertA发送给B
-
B验证R1完整性并生成随机数R2,用B的私钥对R1+R2签名后+CertB+R2再整体发送给A
-
A验证签名,通过A的私钥对R2签名并发送给B(A对B认证)
-
B验证签名(B对A认证)
-
-----DH结合公钥的DH协议,协商会话密钥
-
发起通信方A用B的公钥加密g和x发送给B,加签名
-
B解密并验证A的签名
-
B生成随机数RB并将计算的m=gRB(mod p)发送给A,加签名
-
A生成随机数RA并将计算的n=gRA(mod p)生成会话密钥k ,把[y,Ek(SKpriA(RA,RB))]发送给B,加签名
-
B计算K并将消息解密并验证签名,将Ek(SKpriB(RA,RB))发送A
-
A验证B的签名
2.协议步骤形式化展示
协议步骤(一) 身份鉴别并交换证书 |
|||
---|---|---|---|
步骤1 |
A生成随机数R1,将R1+CertA+sm3(R1)发送给B |
||
A生成随机数R1,计算sm3(R1),将R1+CertA++sm3(R1)打包发送 | B接受包 | ||
步骤2 |
B验证R1完整性并生成随机数R2,
|
||
A接受包 | B验证R1完整性,生成随机数R2,计算SkpriB(R1+R2),将SkpriB(R1+R2)+CertB+R2打包发送 | ||
步骤3 |
A验证签名,通过A的私钥对R2签名并发送给B(A对B认证) |
||
A验证B的签名,计算SkpriA(R2),将SkpriA(R2)打包发送 | B(无) | ||
步骤4 |
B验证签名(B对A认证) |
||
A(无) | B验证A的签名 | ||
协议步骤(二) 结合公钥的DH协议,协商会话密钥 |
|||
步骤1 |
发起通信方A用B的公钥加密g和x发送给B,加签名 |
||
A生成DH参数g和x,计算EKpubB(g|x),计算SKpriA(EKpubB(g|x)),将EKpubB(g|x)+SKpriA(EKpubB(g|x))打包发送 | B接受包 | ||
步骤2 |
B解密并验证A的签名 |
||
A(无) | B计算DKpriB(EKpubB(g|x))解密,并验证A的签名 | ||
步骤3 |
B生成随机数RB并将计算的m=gRB(mod p)发送给A,加签名 |
||
A接受包 | B生成随机数RB,计算m=gRB(mod p),计算SKpriB(m),将m+SKpriB(m)打包发送 | ||
步骤4 |
A生成随机数RA并将计算的n=gRA(mod p)生成会话密钥k ,把[y,Ek(SKpriA(RA,RB))]发送给B,加签名 |
||
A生成随机数RA,计算n=gRA(mod p),计算k=mRA(mod p),计算Ek(SKpriA(RA,RB)),计算SKpriA(n|Ek(SKpriA(RA,RB))),将n+Ek(SKpriA(RA,RB))+SKpriA(n|Ek(SKpriA(RA,RB)))打包发送 | B接受包 | ||
步骤5 |
B计算K并将消息解密并验证签名,将Ek(SKpriB(RA,RB))发送A |
||
A接受包 | B计算k=nRB(mod p),用k解密并验证A的签名,计算Ek(SKpriB(RA,RB)),将Ek(SKpriB(RA,RB))打包发送 | ||
步骤6 |
A验证B的签名 |
||
A解密并验证B的签名 | B(无) |
4.通信
- -----每一对(发起通信到另一方回复)加密通信
- 发起通信方将信息用加密秘钥加密,做签名
- 接收方验证签名
加密通信部分(A发起通信) |
|||
---|---|---|---|
步骤1 |
A将信息用加密秘钥加密,做签名 |
||
A计算E(sm3)k(message),计算SKpriA(E(sm3)k(message)),将E(sm3)k(message)+SKpriA(E(sm3)k(message))打包 | B接受包 | ||
步骤2 |
B验证签名 |
||
A(无) | B验证签名,并解密 |
5.包格式细化
UDP有校验和,要做到分段的话还是要加校验
UDP包数据段最大长度1472字节,防止底层协议分片
通信序号(要唯一标识,相当于uid(IP+昵称))32bit,数据包序号唯一标识32bit,应答序号唯一标识32bit,步骤标志(4位,分为鉴别、发送g和x、DH、通信,结束,3位表步骤,一位表是否完成,只有第一次才会从鉴别开始,其他都是从发送g和x开始),是否分段标识1位和下一分段是否结束标识1位和累计包数6位(单位为:一个包数据长度,现为1450字节)=1字节,长度(4位),窗口大小(1字节),数据1440字节,校验4字节,时间戳4字节,填充(用0填充)8字节,结束符(1字节->0xaa)
数据包序号唯一标识,应答序号唯一标识都是由一个指定函数递增生成
第一个包,应答序号为0
后面根据函数来指定,可以做一个函数指针,按需求改,自己实现时可以随时修改直到完成
-
包结构体
32位=4bytes uid -> int
32位=4bytes sender_sequence -> int
32位=4bytes responder_sequence -> int
4位 stage
4位 header_len(/4bytes,单位)-> char
1位 flag_shared
1位 flag_next
6位 packet_count(分片包计数) -> char
8位 window_size -> char
32位=4bytes timestamp -> int
16位=2bytes checknum -> short int
8bytes reserved -> char[2] 0x00...00
2bytes padding 0x1A1A ->char[2]
1440bytes data -> char*
8位 endnode 0xaa -> char
6.数据包步骤
通信双方A和B,第三方公证方T
T提前存在A和B本地,且生成A和B的sm2证书并用根证书签名
-
-----身份鉴别并交换证书
-
A生成随机数R1,将R1+sm3(R1)+CertA发送给B
-
B验证R1完整性并生成随机数R2,用B的私钥对R1+R2签名后+CertB+R2再整体发送给A
-
A验证签名,通过A的私钥对R2签名并发送给B(A对B认证)
-
B验证签名(B对A认证)
-
-----DH结合公钥的DH协议,协商会话密钥
-
发起通信方A用B的公钥加密g和x发送给B,加签名
-
B解密并验证A的签名
-
B生成随机数RB并将计算的m=gRB(mod p)发送给A,加签名
-
A生成随机数RA并将计算的n=gRA(mod p)生成会话密钥k ,把[y,Ek(SKpriA(RA,RB))]发送给B,加签名
-
B计算K并将消息解密并验证签名,将Ek(SKpriB(RA,RB))发送A
-
A验证B的签名
-
-----进行通信
-
A将信息用加密秘钥加密,并签名后发送给B
-
B验证签名,并解密
-
-----结束
-
一方提出结束请求,另一方发送结束请求确认(必须要签名数据,签名包含头部),提出请求方还需要确认签名
7.如何实现udp可靠传输步骤(包如何发送既中间处理)
包传输实现参考
计时器2个
-
分段模块
-
发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
-
校验和
目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)
-
对报文排序
对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
-
丢弃重复的数据
-
流量控制。
每一方都有固定大小的缓冲空间。接收端只允许另一端发送接收端缓冲区所能接纳的数据(就是窗口大小限制)。这将防止较快主机致使较慢主机的缓冲区溢出。 -
重传
用于控制数据段是否需要重传的依据是设立重发定时器。在发送一个数据段的同时启动一个重传,如果在重传超时前收到确认(Acknowlegement)就关闭该重传,如果重传超时前没有收到确认,则重传该数据段。在选择重发时间的过程中,TCP必须具有自适应性。它需要根据互联网当时的通信情况,给出合适的重发时间。
这种重传策略的关键是对定时器初值的设定。采用较多的算法是Jacobson于1988年提出的一种不断调整超时时间间隔的动态算法。其工作原理是:对每次发送都保持一个变量RTT(Round Trip Time),用于存放当前到目的端往返所需要时间最接近的估计值。当发送一个数据段时,同时启动连接的定时器,如果在定时器超时前确认到达,则记录所需要的时间(M),并修正[2] RTT的值,如果定时器超时前没有收到确认,则将RTT的值增加1倍。通过测量一系列的RTT(往返时间)值,可以估算数据包重发前需要等待的时间。在估计该连接所需的当前延迟时通常利用一些统计学的原理和算法(如Karn算法),从而得到重发之前需要等待的时间值。 -
窗口
对接受到的数据进行确认,并向源应用程序发送确认信息。使用数据报头序列号以及确认号来确认已收到包含在数据段的相关的数据字节。这个过程称为期待确认。
源主机在收到确认消息之前可以传输的数据的大小称为窗口大小。用于管理丢失数据和流量控制。
8.所需的函数
考虑了一下还是双证书体系:一个加密证书,一个解密证书
使用API生成证书,参考C++使用OpenSSL证书API、用Openssl API制作证书
1.协议步骤涉及OpenSSL接口
-
大随机数生成->openssl自带的大数库
BN_rand(BIGNUM *rnd,int bits,int top,int bottom):生成一个强密码学随机函数,是一个无法预测的随机数。rnd:需要生成的随机数,bits:需要生成随机数的位数,top:为设置最高位的值,top=-1表示最高位设置为0,top=0表示最高位设置为1,top=1时,最高两位都设置成1,bottom:不为0时,可以生成奇的随机数。参考:https://blog.csdn.net/taylorshuang/article/details/10208697 -
sm2签名函数->OpenSSL里
EVP_DigestSignInit()
EVP_DigestSignUpdate()
EVP_DigestSignFinal() -
sm2签名验证函数——>OpenSSL里
EVP_DigestVerifyInit()
EVP_DigestVerifyUpdate()
EVP_DigestVerifyFinal() -
DH协议->OpenSSL里有 crypto/dh/dh.h
BN_get_rfc3526_prime_4096()生成RFC3526推荐的DH参数(尝试自己生成DH参数,参照《密码工程》,实在不行就用此函数,如果生成的推荐参数不固定就使用此函数)
-
sm3hash(自己以前做过)->OpenSSL API
EVP_MD_CTX_init(sm3ctx); //初始化摘要结构体
EVP_DigestInit_ex(sm3ctx, EVP_sm3(), NULL); //设置摘要算法和密码算法引擎,这里密码算法使用MD5,算法引擎使用OpenSSL默认引擎即软算法
EVP_DigestUpdate(sm3ctx, msg1, strlen(msg1));//调用摘要UpDate计算msg1的摘要
EVP_DigestUpdate(sm3ctx, msg2, strlen(msg2));//调用摘要UpDate计算msg2的摘要
EVP_DigestFinal_ex(sm3ctx, sm3_value, &sm3_len);//摘要结束,输出摘要值
EVP_MD_CTX_reset(sm3ctx); -
sm4加密(自己以前做过)->OpenSSL API
//初始化密码算法结构体
EVP_CIPHER_CTX_init(ctx);
//设置算法和密钥以
rv = EVP_EncryptInit_ex(ctx,EVP_sm4_cbc(),NULL,key,iv);//数据加密
rv = EVP_EncryptUpdate(ctx,out,&outl,msg,strlen(msg));//结束数据加密,把剩余数据输出。
rv = EVP_EncryptFinal_ex(ctx,out+outl,&outltmp); -
信封加解密->OpenSSL seal系列函数,如:EVP_SealInit()
2.数据包步骤函数
双证书CertsA,CerteA,CertsB,CerteB
-
Protocal_identifyWithExchange_first()
- 输入:无
- 输出:无
- 函数功能:A生成随机数R1,将R1+sm3(R1)+CertA发送给B
-
Protocal_identifyWithExchange_second()
- 输入:无
- 输出:无
- 函数功能:B验证R1完整性并生成随机数R2,用B的私钥对R1+R2签名后+CertB+R2再整体发送给A
-
Protocal_identifyWithExchange_third()
- 输入:SignB(R1+R2),R2
- 输出:无
- 函数功能:A验证签名,通过A的私钥对R2签名并发送给B(A对B认证)
-
Protocal_identifyWithExchange_fourth()
- 输入:SignA(R2)
- 输出:无
- 函数功能:B验证签名(B对A认证)
-
Protocal_dhwithsm2_pre_first()
- 输入:无
- 输出:无
- 函数功能:发起通信方A用B的公钥加密g和x发送给B,加签名
-
Protocal_dhwithsm2_pre_second()
- 输入:SignA[En(CerteB)(g|x)],En(CerteB)(g|x)
- 输出
- 函数功能:B解密并验证A的签名
-
Protocal_dhwithsm2_first()
- 输入:
- 输出:无
- 函数功能:B生成随机数RB并将计算的m=gRB(mod p)发送给A,加签名
-
Protocal_dhwithsm2_second()
- 输入:m
- 输出:无
- 函数功能:A生成随机数RA并将计算的n=gRA(mod p)生成会话密钥k ,把[y,Ek(SKpriA(RA,RB))]发送给B,加签名
-
Protocal_dhwithsm2_third()
- 输入:n
- 输出:无
- 函数功能:B计算K并将消息解密并验证签名,将Ek(SKpriB(RA,RB))发送A
-
Protocal_dhwithsm2_forth()
- 输入:Ek(SKpriB(RA,RB))
- 输出:无
- 函数功能:A验证B的签名
-
Encrypted_dialogue_first()
- 输入:对话内容message
- 输出:
- 函数功能:计算Ek(e)(message),计算SignA[Ek(e)(message)],将Ek(e)(message)+SignA[Ek(e)(message)]打包,发送给B
-
Encrypted_dialogue_second()
- 输入:Ek(e)(message),SignA[Ek(e)(message)]
- 输出:无
- 函数功能:解密并验证签名
-
Protocal_endAsk_first()
- 输入:无
- 输出:无
- 函数功能:生成结束请求,签名后打包发送
-
Protocal_endConfirm_second()
- 输入:无
- 输出:无
- 函数功能:确认结束请求,验证签名,签名后打包回复
-
Protocal_endConfirm_third()
- 输入:无
- 输出:无
- 函数功能:验证签名
3.步骤数据处理部分设计思考
-
发送窗口与接受窗口相当于生产者和消费者(生产者和消费者问题)
-
发送包区管理函数(),验证包序号和时间戳
每个包都是一个结构体,排序可以使用<stdlib.h>中的qsort()
时间戳time.h里的time()可以获取
-
时间戳:根据UTC时间,生成时间戳
-
接受包区管理函数(),验证包序号和时间戳
-
协议一个步骤的数据分段函数
发送端将一个步骤超过1440的数据,分为多个udp包,并设置相应的分段标识和分段是否结束标识,包序号仍然递增
接收端将有设置分段标识的包合并后再进行验证签名或者解密等操作 -
生成校验和函数,参考:https://blog.csdn.net/lanhy999/article/details/51123626、https://bbs.csdn.net/topics/391049303 IPSec中为 HMAC前96位作为完整性校验值ICV
-
包排序函数()
每个包都是一个结构体,排序可以使用<stdlib.h>中的qsort()
-
错误报文处理函数
-
定时器函数:参考Linux下实现定时器
-
字节分割
-
字节合并
-
位分割
-
位合并
4.步骤数据处理函数
-
PacketManage()
-
输入:包
-
输出:无
-
函数功能:验证包序号和时间戳和排序
-
-
TimestampGen()
- 输入 :无
- 输出:时间戳
- 提示:<time.h>time()
- 函数功能:生成UTC时间戳
-
PacketDivide()
-
输入:一个步骤数据
-
输出:多个包
-
函数功能:步骤数据分片
-
-
PacketMerge()
-
输入:多个包
-
输出:一个步骤数据
-
函数功能:步骤数据分片合并
-
-
PacketSort()
-
输入:多个包
-
输出:排序后的包
-
提示:每个包都是一个结构体,排序可以使用<stdlib.h>中的qsort()
-
函数功能:根据包序号排序
-
-
PacketProcess()
- 输入:单个包
- 输出:
- 提示:窗口值的提取、步骤顺序的确认
- 函数功能:处理定义包结构的每部分数据
5.异常中断处理
6.状态检测
9. 其他
-
攻击方式:窃听、截获、伪造、篡改、重放
签名可以防伪造、篡改
加密防窃听
包序号防重放
-
验证程序考虑:进入主界面需要输入一个昵称,然后根据昵称,sm4加密后生成一个sm2证书,
-
通话需要输入,IP(昵称),打开聊天界面先搜索本地数据库是否已有会话记录,无则开始协议,(搜索分有无证书,有无会话密钥)
-
协商时禁止输入,完成后可开始通信,关闭聊天窗口即结束会话,即将会话密钥有效期置零
-
再进行拓展可以考虑把自定义协议写入内核中
额外参考:《计算机网络》课件《第五章运输层(1-4)》第59页
二、遇到和解决的问题
设计时分模块不够准确,对于协议的思考欠缺了点
老师指点认识到整个系统是依靠证书的协议,所以有些可以简化,有些不能删减
三、下周计划
设计包格式或者其他数据结构
开始进行详细设计
四、其他有价值的参考
-
LINUX下的网络层加密解密的实现:修改内核部分文件
-
TFTP数据包格式,TFTP协议过程分析:基于UDP的协议
-
RFC5996中文翻译:IKE协议