mdn / content

The content behind MDN Web Docs
https://developer.mozilla.org
Other
9k stars 22.44k forks source link

SubtleCrypto: sign() method missing Ed25519 in Supported algorithms #30886

Open guest271314 opened 7 months ago

guest271314 commented 7 months ago

MDN URL

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/sign

What specific section or headline is this issue about?

Supported algorithms

What information was incorrect, unhelpful, or incomplete?

Missing Ed25519.

What did you expect to see?

Ed25519 algorithm listed.

Do you have any supporting links, references, or citations?

https://github.com/GoogleChromeLabs/webbundle-plugins/issues/11#issuecomment-1847301072

Yes. Node support is unfortunately required as long as Ed25519 keys are not supported by SubtleCrypto so that JS-only library would be possible. So node is needed in order to sign a web bundle, as Node's Crypto API supports Ed25519 keys.

https://github.com/GoogleChromeLabs/webbundle-plugins/issues/11#issuecomment-1847301072

It's not limited to node-only as there's also golang version of the package. Whenever the support for ed25519 keys is added to SubtleCrypto, it'll be rather simple to create a browser-only version of the wbn-sign package. Web bundles are still experimental and I'm sure the tooling coverage improves when use of IWAs increases.

This modified version of Deno test code https://github.com/denoland/deno/blob/ca64771257d23ceee97e882965269702c359f6aa/cli/tests/node_compat/test/parallel/test-webcrypto-sign-verify.js#L115-L133 logs true on Chromium Version 122.0.6170.0 (Developer Build) (64-bit).

// Test Sign/Verify Ed25519
{

  async function test(data) {
    const {subtle} = self.crypto;
    const ec = new TextEncoder();
    const { publicKey, privateKey } = await subtle.generateKey({
      name: 'Ed25519',
    }, true, ['sign', 'verify']);

    const signature = await subtle.sign({
      name: 'Ed25519',
    }, privateKey, ec.encode(data));

    console.log(await subtle.verify({
      name: 'Ed25519',
    }, publicKey, signature, ec.encode(data)));
  }

  test('hello world').catch(console.error);
}

Do you have anything more you want to share?

No response

guest271314 commented 7 months ago

Secure Curves in the Web Cryptography API

The Implementation of the Ed25519 algorithm landed Chromium in Nov 2022 and shipped in Chrome 110.0.5424.0. The X25519 key sharing algorithm took more time due to the review process, but it finally landed in March 2023 and has been shipped in Chrome since 113.0.5657.0.

bsmth commented 6 months ago

Thanks for opening this one. That page is targeting this spec: https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign which does not include Ed25519 or others.

The spec that covers the algorithms with the missing secure curves is at this state:

This specification was published by the Web Platform Incubator Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. ... This is an unofficial proposal.

Although there's partial / experimental support, it looks a little early to include these at the moment. If we were to add anything, it would likely be under https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto#supported_algorithms with some indication of status and resources to learn more.

guest271314 commented 6 months ago

There's a whole bunch of proposals that are implemented in the wild and are documented on MDN. E.g., WICG File System Access API, not to be confused with WHATWG File System Standard. Direct Sockets in Isolated Web Apps are shipped on Chromium. That's how I can create a TCPSocket in the browser.

Node.js, Deno, Bun, and Chromium 122 all implement Ed25519.

The problem is the authors wbn-sign quoted MDN as the source for information re Ed25519 algorithm as a reason for using Node.js crypto to sign the Web Bundle, and Node.js crypto cannot be polyfilled as far as I can tell. It took a while to figure this out. When I did I used the same Web Cryptography API code for Node.js, Deno, and Bun

Next I'm going to use the same code in the browser, substituting WICG File System Access API for Node.js fs.

This has to be written up somewhere on MDN Web Docs so people can't make excuses for why they are using Node.js crypto for Ed25519, as if only node implements the algorithm, and point to MDN omission as canonical source.

guest271314 commented 6 months ago

@bsmth I see the "waiting for implementations" label. Chromium and Chrome, Node.js, Deno, and Bun all implement Ed25519. Chromium and Chrome and Deno directly via Web Cryptography API, Bun using const {webcrypto} = "node:crypto". I actually haven't tested Firefox Nightly 123 yet. How many (more) implementations are you looking for or do you need to write this up in MDN Web Docs so folks can't say, look, MDN doesn't include the algorithm, therefore it must not be implemented by anybody other than Node.js, and not via webcrypto, rather via the internal crypto?

