Discourse 加密(已弃用)

Original Plugin Description
:discourse2: Summary Discourse Encrypt enables private, encrypted messaging between end-users. All sensitive information is stored securely on the server and is encrypted and decrypted only on the client-side.
:hammer_and_wrench: Repository Link https://github.com/discourse/discourse-encrypt
:open_book: Install Guide How to install plugins in Discourse

Three easy steps to use this plugin

  1. Enable encryption and activate current device.

  1. Send an encrypted message. The recipient must also have enabled encryption.

Optionally, you can determine the time after which the whole message or specific post will be permanently destroyed

  1. Read secret messages. Encryption must be activated first to read them.

Note: In this example, the user was prompted for paper key again because encryption was deactivated (by logging out or explicitly deactivating it from preferences screen).

Technical information

This plugin gives users the possibility to communicate securely through Discourse, by using an end-to-end encryption scheme. Most of plugin’s logic is implemented on the client-side and the server-side handles only public or encrypted information. It does not encrypt any post metadata, such as names of participants in the conversation, posted time, likes, small actions, etc; uploads are encrypted, but their presence is not because the system must associate uploads with posts to prevent deleting them.

The whole code is open-source and security enthusiasts are welcome to review it. For any further information, do not hesitate to contact me or the team. :slight_smile:

read more...

Summary

The goal of this plugin is to offer integrity and confidentiality of the encrypted contents, and to protect it against information leaks and unauthorized users. The following sections describe the usual operation mode, used algorithms and threat models.

To use this system, users enroll once by generating a “user identity” consisting of two 4096-bits RSA keys, one for encryption and another for signing. Users can export their “identity” for safe keeping or store it on the server, encrypted after generating a paper key. These two methods serve as backups or are used to enroll new devices.

Paper keys (inspired by RFC 1751 and BIP-39) are human-readable keys that are used to securely store the “user identity” on the server. A paper key consists of 12 random words, picked from a list of 2048 words, offering 121-bits of entropy (the first word is used as a label). To encrypt the “user identity” with a paper key, the system will first derive the encryption key using PBKDF2 to stretch the paper key into a 256-bit AES-GCM key.

Creating an encrypted post

To create a new post, the user (their browser) will:

  1. sign the current post content using their private signing key;

  2. generate a new “topic key” (a AES-256-GCM key) - which is going to be used to encrypt the post, some post metadata and the title of the new topic (if available);

  3. fetch the public keys of all participants and encrypt the “topic key” for each of them;

  4. send to the server the encrypted post (Base64 encoded) and the encrypted topic keys (also Base64 encoded) of each participant.

The pseudocode for the encryption operation would be something like:

signature = rsa_pss_sign(current_user.identity.sign_key.private, post.raw) # 1
topic_key = topic.key || generate_aes_256_gcm_key() # 2
encrypted_title = aes_256_gcm_encrypt(topic.title, topic_key) if topic.blank?
encrypted_post = aes_256_gcm_encrypt(signature + post.raw, topic_key)
encrypted_topic_keys = recipients.map { |r| rsa_oaep_encrypt(topic_key, r.identity.encryption_key.public) } # 3
$.put("/posts/create", { title: encrypted_title, raw: encrypted_post, keys: encrypted_topic_keys }) # 4

Reading an encrypted post

To read a post, the user (their browser) will:

  1. fetch the encrypted post payload (post plaintext and signature) and encrypted topic key;

  2. use their private encryption key to decrypt the encrypted topic key;

  3. use the decrypted topic key to decrypt the encrypted post payload;

  4. fetch the public signing key of the poster and verify the post signature.

Algorithm Suite

This plugin makes extensive use of the cryptographic primitives implemented in Web Crypto API, which are available in any of the modern browsers Discourse supports (except Internet Explorer).

  • getRandomValues PRNG: It generates paper keys and 96-bits random IVs.

  • PBKDF2: It stretches the 132-bit paper keys to 256-bit keys, used for encrypting “user identities”.

  • AES-256-GCM: Used to encrypt each post’s content. It also offers authentication by producing an authentication tag of 128-bits, but this is a less important aspect because posts are verified using a signature generated by the poster (see step 1 above).

  • RSA-OAEP: Used to encrypt “topic keys” and “user identites” for safe-keeping on the server. All RSA-OAEP keys are 4096-bits long.

  • RSA-PSS: Used to sign each post’s content for verifying authenticity. All RSA-PSS keys are 4096-bits long.

Primitives

