目录
1. Signal protocol概述
Signal protocol是真正的端到端的通讯加密协议,号称是世界上最安全的通讯协议,任何第三方包括服务器都无法查看通讯内容,热门应用facebook messenger,whatsapp,singal app都采用的此协议。
Signal protocol保证双方通信的安全性,具体做法即一次一密。即便黑客获取了某个消息的密钥,也无法解密之前或之后的加密消息。因此,Signal protocol能提供前向安全和后向安全。
2. Signal protocol逐层研究
2.1 迪菲-赫尔曼密钥交换协议
迪菲-赫尔曼密钥交换协议(英文名:Diffie-Hellman key exchange,以下简写为DH协议)是一种可以在双方完全没有对方预先信息的情况下,在不安全的非保护公共信道上,创建共享密钥,实现安全通信的安全协议。
2.1.1 关键点
它能够实现安全通信的关键点在于,通信双方在创建共享密钥时,只需使用自己的私钥和对方的公钥。这意味着通信双方只需要发送自己的公钥,即便黑客截获了双方的公钥,也无法计算出通信双方使用的共享密钥。
2.1.2 举例
假设通信双方分别是A和B。那么A有一个密钥对,即私钥a和公钥A,同样,B有一个密钥对私钥b和公钥B。接下来,A和B通过公共信道将公钥A和公钥B发送给对方。此时若有人截获了他们的消息,只能获取到公钥A和公钥B。设DH协议计算密钥的方法为DH(本方私钥,对方公钥),那么最后的共享密钥S=DH(私钥a,公钥B)=DH(私钥b,公钥A)。截获了公钥的攻击者,由于缺乏私钥,无法使用同样的方法获取S。至此,DH协议成功实现在不安全的网络环境中,实现安全的密钥协商。
2.1.3 优点
利用特殊的DH算法,可以实现在不安全的非保护公共信道上,创建共享密钥,进行安全通信
2.1.4 缺点
DH协议不支持认证,所以它可以抵抗偷窥但无法抵抗篡改。黑客可以通过中间人攻击的方式破解加密信息。因此,DH协议常常搭配其它算法或协议使用。
注释:中间人攻击——通过拦截正常的网络通信数据,并进行数据篡改和嗅探,而通信的双方却毫不知情。就DH协议来说,中间人攻击就是中间人获取他们发送给对方的公钥,篡改成自己的公钥。因此,会生成两个中间人和双方的协商密钥,这使得中间人可以用发送方的会话密钥破解发送方的加密消息,再用接收方的会话密钥加密后转发给真正的接收方,而发送方和接收方不会察觉到他们的通信中隐藏着这个攻击者。
2.1.5 数学理论证明
假设,用户Alice有一个秘密整数a=6,用户Bob有一个秘密整数b=15。Alice和Bob提前协商了两数字,它们分别是素数p=23及其原根g=5(设m是正整数,a是整数,若a mod m的阶等于φ(m),则称a为模m的一个原根。其中φ(m)表示m的欧拉函数)。Alice通过a计算出公共整数A=g^a mod p=5^6 mod 23=8,Bob通过b计算出公共整数B=g^b mod p=5^15 mod 23=19。通过公共网络,Alice和Bob交换了公共整数A和B。然后,A使用自己的秘密整数a和对方的公共整数B计算得到协商数字s=B^a mod p=19^6 mod 23=2,而B也使用自己的秘密整数b和对方的公共整数A计算得到协商整数s=A^b mod p=8^15 mod 23=2。此时,Alice和Bob成功地获得了相同的协商整数s。而自始至终,Alice和Body只通过公共网络获取了对方的公共整数,即便有人也得到了公共整数,也无法计算出同样的协商整数s。
如果将秘密整数视为密钥,公共整数视为公钥,协商整数视为协商密钥。那么上述过程,其实就是DH协议实现的数学例子。
接下来,对上述例子进行总结和归纳。上述的协商密钥计算方法,用公式表示就是
由于A和B是通过a和b计算得出的,所以上述等式可以写成
为了证明上述等式成立,需要先证明一个引理。
设,则存在整数q,满足
,可得
可以发现,的二项式展开中,只有最后一项
中没有b的整数倍。由此可得
所以
完成引理证明后,可以得到
至此,数学理论证明完成。
2.2 X3DH协议
Signal protocol采用X3DH协议创建消息密钥。X3DH协议基于DH协议,但是引入更多的公钥参数以提高安全性,可以理解为X3DH协议是DH协议的三倍扩展版。X3DH协议是在一个中央服务器协助下,实现通讯双方可以异步并且以只与服务器通讯的方式实现DH密钥协商的协议。它的出现主要是完善简单的DH协议,因为DH协议有着无法防御中间人攻击等缺陷,而X3DH协议在防御中间人攻击等方面增加措施,从而提高加密通信的安全性。
2.2.1 关键点
所有用户在服务器预留一部分公钥信息供任何想与其建立通讯会话的对方使用。当有用户试图与其他用户建立通信时,这位发送用户将从服务器获取目标用户的一组信息,并使用从服务器获得的信息计算得到结果,混合自身的身份元信息发送到目标用户,目标用户验证发送的信息无误后回复发送用户,从而成功建立会话信息
2.2.2 内容
在X3DH协议中,有3个角色:
(1)会话发起者
(2)会话接收者
(3)服务器:负责存储所有用户的公钥
每个用户要创建三个密钥对:
(1)身份密钥(Identity Key,IK)——一个长期密钥对,用户注册时创建,与用户身份绑定,用于身份验证
(2)已签名的预共享密钥(Signed Pre Key,SPK)——一个中期密钥对,是用户使用身份密钥签名过的,用于建立会话认证使用,为安全会以一定的周期更换,一般一周,一天,甚至几个小时
(3)一次性预共享密钥(One-Time Pre Keys,OPK)——为建立会话生成的仅可使用一次的密钥对,一般用户会向服务器上传一组几十上百个这样的公钥,这样的公钥每次成功建立一个会话后一定要废弃,绝对不可以重复使用,否则将面临巨大的安全风险
所有人都要将这三个密钥对的公钥上传到服务器上,以便其他人发起会话时使用。
每当有用户试图与其他人创建会话时,都会从服务器中取出目标用户的三个公钥,与自有的私钥计算出会话的初始消息密钥。
2.2.3 举例
假设用户Alice试图与Bob创建会话,那么Alice将进行以下流程(小写字母表示私钥,大写字母表示公钥):
(1)Alice首先创建一个临时密钥对(ephemeral key,EK)
(2)Alice从服务器中获取Bob的三个密钥对的公钥——身份密钥对IK-B,已签名的预共享密钥SPK-B,一次性预共享密钥OPK-B(服务器每次下发一个一次性共享密钥,都会将其删除,防止重复使用,如果已经用尽,那么服务器返回的消息里就不会有该密钥)
(3)Alice使用DH协议计算协商密钥,排列组合两个Alice自有的私钥和Bob的三个公钥,可以计算出四个值:
DH1=DH(IK-a,SPK-B)
DH2=DH(EK-a,IK-B)
DH3=DH(EK-a,SPK-B)
DH4=DH(IK-a,OPK-B)
由于一次性预共享密钥OPK有可能耗尽,所以可能不会计算DH4。
然后将四个值连接在一起进行KDF计算,就能得到初始的消息密钥SK
SK=KDF(DH1||DH2||DH3||DH4)
注释:这里的KDF是一种密钥衍生算法,它与signal消息加密的前后向安全有关,这里我们先保留疑问,待到后面的内容再解释KDF的作用
至此,Alice生成消息密钥,将EK-a和DH算法的中间结果删除(EK-A保留)。
(4)Alice根据Alice自己和Bob的身份密钥(有可能还根据用户名、头像等)计算一组附带数据(Associated Data,AD),这个AD是用于AEAD加密机制的。
注释:AEAD加密机制,是一种带有认证功能的加密方式。单纯的对称加密算法,其解密步骤是无法确认密钥是否正确的,即一般无论使用的密钥是否正确,都可以解密得到一组疑似原始数据,而解密者无法确定这组数据是否正确。AEAD加密机制,简单来说,就是使用同一个密钥加密原始数据和附带数据AD,并将计算出的两组密文放在一起发送。因为附带数据一般是公开的数据,所以解密者手里应当已有一份准确的附带数据。接收消息后的解密者,使用密钥解密附带数据加密后的密文,将得到的疑似附带数据和手里的准确附带数据进行比对,如果一致,那就能确定自己使用了正确的密钥,可以正确解密原始数据了。
(5)Alice向Bob发送创建会话的起始消息,内容包括:
Alice的身份密钥IK-A
Alice的临时密钥EK-A
Alice使用的SPK-B和OPK-B的标识符
使用AEAD加密机制加密的密文
(6)Bob接收到起始消息后,如果上述的所有计算过程合法无误,那么Bob可以使用对应的DH算法得到一样的初始消息密钥SK,并与Alice建立安全的通信。
2.2.4 优点
通过消息携带的身份认证公钥,可以从其它渠道或是基于首次安全认证机制验证对方身份非伪造,防御中间人攻击。计算中使用到的单次预设密钥可以防御重放攻击。服务器在通信中能起到的作用很有限,最多能阻断双方建立会话,并不会对通讯安全和已经建立的会话造成实质性的破坏,因而可以容许有问题的服务器。
2.2.5 缺点
发送者和接受者之间一直使用同一个密钥来加密消息。虽然这个密钥采用了很多手段来保护,防止被破解,但还是有可能被攻击者获取到。一旦消息密钥被攻击者得到,就意味着整个会话中的所有加密消息都有被攻击者破解的危险,端到端加密通信不复存在。
2.3 KDF棘轮算法
X3DH算法有一个缺点,是一旦密钥泄露,会导致所有加密消息被破解。为了解决这一缺陷,协议使用了双棘轮算法来实现一次一密,即每个消息使用一个不同的密钥。而且即便有人得到了某条消息的密钥,也无法破解之前或之后的消息。
棘轮算法,指的是像上图棘轮只能朝一个方向旋转一样,只能根据当前密钥向前或向后推算密钥的算法,即满足前或后向安全性。而协议使用了双棘轮算法,保证了攻击者无法通过当前消息密钥破解之前或之后的消息密钥,从而同时满足了前后向安全性。
首先,我们介绍双棘轮算法中,实现前向安全性的KDF棘轮算法。
2.3.1 关键点
前文X3DH中曾经提到过KDF算法,这是一种密钥衍生算法。它可以通过原密钥与附件数据计算出新密钥,从原密钥中导出新密钥。
其公式可以表示为KDF(原密钥,盐)=新秘钥。这里的盐即附件数据的代称,因此在计算中增加附加数据也称加盐。
那么要想每次的消息密钥都发生变化,只要每次两个用户使用同样的原密钥和同样的附件数据,去计算相同的新秘钥即可。如此,既不会影响加密解密,也可以做到一次一密。
2.3.2 内容
首先,用户与另一名用户成功建立了会话,并通过X3DH协议生成了初始的消息密钥。然后,双方按照协定,选择同样的附件数据,例如双方的用户名、注册时间等。最后,将初始的消息密钥当做原密钥,增加附加数据,通过KDF计算出新密钥。新的密钥并不直接使用,而是将它分割为两部分,后半部分作为下一条消息的消息密钥,前半部分则用于下次KDF计算所需要的原密钥。如此循环下去,就能源源不断地生成新密钥,从而实现一次一密了。
注意,上述行为是两个用户一致进行的,选择的附件数据一致,密钥分割后两个密钥的长度一致,因此每次生成的消息密钥也是一致的,所以不会影响正常通讯的加密解密。
2.3.3 举例
假设用户Alice已经与Bob成功创建会话,Alice和Bob协商出了同样的初始消息密钥SK,并选择双方的注册手机号连接在一起PN(Phone number)作为附加数据,也就是盐。
这里只举例Alice方面的密钥计算,Bob的计算过程与其一致。
(1)将SK作为原密钥,S作为附加数据,通过KDF算法计算出新密钥NK1
(2)将NK1分割为前后两部分,前半部分作为下一次KDF计算的原密钥OK1,后半部分作为第一个消息密钥MK1
(3)将OK1增加附加数据S,通过KDF算法计算出新密钥NK2,
(4)重复分割操作,将NK2分割为下一次KDF计算的原密钥OK2和第二个消息密钥MK2,并不断重复(3)(4)
2.3.4 优点
由于双方用户每次进行KDF计算时,使用的是同样的原密钥和盐,所以得出的新密钥也是一致的,无需在线确认增加风险,也不会影响正常通讯。而攻击者在获取到某条消息的密钥时,由于KDF算法不可逆,因此他无法破解之前发送的加密信息,KDF棘轮由此保证了前向安全性。
2.3.5 缺点
虽然KDF棘轮保护了之前发送的加密信息,但一旦某条消息的消息密钥泄露,且攻击者获取到了用于KDF计算的盐,那么他将可以计算出接下来所有的消息密钥,即KDF棘轮无法满足后向安全性。
2.4 DH棘轮算法
KDF棘轮由于每次使用相同的盐,无法保证后向安全性,那么只要是每次加的盐都是不同的随机内容,就能实现后向安全性了。所以需要一种算法,可以保证双方每次KDF计算时,生成同样的随机内容作为盐,从而实现无法通过当前密钥计算之后的消息密钥。
之前篇幅较长,可能会有遗忘,在此要再次声明,Signal协议的应用背景是不安全的网络。所以在之前的内容里,协议从不在通信中加入私密内容,只有公开的公钥等,从而保证不会泄露重要信息。那么在KDF的迭代计算中,每次生成的随机内容也不能通过网络发给对方。
2.4.1 关键点
在不安全的网络通信中,生成同样的随机内容,就要再次使用到DH协议。使用两个随机密钥对,通过DH协议即可协商出一致的随机密钥,用于每次KDF计算中的加盐。
DH棘轮就是由两个用户轮流更新随机密钥对,每次生成不同的随机协商密钥,作为KDF计算中的盐,从而实现了后向安全性。因为每次发送一个消息,盐就会更新,即便攻击者获取到了某条消息的密钥和对应的盐,也计算不出后面的消息密钥。
2.4.2 内容
第一次生成消息密钥时,先由一位用户生成一个随机密钥对,并将公钥发送给另一个用户。另一个用户也生成一个随机密钥对,用私钥和收到的公钥生成一个协商密钥,将其作为盐进行KDF计算,得到消息密钥后,加密信息发送给对方,并将自己速记密钥对的公钥一并发送。对方收到以后重复同样的行为,生成随机密钥对,通过新的私钥和对方的公钥计算盐,KDF计算消息密钥,发送加密信息和公钥,此后不断迭代重复。总而言之,每次发送消息时,发送方会生成一个随机密钥对,与最近一次收到的接收方公钥DH计算出协商密钥,然后将其作为盐KDF计算出新的消息密钥,用该消息密钥加密消息后,和新的随机密钥对中的公钥一同发送给接收方。
2.4.3 举例
假设用户Alice发起会话,并和Bob基于X3DH协议创建了会话,开始通信。
在X3DH协议,Alice在生成初始消息密钥SK时随机生成了一个密钥对EK,它既可以在X3DH协议中参与生成SK,也可以作为DH棘轮中的第一个随机密钥对RK-a1和RK-A1(Random key)。Bob在生成SK时已经收到了RK-A1。
(1)Bob生成随机密钥对RK-b1和RK-B1,将RK-b1和RK-A1通过DH计算出第一个盐S1(Salt),通过KDF计算出第一个消息密钥MK1,加密消息,发送给Alice
(2)Alice收到消息,引入RK-B1,加上RK-a1通过DH计算出同样的内容,即第一个盐S1,通过KDF计算出消息密钥MK1,从而解密Bob发来的消息
(3)如果下一条消息由Alice发送时,Alice生成随机密钥对RK-a2和RK-A2,将RK-a2和RK-B1通过DH计算出盐S2,再通过KDF计算出新的消息密钥MK2,将加密消息和发送给Bob。Bob接收到消息后,引入RK-A2,加上RK-b1计算出S2,再计算出MK2,从而解密Alice发送的消息
(4)如果下一条消息还是由Bob发送时,Bob生成随机密钥对RK-b2和RK-B2,将RK-b2和RK-B2通过DH计算出盐S2',再通过KDF计算出消息密钥MK2',将加密消息和随机密钥公钥RK-B2一同发送给Alice。Alice接收到RK-B2后,加上RK-a1计算出S2',再计算出MK2',从而解密Bob发送的消息
2.4.4 优点
通过DH算法生成随机的附加数据,既不影响对称加密,也成功实现了后向安全。
2.4.5 缺点
通信双方离线,不能确认对方是否收到了消息。发送方连续发出多条消息,每次都会更新自己的随机公钥。接收方上线进行解密时,从发送方请求到的公钥,已经无法解密稍早的消息了。所以,在实际应用中会规定,在没有接收到接收方回复一条消息时,不更新随机密钥对。