bsmth commented 6 months ago

Thanks for the feedback. Where I've added waiting for implementations, I'm specifically talking about the experimental work that is intended to land in SubtleCrypto. i.e., it's not possible to do window.crypto.subtle.sign('Ed25519'... anywhere yet as it's not even landed on the spec, or have I misunderstood?

For some context, I got started on this already today adding an ed25519 example to https://github.com/mdn/dom-examples/tree/main/web-crypto/sign-verify before I realized why it wasn't working on Chrome canary and came back to re-read the issue and linked resources.

I'm more than happy to include documentation for the missing algos, but it needs to be clear it's not part of this API yet. Can we consider where to include it or pitfalls readers should be aware of?

guest271314 commented 6 months ago

Thanks for the feedback. Where I've added waiting for implementations, I'm specifically talking about the experimental work that is intended to land in SubtleCrypto. i.e.,

That implementation has already landed in

i.e., it's not possible to do window.crypto.subtle.sign('Ed25519'... anywhere yet as it's not even landed on the spec, or have I misunderstood?

Yes, it's possible. I linked to the repositories above

https://github.com/guest271314/webbundle/blob/50d73ff7b6403bf62c5eff3492887a1194401e83/index.js#L45

await webcrypto.subtle.sign(algorithm, cryptoKey.privateKey, data),

The works in Node.js, Deno, and Bun using the same code. The code also works on Chromium 122 Developer Build.

Screenshot_2024-01-19_17-12-45

This is the MDN source the GoogleChrome author referenced, which turns out is inaccurate information.

https://github.com/GoogleChromeLabs/webbundle-plugins/issues/11#issuecomment-1847224287

Yes. Node support is unfortunately required as long as Ed25519 keys are not supported by SubtleCrypto so that JS-only library would be possible. So node is needed in order to sign a web bundle, as Node's Crypto API supports Ed25519 keys.

See this Deno test https://github.com/denoland/deno/blob/ca64771257d23ceee97e882965269702c359f6aa/cli/tests/node_compat/test/parallel/test-webcrypto-sign-verify.js#L115-L133

// Test Sign/Verify Ed25519
{
  async function test(data) {
    const ec = new TextEncoder();
    const { publicKey, privateKey } = await subtle.generateKey({
      name: 'Ed25519',
    }, true, ['sign', 'verify']);

    const signature = await subtle.sign({
      name: 'Ed25519',
    }, privateKey, ec.encode(data));

    assert(await subtle.verify({
      name: 'Ed25519',
    }, publicKey, signature, ec.encode(data)));
  }

  test('hello world').then(common.mustCall());
}

and read this Secure Curves in the Web Cryptography API which might be the source of your idea that Ed25519 is not implemented. It's implemented in a lot of JavaScript runtimes and Chrome and Chromium, listed above - not in Firefox Nightly 123

Screenshot_2024-01-19_17-21-53

That's 1 not implemented out of 4 separate JavaScript runtimes (counting Chromium and Chrome as 1, even though they are not the same browser).

Just run the code here https://github.com/guest271314/webbundle using Node.js (I'm running nightly release 22), Deno, Bun and run this code

const algorithm = { name: "Ed25519" };
const encoder = new TextEncoder();
const cryptoKey = await crypto.subtle.generateKey(
  algorithm,
  true, /* extractable */
  ["sign", "verify"],
);

console.log(await crypto.subtle.sign(algorithm, cryptoKey.privateKey, new Uint8Array([255])));

on Chrome-For-Testing https://github.com/GoogleChromeLabs/chrome-for-testing or Chromium Developer Build https://download-chromium.appspot.com/ or Chrome Unstable Build (Canary) to verify for yourself. Just because Firefox hasn't implemented a standard or API doesn't mean multiple other vendors have not.

guest271314 commented 6 months ago

@bsmth PR for sign-verify example https://github.com/mdn/dom-examples/pull/247

bsmth commented 5 months ago

@bsmth PR for sign-verify example mdn/dom-examples#247

Thank you very much, I will take a look shortly

bsmth commented 5 months ago

See also https://github.com/w3c/webcrypto/pull/362

hamishwillee commented 2 hours ago

FYI I'm looking at this as part of #34989 because FF129 implements this. Great you've done the hard work.