Skip to content

Commit e573cac

Browse files
kjpou1CoffeeFlux
andauthored
[wasm][crypto] RandomNumberGenerator mapped to Web Crypto getRandomValues (#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 <[email protected]> * 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 <[email protected]>
1 parent 0798485 commit e573cac

File tree

5 files changed

+52
-12
lines changed

5 files changed

+52
-12
lines changed

src/libraries/Native/Unix/System.Native/pal_random.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,24 @@ Return 0 on success, -1 on failure.
6363
*/
6464
int32_t SystemNative_GetCryptographicallySecureRandomBytes(uint8_t* buffer, int32_t bufferLength)
6565
{
66+
assert(buffer != NULL);
67+
68+
#ifdef __EMSCRIPTEN__
69+
extern int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength);
70+
static bool sMissingBrowserCrypto;
71+
if (!sMissingBrowserCrypto)
72+
{
73+
int32_t bff = dotnet_browser_entropy(buffer, bufferLength);
74+
if (bff == -1)
75+
sMissingBrowserCrypto = true;
76+
else
77+
return 0;
78+
}
79+
#else
80+
6681
static volatile int rand_des = -1;
6782
static bool sMissingDevURandom;
6883

69-
assert(buffer != NULL);
70-
7184
if (!sMissingDevURandom)
7285
{
7386
if (rand_des == -1)
@@ -121,6 +134,6 @@ int32_t SystemNative_GetCryptographicallySecureRandomBytes(uint8_t* buffer, int3
121134
return 0;
122135
}
123136
}
124-
137+
#endif
125138
return -1;
126139
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
var DotNetEntropyLib = {
5+
$DOTNETENTROPY: {
6+
},
7+
dotnet_browser_entropy : function (buffer, bufferLength) {
8+
// check that we have crypto available
9+
if (typeof crypto === 'object' && typeof crypto['getRandomValues'] === 'function') {
10+
// for modern web browsers
11+
// map the work array to the memory buffer passed with the length
12+
var wrkArray = new Uint8Array(Module.HEAPU8.buffer, buffer, bufferLength);
13+
crypto.getRandomValues(wrkArray);
14+
return 0;
15+
} else {
16+
// we couldn't find a proper implementation, as Math.random() is not suitable
17+
// instead of aborting here we will return and let managed code handle the message
18+
return -1;
19+
}
20+
},
21+
};
22+
23+
autoAddDeps(DotNetEntropyLib, '$DOTNETENTROPY')
24+
mergeInto(LibraryManager.library, DotNetEntropyLib)

src/mono/wasm/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ PINVOKE_TABLE?=$(TOP)/artifacts/obj/wasm/pinvoke-table.h
1515
MONO_BIN_DIR?=$(BINDIR)/mono/Browser.wasm.$(CONFIG)
1616
NATIVE_BIN_DIR?=$(BINDIR)/native/net5.0-Browser-$(CONFIG)-wasm
1717
ICU_LIBDIR?=
18+
SYSTEM_NATIVE_LIBDIR?=$(TOP)/src/libraries/Native/Unix/System.Native
1819
ENABLE_ES6?=false
1920

2021
all: build-native icu-data
@@ -81,8 +82,8 @@ $(NATIVE_BIN_DIR):
8182
$(BUILDS_OBJ_DIR):
8283
mkdir -p $$@
8384

84-
$(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)
85-
$(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
85+
$(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)
86+
$(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
8687

8788
$(BUILDS_OBJ_DIR)/pinvoke-table.h: $(PINVOKE_TABLE) | $(BUILDS_OBJ_DIR)
8889
if cmp -s $(PINVOKE_TABLE) $$@ ; then : ; else cp $(PINVOKE_TABLE) $$@ ; fi

src/mono/wasm/runtime-test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,14 @@ if (typeof console !== "undefined") {
6262
console.error = console.log;
6363
}
6464

65-
if (typeof crypto == 'undefined') {
65+
if (typeof crypto === 'undefined') {
66+
// **NOTE** this is a simple insecure polyfill for testing purposes only
6667
// /dev/random doesn't work on js shells, so define our own
6768
// See library_fs.js:createDefaultDevices ()
6869
var crypto = {
6970
getRandomValues: function (buffer) {
70-
buffer[0] = (Math.random()*256)|0;
71+
for (var i = 0; i < buffer.length; i++)
72+
buffer [i] = (Math.random () * 256) | 0;
7173
}
7274
}
7375
}

src/mono/wasm/runtime/library_mono.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ var MonoSupportLib = {
211211
},
212212
/** @returns {ManagedPointer} */
213213
get: function (index) {
214-
this._check_in_range (index);
214+
this._check_in_range (index);
215215
return Module.HEAP32[this.get_address_32 (index)];
216216
},
217217
set: function (index, value) {
@@ -317,7 +317,7 @@ var MonoSupportLib = {
317317
throw new Error ("capacity >= 1");
318318

319319
capacity = capacity | 0;
320-
320+
321321
var capacityBytes = capacity * 4;
322322
var offset = Module._malloc (capacityBytes);
323323
if ((offset % 4) !== 0)
@@ -328,7 +328,7 @@ var MonoSupportLib = {
328328
var result = Object.create (this._mono_wasm_root_buffer_prototype);
329329
result.__offset = offset;
330330
result.__offset32 = (offset / 4) | 0;
331-
result.__count = capacity;
331+
result.__count = capacity;
332332
result.length = capacity;
333333
result.__handle = this.mono_wasm_register_root (offset, capacityBytes, msg || 0);
334334

@@ -347,7 +347,7 @@ var MonoSupportLib = {
347347
mono_wasm_new_root: function (value) {
348348
var index = this._mono_wasm_claim_scratch_index ();
349349
var buffer = this._scratch_root_buffer;
350-
350+
351351
var result = Object.create (this._mono_wasm_root_prototype);
352352
result.__buffer = buffer;
353353
result.__index = index;
@@ -395,7 +395,7 @@ var MonoSupportLib = {
395395
* Multiple objects may be passed on the argument list.
396396
* 'undefined' may be passed as an argument so it is safe to call this method from finally blocks
397397
* even if you are not sure all of your roots have been created yet.
398-
* @param {... WasmRoot} roots
398+
* @param {... WasmRoot} roots
399399
*/
400400
mono_wasm_release_roots: function () {
401401
for (var i = 0; i < arguments.length; i++) {

0 commit comments

Comments
 (0)