Skip to content

chore(WIP): migrate to @noble/curves and eciesjs #1236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

alexandre-abrioux
Copy link
Member

@alexandre-abrioux alexandre-abrioux commented Nov 13, 2023

Description of the changes

Get rid of:

Replace it with:

  • ethers for signatures, which uses @noble/curves under the hood starting in v6
  • eciesjs for encryption/decryption, which uses @noble/curves under the hood in browsers and the crypto module in Node.js

Note: @noble/curves is an audited library and now the industry standard used by ethers and viem.

Breaking change

The data encryption format changes. This is a breaking change as old versions of the protocol will not be able to decrypt new Requests. The impact should be limited to integrations where actors encrypting and decrypting the Request are different and not using the same version of the protocol, which should, I think, be negligible in the current state of our ecosystem.

The new encryption still uses ECIES but uses the following parameters:

  • curve: secp256k1
  • symmetric algorithm: AES-256-GCM
  • derivation method: HDKF

; versus previous configuration:

  • curve: secp256k1
  • symmetric algorithm: AES-256-CBC with HMAC authentication
  • derivation method: SHA512

Note: AES-256-GCM is considered safer than AES-256-CBC as it contains authentification without needing additional HMAC verification. See https://security.stackexchange.com/questions/184305/why-would-i-ever-use-aes-256-cbc-if-aes-256-gcm-is-more-secure

Related

In ecies/js#747 I've discussed the possibility of supporting the legacy AES-CBC algorithm for decryption, and this has been added by the maintainer. In the end, I did not use the library's feature because it does not fit our needs. Indeed, eccrypto was using AES-CBC-MAC (not just AES-CBC) so verifying the authentication is important before decryption. Furthermore, we have been serializing the encrypted data in a certain format (iv + publicKey + mac + cipher see here) which is not the expected format needed by the library (publicKey + iv + cipher) and there is no way to pass them down individually. For this reason, I have reimplemented the logic from scratch in utils/crypto/ec-utils-legacy.ts and made sure to verify the HMAC authentication for security.

@MantisClone
Copy link
Member

MantisClone commented Nov 14, 2023

I thought we were using GCM also, according to the old encryption audit. Is the CBC code actually used for anything?

https://request.network/en/2020/07/07/request-encryption-audit-completed-by-cure53/

Action: Use the authenticated encryption algorithm aes-256-gcm instead of aes-256-cbc and remove the hash.
Status: fixed – Commit 1 & Commit 2

@alexandre-abrioux
Copy link
Member Author

alexandre-abrioux commented Nov 18, 2023

@MantisClone There are two encryption stages. First, the request is encrypted using AES-256-GCM (symmetric encryption). The generated encryption key is later referred to as the channel key. This channel key is then encrypted with each shareholder's public key using ECIES (asymmetric encryption). This two-stage encryption scheme aims to reduce the size of the encrypted data; otherwise, we would have to encrypt the whole request as many times as there are shareholders. Instead, we encrypt the channel key multiple times, which is a minimal overhead—more details over here.

This PR only concentrates on the ECIES part. I didn't know this before, but ECIES also uses AES under the hood, and eccrypto uses AES-256-CBC. AEC "cbc" mode is not recommended because it has no "aead" tag, so I'm trying to find a way to upgrade while keeping compatibility for previously encrypted requests.

@MantisClone
Copy link
Member

@alexandre-abrioux now that ecies/js added support for AES-256-CBC in ecies/js#748, do you still think that it's possible to migrate to @noble/curves and ecies/js?

Are we blocked by the fact that ecies/js does not support the SHA512 key derivation function?

ecies/js#747 (comment):

Another point is that eccrypto is using sha512 (specifically the first 32 bytes of SHA512(ECDH(ephermeralPublicKey, publicKey)) to derive the shared key (https://github.com/bitchan/eccrypto/blob/master/index.js#L219 or https://github.com/torusresearch/eccrypto/blob/master/src/index.ts#L248) but we are using HDKF-SHA256, this also makes it incompatible.

ecies/js#747 (comment):

Since we don't have a plan to support SHA512 as a key derivation function, you may need to think about a migration strategy.

@alexandre-abrioux
Copy link
Member Author

@MantisClone I still think it's possible. We will probably have to implement our own decryption fallback class for supporting old requests with SHA512, but I haven't found time yet to look deeper.

Copy link
Contributor

coderabbitai bot commented Apr 12, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Comment on lines +30 to +45
const hmacSha256Verify = (key: Uint8Array, msg: Uint8Array, sig: Uint8Array): boolean => {
const expectedSig = hmac(sha256, key, msg);
return equalConstTime(expectedSig, sig);
};

// Compare two buffers in constant time to prevent timing attacks.
const equalConstTime = (b1: Uint8Array, b2: Uint8Array): boolean => {
if (b1.length !== b2.length) {
return false;
}
let res = 0;
for (let i = 0; i < b1.length; i++) {
res |= b1[i] ^ b2[i];
}
return res === 0;
};
Copy link
Member Author

@alexandre-abrioux alexandre-abrioux Apr 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using the Web Crypto API (available in Node.js and in browsers) this whole code (both methods hmacSha256Verify + equalConstTime) could be replaced by a single line:

globalThis.crypto.subtle.verify("HMAC", key, sig, msg)

Pros:

  • no need to use a library (@noble/hashes)
  • the Web Crypto API is async so non-thread blocking

Cons

  • the Web Crypto API is async so the calling code needs to be async too (but that's OK since ecEncrypt and ecDecrypt were already async in the previous implementation)
    - the Web Crypto API is only available in secure context (= HTTPS) (this could be a pain point in localhost environments)

Let me know if you would prefer it, I can easily make the switch.

@alexandre-abrioux alexandre-abrioux changed the title chore: migrate to @noble/curves and ecies/js chore: migrate to @noble/curves and eciesjs Apr 13, 2025
"moduleResolution": "node",
"moduleResolution": "nodenext",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed to load @ecies/ciphers/aes. The value node is deprecated anyway, we shouldn't use it, see https://www.typescriptlang.org/tsconfig/#moduleResolution

@alexandre-abrioux alexandre-abrioux changed the title chore: migrate to @noble/curves and eciesjs chore(WIP): migrate to @noble/curves and eciesjs Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants