概述
设备(端)的定义
我们对“设备”有特殊的含义。作为用户,我可能有多个设备(桌面客户端、一些网络浏览器、Android 设备、iPhone 等)。当我第一次使用客户端时,它应该将自己注册为新设备。如果我注销并以其他用户身份再次登录,则客户端必须注册为新设备。至关重要的是,客户端必须为每个“设备”创建一组新的密钥。
设备的寿命将取决于客户端。在 Web 客户端中,我们会在您每次登录时创建一个新设备。在移动客户端中,如果登录会话过期, 如果用户相同,则可以重新使用该设备。切勿在不同用户之间共享密钥。
设备由它们标识device_id
(在给定用户的范围内是唯一的)。默认情况下,/login
and/register
端点会自动生成 adevice_id
并在响应中返回它;客户端也可以自由生成自己device_id
的设备,或者如上所述,重用设备,在这种情况下,客户端应该 device_id
在请求正文中传递 。
设备的寿命和access_token
s密切相关。device_id
在每次登录时都会创建一个新设备的简单情况下,a和 an之间存在一对一的映射access_token
。如果客户端device_id
在登录时重用 a,将会有几个 access_token
s 与给定的关联device_id
- 但是,我们仍然希望其中只有一个同时处于活动状态(尽管我们目前在 Synapse 中没有强制执行)。
端到端加密中使用的密钥
Ed25519指纹密钥对
Ed25519 是用于签署消息的公钥加密系统。
Curve25519 身份密钥对
Curve25519 是一种公钥密码系统,可用于建立共享秘密。
Curve25519 一次性键
除身份密钥外,每个设备还创建多个 Curve25519 密钥对,这些密钥对也用于建立 Olm 会话,但只能使用一次。隐私部分再次保留在设备上。
在启动时,Alice 创建了许多一次性密钥对,并将它们发布到她的家庭服务器。如果 Bob 想与 Alice 建立一个 Olm 会话,他需要获取 Alice 的一个一次性密钥,并创建一个他自己的新密钥。这两个密钥与 Alice 和 Bob 的身份密钥一起用于在 Alice 和 Bob 之间建立 Olm 会话。
Megolm 加密密钥
Megolm 密钥用于加密组消息(实际上它用于派生 AES-256 密钥和 HMAC-SHA-256 密钥)。它用随机数据初始化。每次发送消息时,都会对 Megolm 密钥进行哈希计算,以导出下一条消息的密钥。因此,可以与用户共享 Megolm 密钥的当前状态,允许他们解密未来的消息,但不能解密过去的消息。
Ed25519 Megolm 签名密钥对
当发件人创建 Megolm 会话时,他还会创建另一个 Ed25519 签名密钥对。这用于对通过该 Megolm 会话发送的消息进行签名,以验证发件人。再一次,密钥的私有部分仍保留在设备上。公共部分与加密密钥旁边的房间中的其他设备共享。
创建和注册设备密钥
此过程仅在设备首次启动时发生一次。
它必须创建 Ed25519 指纹密钥对和 Curve25519 身份密钥对。这是通过调用olm_create_account
libolm 来完成的。通过调用来检索(base64 编码的)键 olm_account_identity_keys
。应存储该帐户以备将来使用。
然后它应该将这些密钥发布到主服务器,这是通过使用keys/upload 接口的device_keys
属性来 完成的。
创建和注册一次性密钥
客户端应跟踪主服务器为其存储了多少一次性密钥,并在必要时生成并上传更多。
这可以通过检查响应的device_one_time_keys_count
属性来实现。/sync/
libolm 支持的最大活动键数由 olm_account_max_number_of_one_time_keys
. 客户端应该尝试在主服务器上保持这个数字的一半左右。
要生成新的一次性密钥:
-
调用
olm_account_generate_one_time_keys
以生成新密钥。 -
调用
olm_account_one_time_keys
以检索未发布的密钥。这将返回一个带有单个属性的 JSON 格式的对象curve25519
,它本身就是一个对象映射键 id 到 base64 编码的 Curve25519 键。例如:{
"curve25519": {
"AAAAAA": "wo76WcYtb0Vk/pBOdmduiGJ0wIEjW4IBMbbQn7aSnTo",
"AAAAAB": "LRvjo46L1X2vx69sS9QNFD29HWulxrmW11Up5AfAjgU"
}
}
-
每个密钥都应该以与之前的身份密钥有效负载相同的方式进行签名,并使用keys/upload接口的
one_time_keys
属性进行 上传。 -
调用
olm_account_mark_keys_as_published
以告诉 olm 库不要从未来调用返回相同的键olm_account_one_time_keys
。
curve25519-aes-sha2
事件内容的sender_key
属性给出了发送者的 Curve25519 身份密钥。客户应该为他们与之交谈的每台设备维护一个已知的 Olm 会话列表;建议通过 Curve25519 身份密钥对它们进行索引。
Olm 消息为每个接收设备单独加密。 ciphertext
是来自接收设备的 Curve25519 身份密钥的对象映射。接收客户端当然应该在这个对象中寻找自己的身份密钥。(如果它没有被列出,则没有为它发送消息,并且客户端无法解密它;它应该显示一个错误,或者类似的)。
这应该会产生一个具有属性type
和的对象body
。“0”类型的消息是“prekey”消息,用于在两个设备之间建立新的 Olm 会话;类型“1”是在会话中收到消息后使用的普通消息。
当收到一条消息(任一类型)时,客户端应首先尝试使用该发送者的每个已知会话对其进行解密。有两个步骤:
- 如果(且仅当)
type==0
,客户端应olm_matches_inbound_session
使用会话和body
. 这将返回一个标志,指示消息是否使用该会话加密。 olm_decrypt
客户端通过会话调用,type
和body
。如果成功,则返回事件的明文。
如果客户端无法使用任何已知会话解密消息(或者如果还没有已知会话),并且消息的类型为 0, 并且 olm_matches_inbound_session
对于任何现有会话都不是真的,那么客户端可以尝试建立新会话. 这是按如下方式完成的:
olm_create_inbound_session_from
使用 olm 帐户调用,sender_key
以及body
消息的和。- 如果会话建立成功:
- 调用
olm_remove_one_time_keys
以确保不能重复使用相同的一次性密钥。 olm_decrypt
与新会话通话。- 存储会话以供将来使用。
- 调用
最后,客户端有望成功解密有效载荷。
除了type
和content
属性外,明文有效负载还应包含许多其他属性。每一项都应检查如下2。
-
sender
: 发件人的用户 ID。客户端应检查这是否与sender
事件中的 匹配。 -
recipient
: 收件人的用户 ID。客户端应检查这是否与本地用户 ID 匹配。 -
keys
:具有属性的对象ed25519,keys被验证时
,客户端应检查此属性的值是否与发送者的指纹密钥匹配。 -
recipient_keys
:具有属性的对象ed25519
。客户端应检查此属性的值是否与其自己的指纹密钥匹配。
aes-sha2
使用此算法的加密事件应具有sender_key
, session_id
和ciphertext
content 属性。如果room_id
和 对应于已知的 Megolm 会话(见 sender_key
下文),则可以通过将密文传递给 来解密密文。session_id
olm_group_decrypt
为了避免重放攻击,客户端应该记住 他们为每个会话解密的每个事件message_index
返回的 megolm。olm_group_decrypt
如果客户端解密一个与 message_index
它已经使用该会话接收到的事件相同的事件,那么它应该将该消息视为无效。但是,当一个事件被多次解密时,必须小心不要将其标记为重放攻击。例如,当客户端解密事件时,可能会发生这种情况,该事件从客户端的缓存中清除,然后客户端回填并重新解密该事件。处理这种情况的一种方法是确保在message_index
清除客户端的事件缓存时适当地清除 es 的记录。另一种方法是记住事件的 event_id
和origin_server_ts
message_index
. 当客户端解密一个与 message_index
先前解密的事件匹配的事件时,它可以比较它记住的event_id
和,如果这些字段匹配,则应该正常解密消息。origin_server_ts
message_index
当事件被已验证时,客户端应检查发送者的指纹密钥是否与 keys.ed25519
建立 Megolm 会话的事件的属性相匹配。
为房间内的用户下载设备列表
在发送加密消息之前,有必要为房间中的每个用户检索设备列表。这可以主动完成,也可以推迟到发送第一条消息。用户还需要这些信息来验证或阻止该消息。
客户端应该使用device_keys接口
,在请求的属性中 传递房间成员的 ID 。
客户端必须使用DeviceKeys
返回 的对象的签名。为此,它应该删除和属性,将其余部分格式化为规范 JSON,并将结果传递到 ,使用参数的 Ed25519 密钥和参数的相应签名。如果签名检查失败,则不应在设备上进行进一步处理。signatures
unsigned
olm_ed25519_verify
key
signature
客户端还必须检查对象中的user_id
和device_id
字段是否与顶级映射3中的字段匹配。
客户端应该检查user_id
/是否device_id
对应于它之前看到的设备。如果是,客户端必须检查 Ed25519 密钥是否未更改。同样,如果它已更改,则不应在设备上进行进一步处理。
否则,客户端将存储有关此设备的信息。
发送加密消息事件
在房间中发送消息时,客户端首先检查它是否具有活动的出站 Megolm 会话。如果没有,它首先会创造一个。如果存在出站会话,它应该检查是否该 替换它,如果是则创建一个新会话。
然后客户端构建一个加密有效载荷,如下所示:
<span style="color:#333333"><span style="background-color:#ffffff"><span style="color:black"><code class="language-text">{
"type": "<event type>",
"content": "<event content>",
"room_id": "<id of destination room>"
}</code></span></span></span>
并调用olm_group_encrypt
加密有效载荷。然后将其打包到事件内容中,如下所示:
<span style="color:#333333"><span style="background-color:#ffffff"><span style="color:black"><code class="language-text">{
"algorithm": "m.megolm.v1.aes-sha2",
"sender_key": "<our curve25519 device key>",
"ciphertext": "<encrypted payload>",
"session_id": "<outbound group session id>",
"device_id": "<our device ID>"
}</code></span></span></span>
最后,加密的事件被发送到房间 PUT消息
最后
以上就是舒服高山为你收集整理的如何实现端到端加密,该如何设计的全部内容,希望文章能够帮你解决如何实现端到端加密,该如何设计所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复