TLS1.2中的PRF(Pseudo-random Function)

通过对TLS1.2的学习,我了解到其中具有三种密钥:预主密钥、主密钥和会话密钥。
在其握手过程中,客户端和服务器都会根据密码套件生成自己的临时公私钥对,并且将公钥发送给对方,当客户端接收到服务器的公钥时,会生成预主密钥。
之后客户端会使用PRF函数计算出主密钥发送给服务器,计算时需要三个输入:

  • 预主密钥
  • 客户端生成的随机数
  • 服务器生成的随机数

如果使用的是RSA,那么预主密钥的结构如下:

    struct {uint32 gmt_unix_time;opaque random_bytes[28];} Random;struct {ProtocolVersion client_version;opaque random[46];} PreMasterSecret;  struct {uint8 major;uint8 minor;} ProtocolVersion;

会话密钥也是通过PRF函数生成的,需要输入:

  • 主密钥
  • 客户端生成的随机数
  • 服务器生成的随机数

Session ID 缓存和 Session Ticket 里面保存的也是主密钥,而不是会话密钥,这样每次会话复用的时候再用双方的随机数和主密钥导出会话密钥,从而实现每次加密通信的会话密钥不一样,即使一个会话的主密钥泄露了或者被破解了也不会影响到另一个会话。

P_HASH算法

它使用一个 hash 函数扩展成一个 secret 和种子,形成任意大小的输出。其中的哈希函数取决于协商的密码套件。

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +HMAC_hash(secret, A(2) + seed) +HMAC_hash(secret, A(3) + seed) + ...

其中的A():

    A(0) = seedA(i) = HMAC_hash(secret, A(i-1))

"+"表示连接,HMAC_hash的运算次数取决于想要结果的长度。
在计算不同类型的密钥时,对应的secret值也是不同的

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

label必须是ASCII字符串,不包含结尾的’\0’。

HKDF(HMAC-key derivation function)

通过前面的介绍,我们已经大概了解了TLS1.2中的密钥生成实现过程,在TLS1.3中主要使用的是HKDF中的 HKDF-Extract 和 HKDF-Expand 函数,HKDF的主要的目标是获取一些初始的密钥材料,并从中派生出一个或多个安全强度很大的密钥。主要分为两步:

提取

HKDF-Extract(salt, IKM) -> PRK

使用协商好的哈希算法将输入的密钥尽量的伪随机化。

  • Salt:输入,如果不提供则全部初始化为0的字符串,长度则为所采用哈希函数的散列值长度。
  • IKM:输入,密钥材料,在TLS1.3中比较复杂。
  • PRK:输出,伪随机化后的密钥,长度则为所采用哈希函数的散列值长度。

扩展

通过一系列的哈希运算,将密钥扩展到我们所需要的长度,有点类似TLS1.2中的P_HASH。

HKDF-Expand(PRK,info,L)-> OKM
  • info:可选上下文和应用程序特定信息(可以是零长度字符串),我们可以理解为要计算密钥的名称。
  • L:所需要的长度。
  • OKM:计算得出的密钥结果

下面看一下OKM的计算方式:

   N = ceil(L / HashLen)T = T(1)| T(2)| T(3)| ... | T(N)OKM = T的前L个八位位组,其中:T(0)= 空字符串(零长度)T(1)= HMAC-Hash(PRK,T(0)| info | 0x01)T(2)= HMAC-Hash(PRK,T(1)| info | 0x02 )T(3)= HMAC-Hash(PRK,T(2)| info | 0x03)... (其中,连接到每个T(n)末尾的常数是一个八位位组。)

n为0-255的整数,L除以所用哈希函数输出摘要的长度,再向上取整,我们将其记为n。
然后将T(n)串接起来,而我们想要获得的OKM正是取T的前L个字节组成。这要我们就得到了我们想要的密钥材料。

