6

NEAR 的账户可以有许多不同的密钥对访问同一个账户。按键也可以更改和旋转。这意味着使用其公钥为特定用户加密消息的默认方式不起作用。

为特定用户加密消息的最佳模式是什么?

4

3 回答 3

5

NEAR 帐户密钥不适用于此用例。

通常,每个参与者都拥有多个设备,因此拥有端到端加密消息(在最具体的意义上是端到端加密聊天,但通常是任何交换加密消息的应用程序)并非易事。例如,出于某种原因,在 Telegram 中,私人聊天附加到设备上,而在其他设备上不可用。

原因是这通常需要在设备之间共享私钥,而安全地做到这一点本身就是一个挑战。

这是一个关于如何建立端到端加密聊天的逐字建议

a) 每个参与者都可能从多个设备参与
b) 消息不仅直接与某人共享,而且还与参与者的“组”共享。

设计目标是发送消息应该是恒定的时间(不取决于目标用户使用的设备数量/发送到的组中的人数),而某些操作可以是线性的。

有计划将其作为库添加到 NEAR,但尚未开始工作,也未计划开始。

提议

问题陈述: 我们希望可以添加新成员和删除旧成员的群聊;新成员能够在加入之前看到发布的消息是一项愿望清单功能;老成员离开后应该看不到新消息;用户应该能够使用多个设备并从所有设备查看所有群聊中的所有消息;每条消息必须存储一次(不是每个组的参与者一次);

建议的解决方案:

  1. 系统中存在三种密钥对:账户密钥(不要与 NEAR 账户密钥混淆)、设备密钥和消息密钥。

  2. 每个帐户只有一个帐户密钥。它是在帐户第一次使用该服务时生成的。

    account_keys:持久映射

  3. 第一次从设备访问聊天时(或每次擦除本地存储时),每个设备都有自己的设备密钥

    类 DeviceKey { name: string, device_public_key: PublicKey, encrypted_account_secret_key: EncryptedSecretKey?, }

    device_keys[account]: PersistentVector

    持久向量是每个账户的,每个这样的持久向量都包含设备公钥(设备私钥只存在于设备上),以及用这样的公钥加密的账户密钥,如果密钥没有用这样的公钥加密,则为 null公钥呢。

    管理设备密钥的方法有以下三种:

    addDeviceKey(device_public_key: PublicKey, name: string): void

添加新密钥,并将 null 关联为对应的加密帐户密钥。

    removeDeviceKey(device_public_key: PublicKey): void

删除设备密钥

authorizeDeviceKey(device_public_key: PublicKey, encrypted_account_secret_key: EncryptedSecretKey): void

设置设备密钥的加密帐户密钥。

因此,用户的流程将是:

a) 从新设备启动聊天,为其命名。
b) 从已经拥有加密帐户密钥的其他设备打开聊天,进入设备设置并授权新设备。

  1. 所有消息键都存储在一个大的持久向量中:
    all_message_public_keys: PersistentVector<PublicKey>

并且在所有其他地方都使用向量中的 u32 索引进行引用。每个用户都知道一些消息密钥:

encrypted_message_secret_keys[account]: PersistentMap<u32, EncryptedSecretKey>
encrypted_mesasge_secret_keys_indexes[account]: PersistentVector<u32>

地图和矢量是每个帐户。仅需要该向量,以便当用户更改其帐户密钥时,我们知道我们需要重新加密的所有消息密钥。密钥使用帐户密钥加密。

每个通道在每个时刻都有一个与之关联的消息密钥,尽管密钥可能会在通道的整个生命周期内发生变化。

channel_public_keys: PersistentMap<u32, u32>

其中键是通道 ID,值是消息键 ID。

  1. 每条消息都有一个 u32 字段,指示用于加密它的消息密钥。如果未加密,则值为 u32::max。每当将消息发送到通道时,都会使用当前通道消息密钥对其进行加密。

  2. 那么流程如下:

    当使用初始参与者集创建通道时,通道的创建者创建消息密钥对,使用每个参与者的帐户密钥加密密钥,并调用

    createChannel(channel_name: string,
                  accounts: AccountId[],
                  message_public_key: PublicKey,
                  encrypted_message_secret_keys: EncryptedSecretKey[])

这会注册消息密钥,将加密的密钥添加到相应的集合中,然后创建通道。

如果需要添加新用户,则addUserToChannel(account: AccountId, encrypted_message_secret_key) 将该用户添加到频道用户列表中,并授予他对最新消息访问密钥的访问权限。

如果需要删除用户,则deleteUserFromChallen(account: AccountId)删除该用户。在这种情况下,或者如果通道参与者认为他们的消息密钥被泄露,他们会调用

updateChannelMessageKey(message_public_key: PublicKey, 
                        encrypted_message_secret_keys: EncryptedSecretKey[])

请注意,由于每条消息都有关联的密钥,并且通道参与者没有失去对旧消息密钥的访问权限,因此现有通道参与者将能够读取所有历史记录,而无需重新加密它。但是,加入频道的新用户只能看到自上次更新密钥以来的消息。

  1. 当用户需要更新帐户密钥时,他们需要:
    a) 使用所有设备密钥对其进行加密;
    b) 用新的账户密钥加密他们所有的消息密钥;
    c) 将 (a) 和 (b) 提供给将更新相应集合的合同方法。

    在这样的过程之后,用户将可以使用新帐户密钥访问来自所有设备的所有旧消息。

于 2020-06-09T20:57:15.367 回答
1

事实上,没有默认的方法来做到这一点。最简单的方法是,如果特定应用程序(例如聊天需要加密消息)是要求用户“使用 NEAR 登录”——这将在应用程序端创建一个新的密钥对,并在用户帐户中为应用程序授权此公钥。

现在任何其他用户都可以扫描收件人的帐户并找到为此应用程序授权的密钥并将其用于加密。这与 Telegram 秘密聊天的行为类似,只能在启动聊天的单个设备上解密。

为了使这项工作跨设备(域、应用程序)工作,可以创建一个密钥对,其中公钥是已知的并附加到给定帐户。私钥也存储在链上,但使用来自不同设备的所有访问密钥进行加密。添加新设备/应用程序时,现有应用程序需要对此进行授权,这将允许在此会话中解密私钥并使用此会话的访问密钥重新加密。

于 2020-06-09T20:31:45.430 回答
0

是否有可能为此获得一些伪代码?我担心的另一个问题是这些应用程序私钥存储在哪里?通常我习惯于系统,我有一个私钥,我备份它或使用助记符。现在,当我登录到另一台设备时,我恢复了该密钥。

如何在多个设备上镜像私钥?

另一方面,查询链以获取用户的应用程序的特定公钥(甚至可能带有标签)是有意义的。

于 2020-06-09T20:38:23.657 回答