The system uses a set of primitives built on top of those provided by the browser via Web Cryptography API.

  • encrypt and decrypt: Used to encrypt and decrypt post contents. encrypt takes a JSON, an AES-256-GCM key and a RSA-PSS public key and outputs a single Base64 encoded string; decrypt takes a Base64 encoded string and an AES-256-GCM key and outputs the initial JSON object;

  • verify: Used to verify post contents after decryption;

  • exportKey and importKey: Used to export and import “topic keys”;

  • exportIdentity and importIdentity: Used to export and import “user identities”.

Types of keys:

  • topic keys (AES-256-GCM)

  • RSA key-pair (public and private keys) (RSA-OAEP and RSA-PSS, 4096-bits)

    • used to encrypt all topic keys a user has access to
    • are generated per user on the client-side by the original poster using WebCrypto’s API generateKey primitive and shared amongst all of user’s devices
    • server-side: public identity is stored as exported by the client, but the private identity will always be encrypted with the passphrase key
    • client-side: public and private keys are stored as CryptoKey in IndexedDb; if not possible, it will use window.localStorage (in Safari)
  • passphrase keys (derived using PKBDF2 with 128,000 iterations)

    • used to encrypt “user identities” for safe storage on the server
    • derived from a paper key (or user’s passphrase for legacy purposes)

Threat models

Compromised Discourse Instance

An attacker which can inject code could in theory access encrypted information by serving malicious code, which decrypts the encrypted content and sends the plaintext posts to another server. To make this possible, it is enough to have access to an administrator account and create a theme component with the malicious code.

Default protection mechanisms such as CSP can detect and mitigate Cross Site Scripting (XSS) attacks that could also represent a way of injecting malicious code.

Man-in-the-Middle Attack

In Man-in-the-Middle attacks, the attacker intercepts the communication between the user and server, giving them the ability to read or alter it. Because the plugin encrypts everything before sending, an attacker cannot decrypt anything by simply eavesdropping. Similarly, because information is authenticated the attacker cannot alter it.

However, the attacker could serve malicious code back to the user and follow a similar attack to the one presented in the previous section. This is partially mitigated by HTTPS, which is considerably reducing the attack probability.

Notes

The plugin already has a little history and that can be seen while browsing the source code and noticing the two implementations of the protocol v0 (initial, alpha-beta release) and v1. Protocol v0 is no longer used to encrypt new posts, but kept to continue decrypting old ones. New protocol includes authenticity of the ciphertexts and all posts are signed with the private key of the poster.

Other Resources

Last edited by @david 2024-12-03T15:46:08Z

Check documentPerform check on document:
98 个赞

11 条帖子已拆分到新主题:角色扮演游戏的帖子部分隐藏

如何才能启用向群组发送加密消息?群组的所有用户和消息发送者都已启用加密,但我仍然收到错误消息:

“您无权向群组发送加密消息。”

3 个赞

我认为目前无法向群组发送加密的私人消息。

2 个赞

这意味着群组邮箱会失效吗?或者邀请群组加入私信将无法正常工作?

这,一开始就不可能。

是否需要提交关于此问题的错误报告?

一切似乎都正常,只是打开时有延迟,但私信并未加密。

1 个赞

无需重复发帖,但如果您想将其作为#bug report(错误报告)而不是#support request(支持请求),可以遵循以下指南,然后重新分类 - Writing an effective bug report

不过值得注意的是,无论是错误报告还是支持请求,都需要时间才能获得关注,尤其是在周末。

5 个赞

:mega: 不幸的是,由于采用率相对较低且维护成本高昂,discourse-encrypt 的支持将在核心产品的下一个稳定版本(2025 年第一季度)发布后停止。

此主题的原始帖子 已更新,包含更多信息,我们将为受影响站点的管理员引入自动警告。

14 个赞

希望未来能开发出来。
这在数据/区块链/安全领域非常重要/有用。

6 个赞

10 个帖子被拆分为新主题:除非管理员是参与者,否则不向管理员显示主题和 PM

继续讨论 Discourse Encrypt (已弃用)

时机已到,最新的 Discourse 更新似乎与 Discourse Encrypt 不兼容。

我们的症状是,没有人能够回复帖子;系统开始加载回复视图,但从未成功加载实际的编辑器。

关闭 Discourse Encrypt 可以解决问题,重新启用它则会带回问题。

由于此插件已弃用,我不会将其报告为错误,我只是报告它,以便其他人可以预料到这种行为。

另外,如果有人知道可以提供给希望能够下载加密消息并离线解码的个人的资源,我们将不胜感激。

4 个赞