随笔 - 6  文章 - 0  评论 - 0  阅读 - 286

obfs4proxy 协议验证方式和部分源代码结构、函数分析

1 obfs4协议验证逻辑

  • 握手过程

  • data内容
    涉及算法:curve25519

    客户端及服务端都必须有自己的Keypair实例。根据curve25519包中的定义,PrivateKey在一定范围内随机生成。根据ECC算法,PublicKey可以通过调用curve25519.ScalarBaseMult()从私钥生成。

    Representative秘钥根据公钥生成,在需要的时候可以调用extra25519.RepresentativeToPublicKey()函数再次转换为公钥。Keypair的定义及初始化代码位于NewKeypair()函数中,该函数在ntor.go文件中定义。

    用extra25519.go里的ScalarBaseMult(),根据privatekey生成public和representative。representative通过Elligator 2映射完成混淆,避免收集到相当数量的公钥后推断出加密算法。
    算法详细说明

    客户端及服务端都应当保存好私钥,将公钥以Representative秘钥的形式发送给对方。Obfs4客户端的连接过程从握手报文开始,因此我们来看一下客户端的握手报文。该报文的整体结构如下所示:

    1. Keypair.representative,其长度为20h字节。在服务器端,它可以作为还原客户端的公钥。(obfs4 bridge配置行)
    2. 使用随机字节的填充数据,其数据大小范围在4Dh至1FC0h之间,该填充数据会混淆握手数据包的大小,从而使其更难识别。
    3. 第一部分Keypair.representative的HMAC值。Obfs4使用SHA-256生成HMAC,长度为20h字节。Obfs4仅将前10h字节保留为HMAC,其余10h字节将被丢弃。
    4. Obfs4使用当前系统时间来计算UNIX Epoch时间(从UTC时间1970年1月1日星期四00:00:00开始)的小时值。计算数据包中前三个部分的HMAC值,加上(指拼接起来)字符串中的小时值。同样,其结果长度为20h字节,前10h字节作为数据包的第四部分。(防重放)

2 obfs4proxy源代码部分结构

  • common/ 密码学、socks5等组件
  • internal/ 更新的混淆算法
  • obfs4proxy/
    obfs4proxy.go 主函数
  • transports/
    包含meeklite、obfs2、3、4、 scramblesuit传输协议的实现
    • obfs4/
      • framing/ 数据帧的处理
        • handshake_ntor.go 完成obfs4握手,包括验证
        • obfs4.go 握手相关函数

3 obfs4proxy源代码部分函数

  • obfs4.go

    • WrapConn()
      调用了serverHandshake(),不管返回什么错,都closeAfterDelay()。

    • serverHandshake()
      新建服务端握手,设置基准超时时间。
      然后按能读取的最大长度(8192)设置缓冲区,读取收包,保存收包内容,接下来parseClientHandshake()解析内容。
      如果解析错误是ErrMarkNotFoundYet,继续读包,其他错误则函数返回错误。
      解析正常则清空缓冲区。

  • handshake_ntor.go

    • parseClientHandshake()
      对于接收内容过少/接收内容长度未达上限时,或找不到MarkMAC,准备了ErrMarkNotFoundYet的错误处理,可以返回继续读。
      其他错误都关闭连接。找不到markMAC/HMAC/包长度不合规(有握手中不需要的数据),返ErrInvalidHandshake。
      重放,返ErrReplayedHandshake。
      计算验证不通过,返ErrNtorFailed。

    • closeAfterDelay()
      closeAfterDelay()被修改,修复了因阈值产生FIN和RST的漏洞。旧版本会在延迟30s/接收一定长度数据后终止连接,新版本都是延迟30s终止连接。

    • SetReadDeadline()
      开始读数据30s后,再有数据进入也返回超时错误,并终止连接。(论文里说有随机延迟,我没找到)

  • obfs4proxy.go

    • serverHandler()
      调用WrapConn(),如果返回错误,在日志中记录握手失败。
    • serverAcceptLoop()
      让服务器循环开启与客户端的握手,调用serverHandler()。

        

记录于2022年,2024年整理发布

posted on   rink_rv  阅读(41)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示