Skip to content
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

Secure Curves in the Web Cryptography API - secp256k1, X25519, X448, Ed25519, Ed448 #4224

Open
suchislife801 opened this issue Jan 19, 2024 · 6 comments
Labels
crypto suggestion a suggestion yet to be agreed

Comments

@suchislife801
Copy link

suchislife801 commented Jan 19, 2024

Is your feature request related to a problem? Please describe.

The current Web Cryptography API lacks support for Secure Curves such assecp256k1, X25519, X448, Ed25519, Ed448, which are essential for robust cryptographic operations. This limitation restricts the API's utility in scenarios requiring advanced security, such as in the implementation of certain modern cryptographic protocols like Signal's X3DH Key Agreement protocol for example.

Describe the solution you'd like

I propose the integration of Secure Curves into the Web Cryptography API, as outlined in the WICG draft (https://wicg.github.io/webcrypto-secure-curves/). This addition would enhance the cryptographic capabilities of the API, allowing developers to leverage these advanced curves for more secure and efficient cryptographic operations.

The following curves are currectly not available:

x25519 - The "X25519" algorithm identifier is used to perform key agreement using the X25519 algorithm specified in [RFC7748].

x448 - The "X448" algorithm identifier is used to perform key agreement using the X448 algorithm specified in [RFC7748].

ed25519 - The "Ed25519" algorithm identifier is used to perform signing and verification using the Ed25519 algorithm specified in [RFC8032].

ed448 - The "Ed448" algorithm identifier is used to perform signing and verification using the Ed448 algorithm specified in [RFC8032].

Describe alternatives you've considered

An alternative could be to use third-party libraries that implement Secure Curves. However, this approach may not be as efficient or secure as having native support within the Web Cryptography API itself. Native support ensures standardized implementation and better integration with the web platform.

@iuioiua
Copy link
Collaborator

iuioiua commented Jan 22, 2024

I like the idea. I'm happy to hear other thoughts, too. Any opinions on this, @jeremyBanks?

@iuioiua iuioiua added suggestion a suggestion yet to be agreed crypto labels Jan 22, 2024
@suchislife801 suchislife801 changed the title Secure Curves in the Web Cryptography API - X25519, X448, Ed25519, Ed448 Secure Curves in the Web Cryptography API - secp256k1, X25519, X448, Ed25519, Ed448 Jan 23, 2024
@kt3k
Copy link
Member

kt3k commented Jan 23, 2024

I propose the integration of Secure Curves into the Web Cryptography API

Do you propose this feature as addition to builtin Web Crypto API? Or do you suggest this feature as extension in std/crypto?

@littledivy
Copy link
Member

We have partial support for Secure curves in WebCrypto. Here is the tracking issue: denoland/deno#16145

@suchislife801
Copy link
Author

suchislife801 commented Jan 23, 2024

@kt3k The Web Crypto API looks so clean. Deno has integrated new digests via std/crypto into the Web Crypto API and the experience is seamless so that works too.

Example 1: X25519 key agreement

// Generate a key pair for Alice.
const alice_x25519_key = await crypto.subtle.generateKey('X25519', false /* extractable */, ['deriveKey']);
const alice_private_key = alice_x25519_key.privateKey;

// Normally, the public key would be sent by Bob to Alice in advance over some authenticated channel.
// In this example, we'll generate another key pair and use its public key instead.
const bob_x25519_key = await crypto.subtle.generateKey('X25519', false /* extractable */, ['deriveKey']);
const bob_public_key = bob_x25519_key.publicKey;

// Perform the key agreement.
const alice_x25519_params = { name: 'X25519', public: bob_public_key };
const alice_shared_key = await crypto.subtle.deriveKey(alice_x25519_params, alice_private_key, 'HKDF', false /* extractable */, ['deriveKey']);

// Derive a symmetric key from the result.
const salt = crypto.getRandomValues(new Uint8Array(32));
const info = new TextEncoder().encode('X25519 key agreement for an AES-GCM-256 key');
const hkdf_params = { name: 'HKDF', hash: 'SHA-256', salt, info };
const gcm_params = { name: 'AES-GCM', length: 256 };
const alice_symmetric_key = await crypto.subtle.deriveKey(hkdf_params, alice_shared_key, gcm_params, false /* extractable */, ['encrypt', 'decrypt']);

// Encrypt some data with the symmetric key, and send it to Bob. The IV must be passed along as well.
const iv = crypto.getRandomValues(new Uint8Array(12));
const message = new TextEncoder().encode('Hi Bob!');
const encrypted = await crypto.subtle.encrypt({ ...gcm_params, iv }, alice_symmetric_key, message);

// On Bob's side, Alice's public key and Bob's private key are used, instead.
// To get the same result, Alice and Bob must agree on using the same salt and info.
const alice_public_key = alice_x25519_key.publicKey;
const bob_private_key = bob_x25519_key.privateKey;
const bob_x25519_params = { name: 'X25519', public: alice_public_key };
const bob_shared_key = await crypto.subtle.deriveKey(bob_x25519_params, bob_private_key, 'HKDF', false /* extractable */, ['deriveKey']);
const bob_symmetric_key = await crypto.subtle.deriveKey(hkdf_params, bob_shared_key, gcm_params, false /* extractable */, ['encrypt', 'decrypt']);

// On Bob's side, the data can be decrypted.
const decrypted = await crypto.subtle.decrypt({ ...gcm_params, iv }, bob_symmetric_key, encrypted);
const decrypted_message = new TextDecoder().decode(decrypted);

@jeremyBanks
Copy link
Contributor

I think this would be a valuable addition. I'm not sure whether the stage it's at in standardization is or is not sufficient for inclusion in the built-in WebCrypto implementation (maybe it is), but it's certainly widely used enough to justify inclusion in std/crypto. But non-extractable keys might not work appropriately in a library implementation, so maybe some trade-off would have to be made there... (can't dig in myself right now because I have a newborn but I like the idea if it can be practical).

@suchislife801
Copy link
Author

Aren't all keys currently extractable as JSON Web Key?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
crypto suggestion a suggestion yet to be agreed
Projects
None yet
Development

No branches or pull requests

5 participants