TLS1.3密钥计算

 HKDF-Expand-Label(Secret, Label, Context, Length) =HKDF-Expand(Secret, HkdfLabel, Length)Where HkdfLabel is specified as:struct {uint16 length = Length;opaque label<7..255> = "tls13 " + Label;opaque context<0..255> = Context;} HkdfLabel;Derive-Secret(Secret, Label, Messages) =HKDF-Expand-Label(Secret, Label,Transcript-Hash(Messages), Hash.length)

Transcript-Hash 和 HKDF 使用的 Hash 函数是密码套件哈希算法,Hash.length 是其输出长度(以字节为单位)。消息是表示的握手消息的串联,包括握手消息类型和长度字段,但不包括记录层头,labels 都是 ASCII 字符串。
我们可以看到由于HKDF-Expand-Label(Secret, Label, Context, Length) = HKDF-Expand(Secret, HkdfLabel, Length)所以Derive-Secret相当于HKDF中的HKDF-Expand函数,所以TLS1.3中整个的密钥生成过程主要还是由HKDF中的两个函数计算得来。
其中的HkdfLabel:

HkdfLabel = Hash.length(2 字节) + label_length(1字节) + "tls13 " + Label + Hash.length(1字节) + HASH(Messages)

Transcript-Hash

TLS 中的许多加密计算都使用了哈希副本。这个值是通过级联每个包含的握手消息的方式进来哈希计算的,它包含握手消息头部携带的握手消息类型和长度字段,但是不包括记录层的头部。我的理解是不包括ContenType、legacyRecordVersion、length字段的数据。示例:

Transcript-Hash(M1, M2, ... Mn) = Hash(M1 || M2 || ... || Mn)

TLS 1.3 完整的密钥导出流程图

              0|vPSK ->  HKDF-Extract = Early Secret|+-----> Derive-Secret(., "ext binder" | "res binder", "")|                     = binder_key|+-----> Derive-Secret(., "c e traffic", ClientHello)|                     = client_early_traffic_secret|+-----> Derive-Secret(., "e exp master", ClientHello)|                     = early_exporter_master_secretvDerive-Secret(., "derived", "")|v(EC)DHE -> HKDF-Extract = Handshake Secret|+-----> Derive-Secret(., "c hs traffic",|                     ClientHello...ServerHello)|                     = client_handshake_traffic_secret|+-----> Derive-Secret(., "s hs traffic",|                     ClientHello...ServerHello)|                     = server_handshake_traffic_secretvDerive-Secret(., "derived", "")|v0 -> HKDF-Extract = Master Secret|+-----> Derive-Secret(., "c ap traffic",|                     ClientHello...server Finished)|                     = client_application_traffic_secret_0|+-----> Derive-Secret(., "s ap traffic",|                     ClientHello...server Finished)|                     = server_application_traffic_secret_0|+-----> Derive-Secret(., "exp master",|                     ClientHello...server Finished)|                     = exporter_master_secret|+-----> Derive-Secret(., "res master",ClientHello...client Finished)= resumption_master_secret

从上面开始分析,PSK和0通过HKDF-Extract计算得到Early Secret,然后右侧的第一个是使用Derive-Secret函数生成binder_key,这是什么呢?我们再分析一下之前理解的不是很清楚的PreSharedKey

struct {opaque identity<1..2^16-1>;uint32 obfuscated_ticket_age;} PskIdentity;opaque PskBinderEntry<32..255>;struct {PskIdentity identities<7..2^16-1>;PskBinderEntry binders<33..2^16-1>;} OfferedPsks;struct {select (Handshake.msg_type) {case client_hello: OfferedPsks;case server_hello: uint16 selected_identity;};} PreSharedKeyExtension;

PSK binders

那么我们主要来说一下PSK binders,也就是PskBinderEntry是怎样计算的:
它的计算过程与 Finished 消息一致,只不过其中的Basekey是通过PSK派生的,也就是binder_key

