缓存的公告

Bulletin#048A2F0A54D305C083E740C468CC9F8C

o5rdqyAP36HG6HTCHbiTNh1GJ7kvKk4Z5m #10

发布@2020-09-19 14:56:17

上一篇


接上条,个体客户端与个体客户端之间可以分头计算出一个相同的对称加密密钥,就可以进行客户端到客户端的加密数据交互,也就是个体间的端到端加密(E2EE End-2-End-Encry)。

这里有一个难点,为了防止加密密钥被破解/泄露,对称加密密钥通常是需要定期/不定期更换的,而非特定中心系统是没有权威时间的,端与端的时间是无法精确同步的。
因为这一特性,或者说缺陷,在时间的认定上需要有特别的设计。

每个消息Json的Timestamp属性都是客户端的时刻,而客户端的时刻是很容易被个体修改的。
那么非特定中心系统是不是没法用了?!
答案是非特定中心系统还是正常的使用,至少在个体层面可以。
非特定中心系统是为每一个个体设计的,赋予每一个个体平等、自由,其中最重要的一点是个体可以拒绝接收任何其他个体。
修改消息Json时间戳的目的是什么?欺骗其他个体。
欺骗与识别欺骗都是人类个体的事情,不是机器的事情。
机器只需要负责处理确定的规则,对每一个个体相同的规则,消息的序号每次递增1,消息的时间戳随序号增加也变大,这两点机器可以保障。
人类个体可以分析带有序号和时间戳的消息序列的每一条消息内容,及物理世界的情况,来分辨对方是否存在欺骗行为。

说了些理念和想法。
接着讲端与端时间同步的技术问题,在对方时间戳不受控的情况下,个体层面可以选择是/否交互。
在双方都选择交互的情况下,如何时间同步?
答案是客户端时间不同步,双方在逻辑的时间空间进行同步。

直接上聊天握手消息:
{
"Action":301, //这是一条聊天握手(密钥交换)消息
"Division":3, //1天的时间分块数,当前默认是3
"Sequence":, //时间块的序号
"DHPublicKey":, //本端DH公钥
"Pair":, //对端DH公钥
"To":, //聊天对象账号
"Timestamp":,
"PublicKey":,
"Signature":
}
在逻辑上将1天分成若干块,当前默认是1天3个块,每个块是8小时,[T+8H)、[T+8H-T+16H)、[T+16H-T+24H)
以某个时刻作为纪元起点,当前默认是Epoch=2011-11-11 11:11:11
以两个账号计算出一个小于86400000(1天的毫秒数)的整数作为偏移量Cursor(避免所有账号都在每天特定的时刻握手)
任意两个准备聊天的账号可以算出属于他俩的时间起点Epoch+Cursor,从这一刻开始每8个小时是一个时间块,第一个块序号为1,依次递增,在逻辑空间将时间全部分块,每一个时刻都落在某个时间块内,两端可以为每一个逻辑上的时间块协商出一个对称加密密钥

DH密钥交换过程简单提一下:
账号A生成公钥AP和私钥AS,生成消息DHPublicKey=AP,Pair="",发给账号B
账号B生成公钥BP和私钥BS,生成消息DHPublicKey=BP,Pair="",发给账号A
当A收BP后,发消息DHPublicKey=AP,Pair=BP给账号B
当B收AP后,发消息DHPublicKey=BP,Pair=AP给账号A
通信路径上节点只知道AP和BP,但不知道AS和BS
数学上可以保证f(AP,BS)=f(BP,AS)=X,这个X只有账号A和账号B知道
两端可以通过X生成一个相同的对称加密密钥,再用这个对称加密密钥加解密这个时间块内的所有消息

至此,两个账号就实现密钥协商、加密聊天。

这里还有一个难点,两个客户端不一定同时在线,服务端也不太适合缓存客户端加密以后的消息。
以上做法的好处是,维持了聊天消息的原子性,可以在个体的客户端独立生成,当双方在线时可以很好有序同步。
当前的网络环境,个体可以轻松保持在线状态,偶然下线不会造成数据混乱即可,离线消息并不是必要功能。

假设账号B离线前收到账号A发送的最后一条消息的序号是N,B上线后,又收到A发来的序号为M(M>N+1)的消息,B能够发现漏收消息,B为了维持一条序号连续的消息链,序号为M的消息无法被保存,B需要向A发送“消息同步”消息
{
"Action":303, //这是一条“消息同步”消息
"CurrentSequence":N, //B当前维护A的消息区块链的最后一个块的序号
"To":A, //聊天对象账号
"Timestamp":,
"PublicKey":,
"Signature":
}
账号A收到后,向B重发N之后的所有消息。

至此,离线再上线的消息同步也可以做到了。

私密聊天总共用到了3个消息范式,Action为301、302、303。