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

[wasm][crypto] RandomNumberGenerator mapped to Web Crypto getRandomValues #42728

Merged
merged 19 commits into from
Oct 1, 2020
Merged

[wasm][crypto] RandomNumberGenerator mapped to Web Crypto getRandomValues #42728

merged 19 commits into from
Oct 1, 2020

Conversation

kjpou1
Copy link
Contributor

@kjpou1 kjpou1 commented Sep 25, 2020

  • Uses Web Crypto API getRandomValues if available.

  • Add javascript bridge implementation library to Native source tree. …

    • Javascript checks for crypto interface and uses crypto.getRandomValues
    • Add api bridge call when building for emscripten browser.
    • If we couldn't find a proper implementation, as Math.random() is not suitable we will abort.

ABORT: no cryptographic support found getRandomValues. Consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };

closes #42727

Part of #40074 and #40074 (comment)

…lues

- Uses Web Crypto API [`getRandomValues`](https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues) if available.
- Falls back to `/dev/urandom` as default if the crypto library is missing.
@ghost
Copy link

ghost commented Sep 25, 2020

Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq, @jeffhandley
See info in area-owners.md if you want to be subscribed.

@steveisok
Copy link
Member

Doesn't /dev/urandom result in a call to Crypto.getRandomValues via the emscripten implementation?

@kjpou1
Copy link
Contributor Author

kjpou1 commented Sep 25, 2020

Looks like it does: https://github.com/paulshapiro/emscripten/blob/master/src/library_fs.js#L1296

We can close this if we want to continue using the default implementation

@kjpou1 kjpou1 requested a review from jkotas September 25, 2020 14:06
@GrabYourPitchforks
Copy link
Member

Falls back to /dev/urandom as default if the crypto library is missing.

Is this even possible? Is there any wasm host which does not provide a subtle crypto implementation? And if there is, why not force the host to polyfill as in #42731?

@steveisok
Copy link
Member

Falls back to /dev/urandom as default if the crypto library is missing.

Is this even possible? Is there any wasm host which does not provide a subtle crypto implementation? And if there is, why not force the host to polyfill as in #42731?

This is just about the best way to call https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues. It's the only API that isn't promised based and we can actually invoke.

To be honest, this already works and unless I'm missing something, I would recommend we close the PR.

@GrabYourPitchforks
Copy link
Member

GrabYourPitchforks commented Sep 26, 2020

Let me rephrase the requirement:

RandomNumberGenerator's built-in implementation must call Crypto.getRandomValues or otherwise use a high-quality source of entropy. It would be better if it made this call directly, but it would also be acceptable to make this call indirectly, assuming there's no low-quality entropy fallback code path. The emscripten implementation doesn't seem to fulfill this latter requirement.

@lewing
Copy link
Member

lewing commented Sep 26, 2020

emscripten-core/emscripten#12240 landed recently which will expose getentropy as a very thin wrapper over subtle crypto which is what the existing wasm /dev/random uses. The code does fall back to requiring crypto.randomBytes on node and fails if that is not supported. I propose we stick with using /dev/random until we update emscripten then call getentropy from pal_random for wasm. Does this satisfy all the requirements?

@lewing
Copy link
Member

lewing commented Sep 26, 2020

Falls back to /dev/urandom as default if the crypto library is missing.

Is this even possible? Is there any wasm host which does not provide a subtle crypto implementation? And if there is, why not force the host to polyfill as in #42731?

This just works because emscripten falls back to node's crypto.randomBytes for both /dev/random and /dev/urandom any code should handle the node case and not fall back to /dev/urandom

Copy link
Member

@lewing lewing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has several issues, it should be implemented in terms of calling getentropy regardless of where the implementation lives.

@marek-safar marek-safar added the arch-wasm WebAssembly architecture label Sep 28, 2020
- Javascript checks for crypto interface and uses `crypto.getRandomValues`
- Add api bridge call when building for emscripten browser.
- separate out into browser subdirectory
- If we couldn't find a proper implementation, as Math.random() is not suitable we will abort.

```

ABORT: no cryptographic support found getRandomValues. Consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };

```
@kjpou1 kjpou1 requested a review from lewing September 29, 2020 07:47
@kjpou1 kjpou1 requested a review from jkotas September 30, 2020 06:49
return 0;
} else {
// we couldn't find a proper implementation, as Math.random() is not suitable
abort("no cryptographic support found for getRandomValues. Consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we should be suggesting an unsecure polyfill in the error message.

I think we should leave it for the documentation to discuss the polyfill workarounds. The recommended workaround should be something that tries to be secure as much as possible, like the MSR library discussed in the other PR. If somebody wants to use insecure polyfill, I would leave it up to them to figure out how to do it.

cc @GrabYourPitchforks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to let normal managed exception to handle error.

WASM-ERR: 
WASM-ERR: Unhandled Exception:
WASM-ERR: System.Security.Cryptography.CryptographicException: Error occurred during a cryptographic operation.
WASM-ERR:    at Interop.GetCryptographicallySecureRandomBytes(Byte* buffer, Int32 length)
WASM-ERR:    at System.Security.Cryptography.RandomNumberGeneratorImplementation.GetBytes(Byte* pbBuffer, Int32 count)
WASM-ERR:    at System.Security.Cryptography.RandomNumberGeneratorImplementation.GetBytes(Span`1 data)
WASM-ERR:    at System.Security.Cryptography.RandomNumberGeneratorImplementation.GetNonZeroBytes(Span`1 data)
WASM-ERR:    at System.Security.Cryptography.RandomNumberGeneratorImplementation.GetNonZeroBytes(Byte[] data)

Does this work?

Copy link
Contributor

@CoffeeFlux CoffeeFlux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo the things Jan mentioned. Thanks!

src/mono/wasm/runtime-test.js Show resolved Hide resolved
src/mono/wasm/runtime-test.js Outdated Show resolved Hide resolved
src/mono/wasm/runtime-test.js Outdated Show resolved Hide resolved
Copy link
Member

@lewing lewing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Address the open reviews and this looks good.

src/mono/wasm/runtime-test.js Show resolved Hide resolved
@marek-safar marek-safar merged commit e573cac into dotnet:master Oct 1, 2020
@kjpou1 kjpou1 deleted the wasm-crypto-getRandomValues branch October 6, 2020 04:02
@ghost ghost locked as resolved and limited conversation to collaborators Dec 7, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly architecture area-System.Security
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[wasm][crypto] RandomNumberGenerator should use Web Crypto API
8 participants