The PskBinderEntry is computed in the same way as the Finished message (Section 4.4.4) but with the BaseKey being the binder_key.
  • 首先就是就是计算binder_key,前面已经说过计算过程了
  • 接着我们看一下Finished计算过程:
    HMAC(Transcript-Hash(all_handshake), finished_key)所以我们还需要计算finished_key
  • 计算finished_key,先看公式:finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
  • 其中的BaseKey正常计算的话,这是在client中计算的,应该是在密钥导出流程图中的client_handshake_traffic_secret
  • 然而此时是binder_key,所以已经可以计算得出,我们只需要计算的是:Transcript-Hash(all_handshake)
  • 计算当前clienthello的Transcript-Hash,其中不包括PSK BindersPSK Binders length,然后和finished_key一起计算HMAC值,即可得出最终结果。

那我们接着往下看,如果给定的 secret 不可用,则使用由设置为零的 Hash.length 字节串组成的 0 值。它不会跳过本轮次,所示当不适用PSK时,Early Secret 仍将是 HKDF-Extract(0,0)。

至于client_early_traffic_secretearly_exporter_master_secret的作用是需要使用会话恢复时,生成的相关密钥。
然后再往下看,Early Secret经过Derive-Secret计算的结果作为下面计算Handshake Secretsalt(EC)DHE作为IKM(EC)DHE是server和client协商出的公钥。然后又扩展成xxx_handshake_traffic_secret,其中都是把clienthello和serverhello中的信息作为Messages来计算的。

继续往下的话,依然是这样的原理,后面的Messages组成部分有Finished。说一下密钥导出吧,我也还不是很理解这是啥意思,慢慢理解吧,先写了:

TLS-Exporter(label, context_value, key_length) =HKDF-Expand-Label(Derive-Secret(Secret, label, ""),"exporter", Hash(context_value), key_length)

其中的Secret是右侧计算出的exporter_master_secretearly_exporter_master_secret

最后再来说一下,右侧生成的xxx_traffic_secret都叫做Basekey,应用于不同的场景,并且这些密钥也不会用来加密数据,最终还需要:

[sender]_write_key = HKDF-Expand-Label(Secret, "key", "", key_length)
[sender]_write_iv  = HKDF-Expand-Label(Secret, "iv" , "", iv_length)

我们可以把它们理解为中间变量,再需要一次HKDF-Expand计算就可以得到对应的加密密钥了。
[sender] 表示发送方。每种记录类型的 Secret 值显示在下表中:

        +-------------------+---------------------------------------+| Record Type       | Secret                                |+-------------------+---------------------------------------+| 0-RTT Application | client_early_traffic_secret           ||                   |                                       || Handshake         | [sender]_handshake_traffic_secret     ||                   |                                       || Application Data  | [sender]_application_traffic_secret_N |+-------------------+---------------------------------------+

client_early_traffic_secret生成的 write_keywrite_iv 最终用于 0-RTT 的加密和解密。

