Skip to content

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

Merged
marek-safar merged 19 commits into
dotnet:masterfrom
kjpou1:wasm-crypto-getRandomValues
Oct 1, 2020
Merged

[wasm][crypto] RandomNumberGenerator mapped to Web Crypto getRandomValues#42728
marek-safar merged 19 commits into
dotnet:masterfrom
kjpou1:wasm-crypto-getRandomValues

Conversation

@kjpou1

@kjpou1 kjpou1 commented Sep 25, 2020

Copy link
Copy Markdown
Contributor
  • 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

ghost commented Sep 25, 2020

Copy link
Copy Markdown

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

@steveisok

Copy link
Copy Markdown
Member

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

@kjpou1

kjpou1 commented Sep 25, 2020

Copy link
Copy Markdown
Contributor Author

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

Comment thread src/libraries/Native/Unix/System.Native/pal_random.c Outdated
@kjpou1
kjpou1 requested a review from jkotas September 25, 2020 14:06
@GrabYourPitchforks

Copy link
Copy Markdown
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
Copy Markdown
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

GrabYourPitchforks commented Sep 26, 2020

Copy link
Copy Markdown
Member

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.

Comment thread src/libraries/Native/Unix/System.Native/pal_random.c Outdated
@lewing

lewing commented Sep 26, 2020

Copy link
Copy Markdown
Member

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

lewing commented Sep 26, 2020

Copy link
Copy Markdown
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 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

@lewing lewing left a comment

Copy link
Copy Markdown
Member

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
Comment thread src/libraries/Native/Unix/System.Native/browser/pal_random_browser.h Outdated
Comment thread src/libraries/Native/Unix/System.Native/browser/pal_random_browser.h Outdated
@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
Copy Markdown
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
Copy Markdown
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?

Comment thread src/mono/wasm/runtime-test.js

@CoffeeFlux CoffeeFlux left a comment

Copy link
Copy Markdown
Contributor

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!

Comment thread src/mono/wasm/runtime-test.js
Comment thread src/mono/wasm/runtime-test.js Outdated
Comment thread src/mono/wasm/runtime-test.js Outdated
Comment thread src/libraries/Native/Unix/System.Native/pal_random.c
Comment thread src/libraries/Native/Unix/System.Native/pal_random.c

@lewing lewing left a comment

Copy link
Copy Markdown
Member

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.

Comment thread src/mono/wasm/runtime-test.js
@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