NEAR 的账户可以有许多不同的密钥对访问同一个账户。键也可以改变和旋转。这意味着使用公钥为特定用户加密消息的默认方式不起作用。
为特定用户加密消息的最佳模式是什么?
NEAR 帐户密钥不适用于此用例。
通常,与具有多个设备的每个参与者拥有端到端加密消息(在最具体的意义上是端到端加密聊天,但通常是交换加密消息的任何应用程序)并非易事。例如,在 Telegram 中,私人聊天是附加到一个设备上的,而在其他设备上不可用。
原因是通常这需要在设备之间共享私钥,安全地做到这一点本身就是一个挑战。
这是关于如何构建端到端加密聊天的逐字建议
a) 每个参与者可能从多个设备参与
b) 消息不仅直接与某人共享,而且还与参与者“组”共享。
设计目标是发送消息的时间应该是恒定的(不取决于目标用户使用的设备数量/发送到的组中的人数),而某些操作可以是线性的。
有一个计划将它作为一个库添加到 NEAR,但它的工作还没有开始,也没有计划开始。
问题描述: 我们想要群聊,可以加入新成员,可以移除老成员;新成员能够在加入之前查看发布的消息是一项愿望清单功能;老成员离开后应该看不到新消息;用户应该能够使用多个设备,并在所有设备上查看所有群聊中的所有消息;每条消息必须存储一次(不是每个组的参与者一次);
建议的解决方案:
系统中有三种密钥对:帐户密钥(不要与 NEAR 帐户密钥混淆)、设备密钥和消息密钥。
每个帐户只有一个帐户密钥。它是在帐户第一次使用该服务时生成的。
account_keys:PersistentMap
第一次从设备访问聊天时(或每次擦除本地存储时),每个设备都有自己的设备密钥
class DeviceKey { name: string, device_public_key: PublicKey, encrypted_account_secret_key: EncryptedSecretKey?, }
device_keys[account]: 持久向量
持久向量是每个账户的,每个这样的持久向量包含设备公钥(设备私钥只存在于设备上),以及用这样的公钥加密的账户密钥,如果没有用这样的公钥加密,则为空。公钥呢。
管理设备密钥的方法有以下三种:
addDeviceKey(device_public_key: PublicKey, name: string): void
Run Code Online (Sandbox Code Playgroud)
添加新密钥,并将null关联为对应的加密帐户密钥。
removeDeviceKey(device_public_key: PublicKey): void
Run Code Online (Sandbox Code Playgroud)
删除设备密钥
authorizeDeviceKey(device_public_key: PublicKey, encrypted_account_secret_key: EncryptedSecretKey): void
Run Code Online (Sandbox Code Playgroud)
设置设备密钥的加密帐户密钥。
因此,用户的流程将是:
a) 从新设备启动聊天,为其命名。
b) 从其他已经拥有加密账户密钥的设备打开聊天,进入设备设置并授权新设备。
all_message_public_keys: PersistentVector<PublicKey>
Run Code Online (Sandbox Code Playgroud)
在所有其他地方都使用 u32 索引引用到向量中。每个用户都知道一些消息密钥:
encrypted_message_secret_keys[account]: PersistentMap<u32, EncryptedSecretKey>
encrypted_mesasge_secret_keys_indexes[account]: PersistentVector<u32>
Run Code Online (Sandbox Code Playgroud)
地图和矢量是每个帐户。只需要向量,以便当用户更改他们的帐户密钥时,我们知道需要重新加密的所有消息密钥。密钥使用帐户密钥加密。
每个通道在每一时刻都有一个与之关联的消息键,尽管在通道的整个生命周期中这些键可能会发生变化。
channel_public_keys: PersistentMap<u32, u32>
Run Code Online (Sandbox Code Playgroud)
其中 key 是频道 ID,value 是消息键 ID。
每条消息都有一个 u32 字段,指示使用什么消息密钥对其进行加密。如果未加密,则值为 u32::max。每当将消息发送到通道时,都会使用当前通道消息密钥对其进行加密。
流程如下:
当使用初始参与者集创建通道时,通道的创建者创建消息密钥对,使用每个参与者的帐户密钥加密密钥,并调用
createChannel(channel_name: string,
accounts: AccountId[],
message_public_key: PublicKey,
encrypted_message_secret_keys: EncryptedSecretKey[])
Run Code Online (Sandbox Code Playgroud)
这会注册消息密钥,将加密的密钥添加到相应的集合中,并创建通道。
如果需要添加新用户,则addUserToChannel(account: AccountId, encrypted_message_secret_key) 将该用户添加到频道用户列表中,并授予其访问最新消息访问密钥的权限。
如果需要删除deleteUserFromChallen(account: AccountId)用户,则删除该用户。在这种情况下,或者如果频道参与者认为他们的消息密钥被泄露,他们会打电话给
updateChannelMessageKey(message_public_key: PublicKey,
encrypted_message_secret_keys: EncryptedSecretKey[])
Run Code Online (Sandbox Code Playgroud)
请注意,由于每条消息都有关联的密钥,并且通道参与者不会失去对旧消息密钥的访问权限,因此现有通道参与者将能够读取所有历史记录,而无需重新加密。但是,加入频道的新用户只会看到自上次更新密钥以来的消息。
当用户需要更新账户密钥时,他们需要:
a) 用所有设备密钥对其进行加密;
b) 用新的账户密钥加密他们所有的消息密钥;
c) 将 (a) 和 (b) 提供给将更新相应集合的合同方法。
在此过程之后,用户将可以使用新帐户密钥访问来自所有设备的所有旧消息。
事实上,没有默认的方法可以做到这一点。最简单的方法是,如果特定应用程序(例如聊天)需要加密消息,则要求用户“使用 NEAR 登录” - 这将在应用程序端创建一个新的密钥对,并在应用程序的用户帐户中授权此公钥。
现在,任何其他用户都可以扫描收件人的帐户并找到授权该应用程序的密钥并使用它进行加密。这与 Telegram 秘密聊天类似,只能在启动聊天的单个设备上解密。
为了使这项工作跨设备(域、应用程序),可以创建一对密钥,其中公钥已知并附加到给定帐户。私钥也存储在链上,但使用来自不同设备的所有访问密钥进行加密。添加新设备/应用程序时,现有应用程序需要对此进行授权,这将允许解密此会话中的私钥并使用此会话的访问密钥重新加密。
| 归档时间: |
|
| 查看次数: |
108 次 |
| 最近记录: |