TLS1.3---密钥的计算相关推荐

  1. RSA的密钥d计算(辗转相除法) c++算法实现

                                   RSA的密钥d计算(辗转相除法) c++算法实现 先亮剑,c++的代码实现: int calc_d(int e, int n) {if ( ...

  2. 证书中密钥标识符计算

    下载国家根证书中心(SM2)根证书: 根证书(MIIBszCCAVegAwIBAgIIaeL+wBcKxnswDAYIKoEcz1UBg3UFADAuMQswCQYDVQQGEwJDTjEOMAwGA ...

  3. 【计算机网络】网络安全 : 总结 ( 网络攻击类型 | 网络安全指标 | 数据加密模型 | 对称密钥密码体质 | 公钥密码体质 | 数字签名 | 报文鉴别 | 实体鉴别 | 各层安全 ) ★

    文章目录 一.四种网络攻击 ★ 二.网络安区指标 ★ 三.数据加密模型 ★ 四.对称密钥密码体质 ★ 五.公钥密码体质 ★ 六.数字签名 ★ 七.报文鉴别 ★ 八.实体鉴别 ★ 九.IP 安全 ( 网 ...

  4. 【计算机网络】网络安全 : 数据加密模型 ( 加密模型 | 密钥 | 密码学 | 密码安全 )

    文章目录 一.数据加密模型 二.密钥 三.密码学 四.密码安全 一.数据加密模型 数据加密模型 : ① 发送明文 : 用户 A 向 用户 B 发送 明文 X ; ② 加密 : 通过 加密算法 对 明文 ...

  5. 边缘计算安全技术综述

    边缘计算安全技术综述 凌捷,陈家辉,罗玉,张思亮  广东工业大学计算机学院,广东 广州 510006   摘要:随着物联网应用的不断展开,大量移动终端设备参与服务计算,传统的云计算模型已经不能满足网络 ...

  6. 用c语言elgamal共密钥密码加密算法,非对称密钥体制RSA加密原理

    一.非对称密钥加密概述 前面讲述了对称密钥加密体制.使用对称密钥加密体制进行保密通信时,任意不同的两个用户之间都应该使用互不相同的密钥.这样,如果一个网络中有n个用户,他们之间彼此都可能进行秘密通信, ...

  7. openstack云计算平台 2(计算服务、Networking 服务、命令行方式启动实例)

    目录 一.组件3-计算服务 1.简介 2.安装并配置控制节点 3.安装并配置计算节点 4.验证操作 二.组件4-Networking 服务 1.简介 2.安装并配置控制节点 3.控制节点配置网络选项- ...

  8. CPU卡校验MAC1、计算MAC2、校验TAC的方式及流程

    前言 mac1验证.mac2计算.tac验证流程 运行结果如下 涉及的帮助类 DES工具类 ByteUtil 前言 CPU卡的各个密钥是需要通过加密机分散获得,因此这里使用的是之前自己发的一张复旦微电 ...

  9. MAC 与密钥派生函数 KDF

    一.MAC 消息认证码 MAC 消息认证码,即 Message Authentication Code,是用于验证消息的一小段信息. 换句话说,能用它确认消息的真实性--消息来自指定的发件人并且没有被 ...

  10. LKCOS安全芯片MAC计算方法简介(一):PBOC-MAC计算

    该方法来源于PBOC标准. 命令安全报文中的MAC是使用命令的所有元素(包括命令头和命令数据域中的数据)来产生的.以保证命令连同数据能够正确完整地传送,并对发送方进行认证. 按照如下方式使用DEA加密 ...

最新文章

  1. python面对对象汉诺塔_如何使用python实现的汉诺塔的小程序
  2. java文件中有中文,在windows下因编码不一致,而导致编译失败的处理方法。
  3. html dd自动换行,为什么我的dd里面的内容没有自动换行呢
  4. atitit.提升开发效率---mda 软件开发方式的革命
  5. c# msi中加入驱动_MSI微星:给你的CPU装上热交换气缸活塞,不用电也能驱动风扇降温...
  6. Linux集中日志服务器rsyslog(亲测)
  7. [渝粤教育] 广东-国家-开放大学 21秋期末考试物权法10774k1
  8. php float转int 元转分
  9. PythonServer
  10. 运维自动化部署Cobbler之服务安装篇
  11. 位图管理、图片下载缓存、管理图片内存 (三) 在非UI线程中处理位图
  12. 大数据之数据仓库分层
  13. 电子之TTL和CMOS门电路的区别
  14. unicode编码表,转载自:近來情轉深的博客
  15. Xcode 报错及解决办法汇总
  16. mysql时间自动填充_Mysql自动设置时间(自动获取时间,填充时间)
  17. UVALive - 4987 Evacuation Plan
  18. 解读温度传感器应用于物联网+冷链行业
  19. Basic4IOS (B4I) New Version Crack
  20. Linux使用gstreamer打开网络摄像头

热门文章

  1. 历年计算机二级Java考试试题及答案(完整版)
  2. java中的数据结构——图
  3. Android 上专为视屏直播打造的轻量级弹幕库(100 多 kb)
  4. Orcad Library Builder使用教程以及安装踩坑记录
  5. JAVA_WEB程序设计教程 pdf
  6. hydra-字典暴力破解
  7. 暴力破解之NTscan+密码字典工具
  8. html5怎么设置黑色背景及亮度,网页背景怎么设置为纯黑色css样式
  9. 科大讯飞 离线语音识别python_用Python来使用科大讯飞语音识别,so easy
  10. C# 访问 带密码的access数据库