{"slug": "support-for-modern-cryptographic-algorithms-in-workers", "title": "Support for modern cryptographic algorithms in Workers", "summary": "Cloudflare Workers added opt-in Web Crypto support for post-quantum algorithms, including ML-KEM-768 and ML-KEM-1024 for key encapsulation and ML-DSA-44, ML-DSA-65, and ML-DSA-87 for signatures, available behind the `webcrypto_modern_algorithms` compatibility flag. The APIs add `encapsulateBits()`, `decapsulateBits()`, `encapsulateKey()`, `decapsulateKey()`, `getPublicKey()`, `SubtleCrypto.supports()`, and JWK import/export, letting developers experiment with ML-KEM and ML-DSA without bundling a separate cryptographic implementation. Cloudflare said the primitives are building blocks for validating post-quantum integrations rather than a full migration path, while the underlying specification is still moving.", "body_md": "# Support for modern cryptographic algorithms in Workers\n\nToday, Cloudflare Workers is adding support for post-quantum-resistant algorithms within Web Crypto. These are defined in [__Modern Algorithms in the Web Cryptography API__](https://wicg.github.io/webcrypto-modern-algos/) draft [__community group report__](https://www.w3.org/standards/types/#reports), and include:\n\n- ML-KEM-768 and ML-KEM-1024 for key encapsulation\n- ML-DSA-44, ML-DSA-65, and ML-DSA-87 for signatures\n- `encapsulateBits()` ,`decapsulateBits()` ,`encapsulateKey()` , and`decapsulateKey()`\n- `getPublicKey()`\n- `SubtleCrypto.supports()`\n- JWK import and export for these algorithms\n\nFor developers preparing for the post-quantum transition, these opt-in Web Crypto APIs make it easier to experiment with ML-KEM and ML-DSA without bundling a separate cryptographic implementation. They do not provide a full migration path, but rather building blocks that can be used to validate your integration.\n\nThis support is available behind the `webcrypto_modern_algorithms` compatibility flag while the specification is still moving.\n\n## Background\n\n[__Web Crypto__](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) is one of those APIs you only notice when it lacks the primitive you need. If you want to experiment with newer post-quantum algorithms in a JavaScript environment, it’s hard. You either cannot build the protocol directly on top of Web Crypto, or you bring your own cryptography implementation in JavaScript or WebAssembly.\n\nNeither option is ideal. They put the burden of selecting and maintaining cryptographic implementations on implementers, who see their applications get larger as they bundle cryptographic code. And this is work that needs to be reproduced for all downstream libraries. As the ecosystem needs to transition to post-quantum-resistant algorithms [__sooner than expected__](https://blog.cloudflare.com/post-quantum-roadmap/), we [__cannot wait__](https://blog.cloudflare.com/ml-dsa-will-have-to-do/) for better post-quantum algorithms. Developers need access to these primitives now so they can test, evaluate, and improve post-quantum integrations.\n\nIn this post, we’ll explain how you can implement these primitives today, and start to prepare your applications for the post-quantum era.\n\n## The short version\n\nHere is what ML-KEM looks like in Workers. One side has a public key. The other side encapsulates a shared secret to that public key. The holder of the private key decapsulates it and gets the same secret.\n\n``` js\nconst keys = await crypto.subtle.generateKey(\"ML-KEM-768\", true, [\n  \"encapsulateBits\",\n  \"decapsulateBits\",\n]);\n\nconst { sharedKey, ciphertext } = await crypto.subtle.encapsulateBits(\n  \"ML-KEM-768\",\n  keys.publicKey,\n);\n\nconst sameSharedKey = await crypto.subtle.decapsulateBits(\n  \"ML-KEM-768\",\n  keys.privateKey,\n  ciphertext,\n);\n```\n\nThere is no encryption in that snippet yet. ML-KEM gives both sides shared key material. Protocols such as Hybrid Public Key Encryption ([__HPKE__](https://www.rfc-editor.org/rfc/rfc9180.html)) then feed that material into a key schedule and an AEAD such as the AES-GCM algorithm.\n\nML-DSA is closer to what most developers have already seen with Ed25519 or ECDSA: generate a key pair, sign bytes, verify bytes.\n\n``` js\nconst data = new TextEncoder().encode(\"hello post-quantum\");\n\nconst { publicKey, privateKey } = await crypto.subtle.generateKey(\n  \"ML-DSA-44\",\n  false,\n  [\"sign\", \"verify\"],\n);\n\nconst signature = await crypto.subtle.sign(\"ML-DSA-44\", privateKey, data);\nconst valid = await crypto.subtle.verify(\n  \"ML-DSA-44\",\n  publicKey,\n  signature,\n  data,\n);\n```\n\nThese examples are deliberately small. They are not protocols. They are the JavaScript hooks for cryptographic primitives that protocols need.\n\n## Why this matters\n\nPost-quantum migration is not one switch. It is a lot of protocols, libraries, services, and deployment environments learning how to use different primitives.\n\nSome of that work is already visible in TLS and SSH. OpenSSH added [__support for mlkem768x25519__](https://www.openssh.org/pq.html) in 2024. HPKE has a [__draft for post-quantum and hybrid KEMs__](https://datatracker.ietf.org/doc/html/draft-ietf-hpke-pq-05) ongoing at the IETF. The IETF published [__RFC 9964__](https://www.rfc-editor.org/rfc/rfc9964.html) for ML-DSA in JOSE, as well as an [__adopted draft__](https://datatracker.ietf.org/doc/draft-ietf-jose-hpke-pq-pqt/) for JWE using PQ & PQ/T HPKE. HTTP Message Signatures can use [__different signature algorithms__](https://www.iana.org/assignments/http-message-signature/http-message-signature.xhtml), as long as the signer and verifier agree on how to produce and verify the signature.\n\nTo support all these on Cloudflare Workers, developers needed support for the underlying cryptographic primitives within Web Crypto.\n\nWithout it, a Workers developer could still experiment with post-quantum code, but they had to bundle a separate implementation. That is useful for portability and for early experiments, but it is not where we want every production application to end up.\n\n## Signing JWTs with ML-DSA\n\nSigned JSON Web Tokens (JWTs) are a familiar example that protect using JSON Web Signatures (JWS). With a [__panva/jose__](https://github.com/panva/jose) library that maps ML-DSA-* algorithms to Web Crypto, the application code is as follows:\n\n``` js\nimport * as jose from \"jose\";\n\nconst alg = \"ML-DSA-44\";\nconst { publicKey, privateKey } = await jose.generateKeyPair(alg);\n\nconst jwt = await new jose.SignJWT({ sub: \"alice\" })\n  .setProtectedHeader({ alg })\n  .setIssuedAt()\n  .setExpirationTime(\"5m\")\n  .sign(privateKey);\n\nawait jose.jwtVerify(jwt, publicKey);\n```\n\nJWTs are only one example. The larger point is that libraries can delegate ML-DSA operations to the runtime instead of carrying their own implementation for every environment. With Workers supporting ML-DSA natively, libraries can delegate signing to the runtime rather than shipping their own implementation.\n\n## HPKE and OHTTP\n\nML-KEM is a key encapsulation mechanism. On its own, it gives two parties shared key material. HPKE turns that into a complete encryption construction by adding a key schedule and an AEAD.\n\nLibraries such as [__panva/hpke__](https://github.com/panva/hpke) are already structured around Web Crypto and runtime support. With the Workers runtime exposing ML-KEM, HPKE implementations can use the native primitive where available.\n\n``` js\nimport * as HPKE from \"hpke\";\n\nconst plaintext = new TextEncoder().encode(\"Hello World!\");\n\nconst suite = new HPKE.CipherSuite(\n  HPKE.KEM_ML_KEM_768,\n  HPKE.KDF_HKDF_SHA256,\n  HPKE.AEAD_AES_128_GCM,\n);\n\nconst recipient = await suite.GenerateKeyPair();\nconst sealed = await suite.Seal(recipient.publicKey, plaintext);\n\nconst opened = await suite.Open(\n  recipient.privateKey,\n  sealed.encapsulatedSecret,\n  sealed.ciphertext,\n);\n```\n\nThis is the shape we want for protocols such as [__OHTTP__](https://datatracker.ietf.org/doc/html/rfc9458) as well (which we’ve [__discussed before__](https://blog.cloudflare.com/stronger-than-a-promise-proving-oblivious-http-privacy-properties/)). OHTTP uses HPKE. If HPKE can use a post-quantum KEM through Web Crypto, then that peer can start discussing migrating to a ciphersuite that supports these primitives.\n\nLibraries may require runtime-specific integration changes. Here, `HPKE.CipherSuite` selects implementations according to the algorithms available in the runtime.\n\n## Getting a public key from a private key\n\nSeveral protocols need to publish or derive a public key after loading a private key. Previously, this often meant keeping both around or doing format-specific work.\n\nThe new `getPublicKey()` helper does the direct thing:\n\n``` js\nconst publicKey = await crypto.subtle.getPublicKey(privateKey, [\"verify\"]);\n```\n\nFor ML-KEM, the usage is different because public keys encapsulate and private keys decapsulate:\n\n``` js\nconst publicKey = await crypto.subtle.getPublicKey(privateKey, [\n  \"encapsulateBits\",\n]);\n```\n\nThis is a small API that aims to remove code used a lot across libraries that deal with public key cryptography.\n\n## Checking support\n\nBecause the API is not yet supported across runtimes, libraries should check for it instead of assuming it exists everywhere.\n\n``` js\nif (SubtleCrypto.supports(\"sign\", \"ML-DSA-44\")) {\n  const keys = await crypto.subtle.generateKey(\"ML-DSA-44\", false, [\n    \"sign\",\n    \"verify\",\n  ]);\n}\n```\n\nLibraries that run across Workers, [__Node.js__](https://github.com/nodejs/node), [__Deno__](https://github.com/denoland/deno/), browsers, and other Web-interoperable runtimes need this kind of check. It also helps when only part of the modern algorithms proposal is implemented.\n\n## What is supported today\n\nThe initial Workers implementation supports ML-KEM-768 as a KEM and ML-DSA-44 as a signature algorithm. All require the `webcrypto_modern_algorithms` flag to [__be set__](https://developers.cloudflare.com/workers/configuration/compatibility-flags/).\n\n```\n// Include the following in your `wrangler.jsonc`\n{\n\t// Opt into modern crypto algorithms\n\t\"compatibility_flags\": [\n\t\t\"webcrypto_modern_algorithms\"\n\t]\n}\n```\n\nFor completeness, we also support ML-KEM-1024, ML-DSA-65, and ML-DSA-87. ML-KEM-512 is not supported because the BoringSSL version used by Workers does not expose it. Rather than add a separate implementation just for that variant, we are starting with the algorithms available through the native crypto library.\n\nThe most recent list of supported algorithms can always be found on our [__developer documentation__](https://developers.cloudflare.com/workers/runtime-apis/web-crypto/).\n\n## How it’s been implemented\n\nWorkers run on [__workerd__](https://github.com/cloudflare/workerd). It’s an [__open-source runtime__](https://blog.cloudflare.com/workerd-open-source-workers-runtime/) built on V8. The implementation adds ML-KEM and ML-DSA support to workerd's Web Crypto layer, backed by BoringSSL primitives.\n\nThis change also adds [__Web Platform Tests__](https://web-platform-tests.org/) for the modern algorithms API surface, Workers-specific tests for compatibility flag behavior, and TypeScript definitions under the new Workers types.\n\nWe split this out from a [__larger proposal__](https://github.com/cloudflare/workerd/pull/6403) from [__panva__](https://github.com/panva/). The change discussed in this blog, which is the first part of the modern Web Crypto algorithm specification, focuses on ML-KEM, ML-DSA, helper APIs, and JWK support. Other algorithms from the W3C Web Incubator Community Group (WICG) proposal, such as SHA-3, cSHAKE, TurboSHAKE, and ChaCha20-Poly1305, are not part of this initial change.\n\nThat smaller scope makes review easier. It also gives library authors something concrete to test before the whole modern algorithms proposal is implemented.\n\nNote that ML-DSA public keys and signatures are [__substantially larger__](https://blog.cloudflare.com/ml-dsa-will-have-to-do/#the-signature-algorithms) than RSA or Ed25519. The integration of these algorithms in the runtime improves performance and reduces the need for bundling. However, it does not change the reality that the size of keys, signatures, or ciphertext is increasing, on the wire or when stored.\n\n## What may come next\n\nThe [__WICG proposal__](https://wicg.github.io/webcrypto-modern-algos/) covers more than ML-KEM and ML-DSA. We have not implemented the following from the original contribution by Filip Skokan in [__cloudflare/workerd#6403__](https://github.com/cloudflare/workerd/pull/6403), which will need further review. This includes the SHA-3 hash function, ChaCha20-Poly1305 AEAD (discussion about XChaCha20-Poly1305 in [__wicg/webcrypto-modern-algos#1__](https://github.com/WICG/webcrypto-modern-algos/issues/1)), cSHAKE, TurboSHAKE, and HPKE (discussed in [__wicg/webcrypto-modern-algos#2__](https://github.com/WICG/webcrypto-modern-algos/issues/2)). An implementation has already been tested against [__panva/hpke__](https://github.com/panva/hpke) and [__panva/jose__](https://github.com/panva/jose) test suites to verify the implementation.\n\nThere is also a practical question about when this should become default, rather than opt-in. For now, all these algorithms are gated behind a compatibility flag. The API is based on a draft, and we want feedback from library authors before treating it as stable.\n\n## Start experimenting today\n\nThis change does not make every protocol post-quantum by itself. It gives Workers developers and library authors the primitives they were missing: ML-KEM for key encapsulation, ML-DSA for signatures, and helper APIs that make those primitives usable through Web Crypto.\n\nIf you maintain a library that currently bundles its own post-quantum implementation, this is a good time to try the native API and tell us what does not fit. The fastest way to find the rough edges is to put real protocol code on top of it. All the details are in [__our changelog__](https://developers.cloudflare.com/changelog/).\n\nWe would like to thank Filip Skokan for the original contribution and iterations, Felix Hanau, James Snell, Bas Westerbaan, and Peter Wu for reviewing the code, and Daniel Huigens for co-authoring the specification work this implementation follows.", "url": "https://wpnews.pro/news/support-for-modern-cryptographic-algorithms-in-workers", "canonical_source": "https://blog.cloudflare.com/workers-ml-kem-ml-dsa-support/", "published_at": "2026-10-01 13:00:00+00:00", "updated_at": "2026-10-01 13:17:45.077651+00:00", "lang": "en", "topics": ["ai-infrastructure", "developer-tools"], "entities": ["Cloudflare", "Cloudflare Workers", "Web Crypto", "ML-KEM-768", "ML-KEM-1024", "ML-DSA-44", "ML-DSA-65", "ML-DSA-87"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/support-for-modern-cryptographic-algorithms-in-workers", "markdown": "https://wpnews.pro/news/support-for-modern-cryptographic-algorithms-in-workers.md", "text": "https://wpnews.pro/news/support-for-modern-cryptographic-algorithms-in-workers.txt", "jsonld": "https://wpnews.pro/news/support-for-modern-cryptographic-algorithms-in-workers.jsonld"}}