diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
index ff1076521589f..aea7e2e5d2af6 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
@@ -217,7 +217,6 @@
-
diff --git a/src/mono/sample/wasm/browser-advanced/Program.cs b/src/mono/sample/wasm/browser-advanced/Program.cs
index bec9cb3256b4c..53cbdbb2e3e0a 100644
--- a/src/mono/sample/wasm/browser-advanced/Program.cs
+++ b/src/mono/sample/wasm/browser-advanced/Program.cs
@@ -14,6 +14,9 @@ public static int Main(string[] args)
{
Console.WriteLine ("Hello, World!");
+ var rand = new Random();
+ Console.WriteLine ("Today's lucky number is " + rand.Next(100) + " and " + Guid.NewGuid());
+
var start = DateTime.UtcNow;
var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count;
var end = DateTime.UtcNow;
diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt
index 6d939088d7431..e0b19bb4a9b69 100644
--- a/src/mono/wasm/runtime/CMakeLists.txt
+++ b/src/mono/wasm/runtime/CMakeLists.txt
@@ -34,8 +34,8 @@ target_link_libraries(dotnet.native
${NATIVE_BIN_DIR}/libSystem.IO.Compression.Native.a)
set_target_properties(dotnet.native PROPERTIES
- LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js;"
- LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-link.rsp ${CONFIGURATION_LINK_FLAGS} --pre-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js --js-library ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --extern-post-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js "
+ LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js;"
+ LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-link.rsp ${CONFIGURATION_LINK_FLAGS} --pre-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js --js-library ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js --extern-post-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js "
RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}")
set(ignoreMeWasmOptFlags "${CONFIGURATION_WASM_OPT_FLAGS}")
diff --git a/src/mono/wasm/runtime/crypto.ts b/src/mono/wasm/runtime/crypto.ts
new file mode 100644
index 0000000000000..f396b5d833b14
--- /dev/null
+++ b/src/mono/wasm/runtime/crypto.ts
@@ -0,0 +1,33 @@
+import { isSharedArrayBuffer, localHeapViewU8 } from "./memory";
+
+// batchedQuotaMax is the max number of bytes as specified by the api spec.
+// If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
+// https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
+const batchedQuotaMax = 65536;
+
+export function mono_wasm_browser_entropy(bufferPtr: number, bufferLength: number): number {
+ if (!globalThis.crypto || !globalThis.crypto.getRandomValues) {
+ return -1;
+ }
+
+ const memoryView = localHeapViewU8();
+ const targetView = memoryView.subarray(bufferPtr, bufferPtr + bufferLength);
+
+ // When threading is enabled, Chrome doesn't want SharedArrayBuffer to be passed to crypto APIs
+ const needsCopy = isSharedArrayBuffer(memoryView.buffer);
+ const targetBuffer = needsCopy
+ ? new Uint8Array(bufferLength)
+ : targetView;
+
+ // fill the targetBuffer in batches of batchedQuotaMax
+ for (let i = 0; i < bufferLength; i += batchedQuotaMax) {
+ const targetBatch = targetBuffer.subarray(i, i + Math.min(bufferLength - i, batchedQuotaMax));
+ globalThis.crypto.getRandomValues(targetBatch);
+ }
+
+ if (needsCopy) {
+ targetView.set(targetBuffer);
+ }
+
+ return 0;
+}
diff --git a/src/mono/wasm/runtime/exports-binding.ts b/src/mono/wasm/runtime/exports-binding.ts
index 8e856c35fa4c5..d7ef9ad945d14 100644
--- a/src/mono/wasm/runtime/exports-binding.ts
+++ b/src/mono/wasm/runtime/exports-binding.ts
@@ -35,6 +35,7 @@ import { mono_wasm_typed_array_to_array_ref } from "./net6-legacy/js-to-cs";
import { mono_wasm_typed_array_from_ref } from "./net6-legacy/buffers";
import { mono_wasm_get_culture_info } from "./hybrid-globalization/culture-info";
import { mono_wasm_get_first_day_of_week, mono_wasm_get_first_week_of_year } from "./hybrid-globalization/locales";
+import { mono_wasm_browser_entropy } from "./crypto";
// the JS methods would be visible to EMCC linker and become imports of the WASM module
@@ -98,6 +99,9 @@ export const mono_wasm_imports = [
mono_wasm_set_entrypoint_breakpoint,
mono_wasm_event_pipe_early_startup_callback,
+ // src/native/minipal/random.c
+ mono_wasm_browser_entropy,
+
// corebindings.c
mono_wasm_release_cs_owned_object,
mono_wasm_bind_js_function,
diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts
index 6de09caa18e9d..4a864cf347f63 100644
--- a/src/mono/wasm/runtime/memory.ts
+++ b/src/mono/wasm/runtime/memory.ts
@@ -401,7 +401,10 @@ export function receiveWorkerHeapViews() {
const sharedArrayBufferDefined = typeof SharedArrayBuffer !== "undefined";
export function isSharedArrayBuffer(buffer: any): buffer is SharedArrayBuffer {
- if (!MonoWasmThreads) return false;
// this condition should be eliminated by rollup on non-threading builds
+ if (!MonoWasmThreads) return false;
+ // BEWARE: In some cases, `instanceof SharedArrayBuffer` returns false even though buffer is an SAB.
+ // Patch adapted from https://github.com/emscripten-core/emscripten/pull/16994
+ // See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
return sharedArrayBufferDefined && buffer[Symbol.toStringTag] === "SharedArrayBuffer";
}
diff --git a/src/mono/wasm/runtime/strings.ts b/src/mono/wasm/runtime/strings.ts
index f4cfa44238618..a03d478973a53 100644
--- a/src/mono/wasm/runtime/strings.ts
+++ b/src/mono/wasm/runtime/strings.ts
@@ -242,9 +242,6 @@ function stringToMonoStringNewRoot(string: string, result: WasmRoot)
// When threading is enabled, TextDecoder does not accept a view of a
// SharedArrayBuffer, we must make a copy of the array first.
// See https://github.com/whatwg/encoding/issues/172
-// BEWARE: In some cases, `instanceof SharedArrayBuffer` returns false even though buffer is an SAB.
-// Patch adapted from https://github.com/emscripten-core/emscripten/pull/16994
-// See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
export function viewOrCopy(view: Uint8Array, start: CharPtr, end: CharPtr): Uint8Array {
// this condition should be eliminated by rollup on non-threading builds
const needsCopy = isSharedArrayBuffer(view.buffer);
diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj
index 818641337c2d2..1afe827d1da03 100644
--- a/src/mono/wasm/wasm.proj
+++ b/src/mono/wasm/wasm.proj
@@ -424,8 +424,7 @@
diff --git a/src/native/libs/System.Native/pal_random.lib.js b/src/native/libs/System.Native/pal_random.lib.js
deleted file mode 100644
index 66cd390cccf26..0000000000000
--- a/src/native/libs/System.Native/pal_random.lib.js
+++ /dev/null
@@ -1,45 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-const DotNetEntropyLib = {
- $DOTNETENTROPY: {
- getBatchedRandomValues: function (buffer, bufferLength) {
- // batchedQuotaMax is the max number of bytes as specified by the api spec.
- // If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
- // https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
- const batchedQuotaMax = 65536;
-
- // Chrome doesn't want SharedArrayBuffer to be passed to crypto APIs
- const needTempBuf = typeof SharedArrayBuffer !== 'undefined' && Module.HEAPU8.buffer instanceof SharedArrayBuffer;
- // if we need a temporary buffer, make one that is big enough and write into it from the beginning
- // otherwise, use the wasm instance memory and write at the given 'buffer' pointer offset.
- const buf = needTempBuf ? new ArrayBuffer(bufferLength) : Module.HEAPU8.buffer;
- const offset = needTempBuf ? 0 : buffer;
- // for modern web browsers
- // map the work array to the memory buffer passed with the length
- for (let i = 0; i < bufferLength; i += batchedQuotaMax) {
- const view = new Uint8Array(buf, offset + i, Math.min(bufferLength - i, batchedQuotaMax));
- crypto.getRandomValues(view)
- }
- if (needTempBuf) {
- // copy data out of the temporary buffer into the wasm instance memory
- const heapView = new Uint8Array(Module.HEAPU8.buffer, buffer, bufferLength);
- heapView.set(new Uint8Array(buf));
- }
- }
- },
- dotnet_browser_entropy: function (buffer, bufferLength) {
- // check that we have crypto available
- if (typeof crypto === 'object' && typeof crypto['getRandomValues'] === 'function') {
- DOTNETENTROPY.getBatchedRandomValues(buffer, bufferLength)
- 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)
diff --git a/src/native/minipal/random.c b/src/native/minipal/random.c
index 2a0f57d53163a..bde7edc47d117 100644
--- a/src/native/minipal/random.c
+++ b/src/native/minipal/random.c
@@ -69,11 +69,11 @@ int32_t minipal_get_cryptographically_secure_random_bytes(uint8_t* buffer, int32
assert(buffer != NULL);
#ifdef __EMSCRIPTEN__
- extern int32_t dotnet_browser_entropy(uint8_t* buffer, int32_t bufferLength);
+ extern int32_t mono_wasm_browser_entropy(uint8_t* buffer, int32_t bufferLength);
static bool sMissingBrowserCrypto;
if (!sMissingBrowserCrypto)
{
- int32_t bff = dotnet_browser_entropy(buffer, bufferLength);
+ int32_t bff = mono_wasm_browser_entropy(buffer, bufferLength);
if (bff == -1)
sMissingBrowserCrypto = true;
else