denoland / deno

A modern runtime for JavaScript and TypeScript.

Home Page:https://deno.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Implement webcrypto APIs.

afinch7 opened this issue · comments

Some applications like handling password will require hashing and encryption. These operations could be implemented in js/ts, but It really needs to be handled from a trusted environment to be secure. It looks like there have been some attempts to get this one rolling before recently with #1461.

Classical method: new Rust ops, TS frontend for them and testing. Will take a look at, maybe work on.

Maybe this repo will be useful for examples https://github.com/diafygi/webcrypto-examples of the usage.

Chromium's implementation of WebCrypto source code https://chromium.googlesource.com/chromium/src/+/master/components/webcrypto/

Are you planning to implement all algorithms in Rust or use already provided community packages? I would suggest to link existing source code written in C++ from chromium since it may not be a good idea to use some Rust package which is not well maintained and wasn't reviewed by security experts.

We could use Chromium code, but it can be difficult to integrate

Related: denoland/deno_std Add crypto module #48

IMHO, implementing the webcrypto API is not the most pressing thing to do regarding deno & crypto.

What I don't like about webcrypto:

  • unnecessary and confusing API surface (Crypto, SubtleCrypto, etc.)
  • supports various obsolete algorithms, hardly state-of-the-art
  • the primary SubtleCrypto interface is a pretty low-level API, inviting users to mix-n-match

🦕 ❤️🔐 = I would love to see deno expose a high-level, hard-to-misuse, modern crypto API like libsodium. No need for obsolete stuff, e.g. SHA1, PBKDF2, RSASSA-PKCS1-v1_5. That can be done in userland if needed. deno should exclusively focus on providing high-security, state-of-the-art crypto with a simple API. Of course, browser compat...

Do we need sth like a nursery repo (denoland/deno_nursery/crypto)?

Something usable should be in deno_std on top of the web compatible stuff.

Also, we already have precedence for not supporting obsolete things, like TextDecorder() which only supports utf8.

Nurseries are hard to manage, people end up using them, not respecting that they aren't "production ready" and then it becomes a defacto things. Iterating on something in deno_std built on top of the web standard APIs is really the best idea. The parts of the web standard really should be implemented directly in Rust too for both security and performance.

I think Crypto should be a higher priority.
Every server-side application that handles authentication will need to be able to verify/sign data.
All major cloud providers give authorization in the form of private keys/JWTs.

I ported Firebase firestore and storage libraries but didn't publish them because without being able to sign and verify with RSASSA-PKCS1-V1_5 there is nothing they can really do(unless used as a regular client).

Also worth considering is the crypto package from Go's standard library: https://golang.org/pkg/crypto/

I think the ideal approach would be a blend of that package and the subtle interface that is expected in the browser context.

I have a very early effort to implement the SubtleCrypto interface in a deno crypto playground. Curious if there are any others interested in collaborating.

Generally speaking, I think the project could benefit from "working groups," whether it's something formal or just additional channels in the Discord.

commented

Related: denoland/deno_std Add crypto module #48

IMHO, implementing the webcrypto API is not the most pressing thing to do regarding deno & crypto.

What I don't like about webcrypto:

  • unnecessary and confusing API surface (Crypto, SubtleCrypto, etc.)
  • supports various obsolete algorithms, hardly state-of-the-art
  • the primary SubtleCrypto interface is a pretty low-level API, inviting users to mix-n-match

🦕 ❤️🔐 = I would love to see deno expose a high-level, hard-to-misuse, modern crypto API like libsodium. No need for obsolete stuff, e.g. SHA1, PBKDF2, RSASSA-PKCS1-v1_5. That can be done in userland if needed. deno should exclusively focus on providing high-security, state-of-the-art crypto with a simple API. Of course, browser compat...

Do we need sth like a nursery repo (denoland/deno_nursery/crypto)?

If you follow "Web Crypto API" it works every where without any dependencies. Eg. Browser, Edge Computing Networks (like Cloudflare workers, AWS Lambda, Google cloud functions). Currently testing this edge code is not easy. With Deno one can test this code locally without much effort.

"Web Crypto API" feature is a must have. After all, they have already implemented everything else. Why to leave this alone?

One of Deno's primary appeals is symmetry with the web and Cloudflare workers. I agree with much of @chiefbiiko's comment, however I ask that the developer cost of diverging the API surface from the web be considered in this decision.

What is the current state of crypto on deno?

I am interested in this project due to its emphasis on a std library, and it seems like crypto would be a core part of that effort.

Currently in deno there is no way to generate a jwks or similar crypto artifacts, meaning that I have to rely on the host system and pass around key files.

Is there something I am missing or is that the current best practice?

I don't think there is much of a debate... As the title of the issues says... Implement the web crypto APIs. There would be no issue with implementing Web Crypto APIs beyond the .getRandomValues() which is already implemented.

@kitsonk @sejr thanks for the reply, sorry if my comment came across as demanding.

Please correct me if I am expanding the scope of the stdlib beyond deno's intentions, but in order to avoid the dependency bloat seen in npm I think that more is required than just the base web crypto apis.

For example in order to implement a jwks or any feature relying on JOSE deno would need node crypto to be ported along with jose support for the following specs.

JSON Web Signature (JWS) - RFC7515
JSON Web Encryption (JWE) - RFC7516
JSON Web Key (JWK) - RFC7517
JSON Web Algorithms (JWA) - RFC7518
JSON Web Token (JWT) - RFC7519
JSON Web Key Thumbprint - RFC7638
JWS Unencoded Payload Option - RFC7797
CFRG Elliptic Curve ECDH and Signatures - RFC8037
secp256k1 EC Key curve support - JOSE Registrations for WebAuthn Algorithms

