-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
crypto: introduce crypto/promises #37218
Conversation
|
||
Calculates the signature for `data` using the given private key and | ||
algorithm. If `algorithm` is `null` or `undefined`, then the algorithm is | ||
dependent upon the key type (especially Ed25519 and Ed448). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest moving the details about the defaults for algorithm
into the bullet point in the argument list above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tniessen is passing null|undefined
used for anything but Ed25519
and Ed448
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't design this API. It would be used for SM2, too. But there's no decision yet whether SM2 will be added, see #37066.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, i thought you did. @mscdex can you pitch in?
Woo! great start. Cursory read through looks good but I'll go through in detail tomorrow. |
Hey, random question - why do we need two promise APIs for crypto (WebCrypto and this). Are the capabilities significantly different? |
const { asymmetricKeyType } = privateKey; | ||
|
||
if (asymmetricKeyType === 'dh') { | ||
return new Promise((resolve, reject) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use util.promisify
to avoid this new Promise
dance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this to be more efficient than the promisify implementation. Not a hill I want to die on tho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's exactly as efficient since in recent version this code is what promisify generates - but not a hill to die on for me either was just trying to comment :]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/nodejs/node/blob/v15.8.0/lib/internal/util.js#L292-L326 sure it has the same outcome, but i think it's handling way more cases which we don't need.
@benjamingr that's a good question. From my POV we have
It boils down to:
|
I... honestly don't use these APIs in crypto enough to judge whether or not this is a good idea given we have WebCrypto. I'll stick to code comments here instead then :] |
I'm using these APIs heavily in my jose module. Given how these security tokens are transmitted you end up using the |
I thought one of the design goals of WebCrypto was to not specify a fixed set of algorithms and allow platforms (like Node.js) to extend it with additional algorithms. Is that not the case? Also - is resolving promises actually expensive in the context of crypto (promises are pretty cheap in modern Node.js and crypto is pretty expensive). |
37eaaa6
to
934d88a
Compare
934d88a
to
87f39d5
Compare
@panva :
This is actually exactly the reason why I made
Eh... the Web Crypto provides an extensibility model then recommends against using it but then the working group for Web Crypto went inactive without defining a clear model for how new algorithms are defined, which is always fun. So long as it's clear that the things we are adding are Node.js specific (e.g. the
Personally I'm fine with doing everything as extensions to Web Crypto. It's not the best API but it's the interoperable/portable one. There are some inefficiencies in the design but now that we have an implementation we can start working on optimizations within that implementation. My emphasis thus far has been on providing the functionality before working on the performance. |
Something like
As far as extensions, at least for the use cases I have in mind, that I think would help bring webcrypto on-par with what i had in mind for this module - |
I feel strongly that if it can be done with WebCrypto we should strive to have 2 and not 3 promise APIs. However, I am quite ignorant on the topic in general - I only know WebCrypto and Node's crypto from a user's point of view, I read very little of the code - so please take everything I say here with a huge grain of salt :D |
I'd prefer for it not to be on
|
NB: This achieves that while still running all the importKey checks. It throws DOMException instead of node's errors though. That being said if all that save's us is one promise, might as well keep the footprint low and not bother. |
While we are at it, I have to say I'm not happy that #35093 added Similar concerns applied to the changes to I added the |
Now, regarding this PR, I wonder how much has changed from @jasnell's #678 (comment). We already have Part of the reason the one-shot For large amounts of data, the existing one-shot APIs can be slow (which is why the streaming APIs should be used instead). However, users will still pass large amounts of data to one-shot functions, to WebCrypto, and they will also pass it to WebCrypto was added to Node.js, which already provides a promise-based API, no matter how inefficient that can be at times. The async callback-based functions in the
If that really is a big problem, then we should probably add required features to the crypto module. If it really does matter much, then I don't think it makes sense to only add new features to If the additional memory requirements and the performance degradation due to copying is not an issue, but blocking the main thread is, applications can already use worker threads to not block the main thread. Adding a third, separate crypto API despite already having |
@tniessen efficient streams but blocking the main thread ✖️ slow one-shot ✖️ WebCrypto w/ limited algorithm support - you're saying if a crypto use doesn't fall into these one should just go manage their own worker resources (and in doing so waste cycles transferring key objects between threads)? Given that the libuv implementation already exists but just isn't exposed i find these choices insufficient. Using stream APIs isn't always applicable, i encounter all of the data needed to be processed to be already present (e.g. in req. headers, payloads, etc) more than streams - plus they block the main thread. Existing one-shots have the same downside as using the stream API in a oneshot kind of way, webcrypto doesn't have the algorithms and curves necessary. So bottom line the best we can do is tell developers to use webcrypto when the algorithm is supported, otherwise go and manage your own worker_threads implementation. 😭 |
@panva no, what I said is
I can see the use cases, but they need to justify the added complexity. |
This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open. |
After discussing with @tniessen (here and privately) and @benjamingr i'm closing this. It makes more sense to extend the existing crypto module with callback methods that are ready to be promisified then to continue down this path. See #37500 for crypto.sign/crypto.verify optional callback inclusion. |
The
crypto.promises
Experimental API provides an alternative set of asynchronous crypto methods that returnPromise
objects and execute their operations in libuv's threadpool. The API is accessible viarequire('crypto').promises
orrequire('crypto/promises')
.It does not bring all current
crypto
features but it's a start.crypto.diffieHellman(...)
crypto.createHash(...).update(...).digest()
crypto.createHmac(...).update(...).digest()
crypto.sign(...)
crypto.verify(...)
All methods are one-shot and use
KeyObject
(orCryptoKey
) instances askey
arguments exclusively.TODO for this PR
dsaEncoding
option for (EC)DSA (one of kSigEncDER, kSigEncP1363)TODO(@jasnell)
intest/parallel/test-crypto-promises-*.js
Refs: #36181
TODO for future PRs