Skip to content

Commit

Permalink
[wasm][crypto] RandomNumberGenerator mapped to Web Crypto getRandomVa…
Browse files Browse the repository at this point in the history
…lues (#42728)

* [wasm][crypto] RandomNumberGenerator mapped to Web Crypto getRandomValues

- 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.

* Remove the emscripten interface code from the driver.c.

* remove extraneous code comment

* Move emscripten definition around.

* Address review comment

* 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.
- 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 } };

```

* Change tests to set random values of the buffer instead of return a single value.

* Remove old test code

* Remove testing code

* Incorporate the PAL bridge layer into the `--js-library` build process

* Address review comments about directory structure and naming

* Update src/mono/wasm/runtime-test.js

Co-authored-by: Ryan Lucia <ryan@luciaonline.net>

* Add note about insecure code for testing purposes

* Formatting

* Return -1 if crypto does not exist instead of aborting from js.  This allows the managed code exception flow to continue as normal.

Co-authored-by: Ryan Lucia <ryan@luciaonline.net>
  • Loading branch information
kjpou1 and CoffeeFlux authored Oct 1, 2020
1 parent 0798485 commit e573cac
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 12 deletions.
19 changes: 16 additions & 3 deletions src/libraries/Native/Unix/System.Native/pal_random.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,24 @@ Return 0 on success, -1 on failure.
*/
int32_t SystemNative_GetCryptographicallySecureRandomBytes(uint8_t* buffer, int32_t bufferLength)
{
assert(buffer != NULL);

#ifdef __EMSCRIPTEN__
extern int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength);
static bool sMissingBrowserCrypto;
if (!sMissingBrowserCrypto)
{
int32_t bff = dotnet_browser_entropy(buffer, bufferLength);
if (bff == -1)
sMissingBrowserCrypto = true;
else
return 0;
}
#else

static volatile int rand_des = -1;
static bool sMissingDevURandom;

assert(buffer != NULL);

if (!sMissingDevURandom)
{
if (rand_des == -1)
Expand Down Expand Up @@ -121,6 +134,6 @@ int32_t SystemNative_GetCryptographicallySecureRandomBytes(uint8_t* buffer, int3
return 0;
}
}

#endif
return -1;
}
24 changes: 24 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_random.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

var DotNetEntropyLib = {
$DOTNETENTROPY: {
},
dotnet_browser_entropy : function (buffer, bufferLength) {
// check that we have crypto available
if (typeof crypto === 'object' && typeof crypto['getRandomValues'] === 'function') {
// for modern web browsers
// map the work array to the memory buffer passed with the length
var wrkArray = new Uint8Array(Module.HEAPU8.buffer, buffer, bufferLength);
crypto.getRandomValues(wrkArray);
return 0;
} else {
// we couldn't find a proper implementation, as Math.random() is not suitable
// instead of aborting here we will return and let managed code handle the message
return -1;
}
},
};

autoAddDeps(DotNetEntropyLib, '$DOTNETENTROPY')
mergeInto(LibraryManager.library, DotNetEntropyLib)
5 changes: 3 additions & 2 deletions src/mono/wasm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ PINVOKE_TABLE?=$(TOP)/artifacts/obj/wasm/pinvoke-table.h
MONO_BIN_DIR?=$(BINDIR)/mono/Browser.wasm.$(CONFIG)
NATIVE_BIN_DIR?=$(BINDIR)/native/net5.0-Browser-$(CONFIG)-wasm
ICU_LIBDIR?=
SYSTEM_NATIVE_LIBDIR?=$(TOP)/src/libraries/Native/Unix/System.Native
ENABLE_ES6?=false

all: build-native icu-data
Expand Down Expand Up @@ -81,8 +82,8 @@ $(NATIVE_BIN_DIR):
$(BUILDS_OBJ_DIR):
mkdir -p $$@

$(NATIVE_BIN_DIR)/dotnet.js: $(BUILDS_OBJ_DIR)/driver.o $(BUILDS_OBJ_DIR)/pinvoke.o $(BUILDS_OBJ_DIR)/corebindings.o runtime/library_mono.js runtime/binding_support.js runtime/dotnet_support.js $(2) | $(NATIVE_BIN_DIR)
$(EMCC) $(EMCC_FLAGS) $(1) --js-library runtime/library_mono.js --js-library runtime/binding_support.js --js-library runtime/dotnet_support.js $(BUILDS_OBJ_DIR)/driver.o $(BUILDS_OBJ_DIR)/pinvoke.o $(BUILDS_OBJ_DIR)/corebindings.o $(2) -o $(NATIVE_BIN_DIR)/dotnet.js
$(NATIVE_BIN_DIR)/dotnet.js: $(BUILDS_OBJ_DIR)/driver.o $(BUILDS_OBJ_DIR)/pinvoke.o $(BUILDS_OBJ_DIR)/corebindings.o runtime/library_mono.js runtime/binding_support.js runtime/dotnet_support.js $(SYSTEM_NATIVE_LIBDIR)/pal_random.js $(2) | $(NATIVE_BIN_DIR)
$(EMCC) $(EMCC_FLAGS) $(1) --js-library runtime/library_mono.js --js-library runtime/binding_support.js --js-library runtime/dotnet_support.js --js-library $(SYSTEM_NATIVE_LIBDIR)/pal_random.js $(BUILDS_OBJ_DIR)/driver.o $(BUILDS_OBJ_DIR)/pinvoke.o $(BUILDS_OBJ_DIR)/corebindings.o $(2) -o $(NATIVE_BIN_DIR)/dotnet.js

$(BUILDS_OBJ_DIR)/pinvoke-table.h: $(PINVOKE_TABLE) | $(BUILDS_OBJ_DIR)
if cmp -s $(PINVOKE_TABLE) $$@ ; then : ; else cp $(PINVOKE_TABLE) $$@ ; fi
Expand Down
6 changes: 4 additions & 2 deletions src/mono/wasm/runtime-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ if (typeof console !== "undefined") {
console.error = console.log;
}

if (typeof crypto == 'undefined') {
if (typeof crypto === 'undefined') {
// **NOTE** this is a simple insecure polyfill for testing purposes only
// /dev/random doesn't work on js shells, so define our own
// See library_fs.js:createDefaultDevices ()
var crypto = {
getRandomValues: function (buffer) {
buffer[0] = (Math.random()*256)|0;
for (var i = 0; i < buffer.length; i++)
buffer [i] = (Math.random () * 256) | 0;
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/mono/wasm/runtime/library_mono.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ var MonoSupportLib = {
},
/** @returns {ManagedPointer} */
get: function (index) {
this._check_in_range (index);
this._check_in_range (index);
return Module.HEAP32[this.get_address_32 (index)];
},
set: function (index, value) {
Expand Down Expand Up @@ -317,7 +317,7 @@ var MonoSupportLib = {
throw new Error ("capacity >= 1");

capacity = capacity | 0;

var capacityBytes = capacity * 4;
var offset = Module._malloc (capacityBytes);
if ((offset % 4) !== 0)
Expand All @@ -328,7 +328,7 @@ var MonoSupportLib = {
var result = Object.create (this._mono_wasm_root_buffer_prototype);
result.__offset = offset;
result.__offset32 = (offset / 4) | 0;
result.__count = capacity;
result.__count = capacity;
result.length = capacity;
result.__handle = this.mono_wasm_register_root (offset, capacityBytes, msg || 0);

Expand All @@ -347,7 +347,7 @@ var MonoSupportLib = {
mono_wasm_new_root: function (value) {
var index = this._mono_wasm_claim_scratch_index ();
var buffer = this._scratch_root_buffer;

var result = Object.create (this._mono_wasm_root_prototype);
result.__buffer = buffer;
result.__index = index;
Expand Down Expand Up @@ -395,7 +395,7 @@ var MonoSupportLib = {
* Multiple objects may be passed on the argument list.
* 'undefined' may be passed as an argument so it is safe to call this method from finally blocks
* even if you are not sure all of your roots have been created yet.
* @param {... WasmRoot} roots
* @param {... WasmRoot} roots
*/
mono_wasm_release_roots: function () {
for (var i = 0; i < arguments.length; i++) {
Expand Down

0 comments on commit e573cac

Please sign in to comment.