Packages like npm jose have basically become a part of the nodejs core due to their almost ubiquitous usage and strict adherence to IETF specs.

Perhaps this will start out as a community package, however its seems likely that this would just result in multiple implementations with varying levels of correctness, which is a recipe for disaster when it comes to crypto.

I would like to contribute to this effort, as I see strong crypto support being the major blocker for deno that prevents me from considering it for serious applications.

@austinrivas I didn't take it that way. My comment was more directed at @sejr. Implementing the Web Crypto APIs in Deno is something that should be done and wouldn't be controversial. They don't really offer good higher order solutions though. Outside of basic primitives though, they should likely be a community project.

That being said, JWT, JWS, JWK, etc. are "standard" enough (and important enough to have provably correct implementations), that they might be good targets for std inclusion built upon the low level Web Crypto APIs.

Apologies, my reply was poorly worded. I definitely agree (as do most I’ve discussed with) about the priority for WebCrypto.

From those discussions, here and on Discord, it seemed like there was not yet a decision when it comes to building the backend for these APIs in pure Rust vs. linking to existing code in V8. Would love to hear your thoughts on that @kitsonk.

I think the JWT/S/K implementations would be a good start too. Worth noting existing work in this package: https://deno.land/x/djwt/README.md

Has this been lost in discussion? Seems kinda important for security, and will be a gamechanger for people who want to use deno(and implement oauth & alikes); or am i missing the point of crypto libaries?

Edit: I am not trying to be pushy, especially as a non-contributor. I just wanted to push this up if possible.

I think the JWT/S/K implementations would be a good start too.

With the advent of WebCrypto API in Node.js my jose module will become an ESM module utiling it. It covers all of JW[STEAK] and would immediately work in Deno too if it got support for WebCrypto.

Any updates?.. I just would to hash passwords without 3rd party modules, is it too much to ask for?.. (Sorry for irony)

Please consider including the Curve25519 algorithms in the implementation.

https://www.chromestatus.com/feature/4913922408710144

@kitsonk Which crypto library should we rely on? I probed a bit and, from my limited knowledge, the only library with an up-to-date Rust crate that covers the whole scope of the Web Crypto API would be OpenSSL. However, including OpenSSL in Deno seems to significantly the build complexity.

I can scaffold the code to expose the Web Crypto API but I'd need direction on which underlying implementation we should rely on.

We can likely use ring for most crypto operations. It is already in our dependency tree through rustls. See https://briansmith.org/rustdoc/ring/

Unfortunately ring does not support RSA key generation, but it's part of the Web Crypto API.
See briansmith/ring#219 and briansmith/ring#733.

If WebCrypto is supported, I will immediately move my projects to Deno.

If WebCrypto is supported, I will immediately move my projects to Deno.

Agreed, this is the one must have feature that I am waiting for in order to start using deno seriously.

I mean, there are wasm-powered libsodium bindings

Simplified your example using async await:

const encoder = new TextEncoder();
const data = encoder.encode("January February");

const algorithm = { name: "AES-CBC", iv: encoder.encode("0123456789ABCDEF") };
const key = await crypto.subtle.importKey("raw", encoder.encoder("GHIJKLMNOPQRSTUV"), "AES-CBC", true, ["encrypt"]);
const encryptedData = await crypto.subtle.encrypt(algorithm, key, data);
console.log(encryptedData);

I would argue that the SubtleCrypto API is a lot more customizable than for example PHP. You can adjust a whole bunch of parameters. For example you can encrypt raw bytes, not just strings, and you have a far wider range of keys types and encryption algorithms to choose from.

Feel free to open an issue with the spec: https://github.com/w3c/webcrypto :-)

Common usecases/boilerplate can be a library (or potentially even in std) on top of SubtleCrypto.

@89z One obvious difference is that node crypto is not async. This issue is about webcrypto implementation in Deno, not about comparing all the different crypto implementations. If you want to chat about this further please hop on Discord: https://discord.gg/deno.

The decision to implement SubtleCrypto in Deno has been made. It will happen.

Some options:

  • https://deno.land/std@0.91.0/node/crypto.ts - doesn't have createCipherIv, has good code reviewing
  • https://deno.land/x/crypto - 4 stars. might be on the right path but needs more engagement. author doesn't have a lot of followers yet. author seems active and open to contributions. I'm starring and following.
  • https://deno.land/x/sodium - 14 stars. part of the denosaurs project, which is unofficial but has a lot of stars on some projects. would prefer more reviewing of the code and the publish process but the underlying library is well-reviewed.
commented

I hope to be as consistent as possible with the browser.

MDN: https://developer.mozilla.org/en-US/docs/Web/API/Crypto

Another (temporary) solution:

import { crypto } from 'https://cdn.skypack.dev/@stagas/webcrypto-liner'

is a fork of webcrypto-liner which implements WebCrypto in TS/JS -- not all APIs work but some do - mainly I used crypto.subtle.importKey and crypto.subtle.sign with success so I'm posting it here in case it's useful to someone.

The fork simply fixes a couple of compatibility issues when using deno deploy. Theoretically the library can be ported to deno entirely but it's too many components involved so it takes some time investment to do it.

@panva would you be interested in creating a draft with me for std that includes jws and jwt for a start now that webcrypto is partially supported? (discord timreichen#1717)

@panva would you be interested in creating a draft with me for std that includes jws and jwt for a start now that webcrypto is partially supported? (discord timreichen#1717)

Sure, you can reach out to me on the OpenJS Foundation slack.

Many Web Crypto APIs are already supported in Deno. Let's continue in #11690