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

It should be clearer why Guid.NewGuid fails in a .NET 7 wasmconsole (because crypto is not present in NodeJS by default) #79683

Closed
eduard-dumitru opened this issue Dec 14, 2022 · 4 comments
Labels
arch-wasm WebAssembly architecture area-System.Runtime

Comments

@eduard-dumitru
Copy link

eduard-dumitru commented Dec 14, 2022

Description

Looks like the wasm-experimental workload doesn't allow for the successful invocation of Guid.NewGuid, when creating a wasmconsole project and running in NodeJS:

image

As it turns out, this is because crypto is not present in the global scope, and Math.random is considered unfit for cryptography.

NodeJS does not provide crypto out of the box, as is the case with browsers.
Yet the wasm-tools and wasm-experimental workloads do not guide the user programmer in such a way that they're aware of this conundrum while employing dotnet new wasmconsole and then going ahead and calling Guid.NewGuid.

Given how Guid.NewGuid can be called by any 3rd party lib, far out in the dependency tree, I think a better error message would be in order, if technically possible.

@SteveSandersonMS 's dotnet-wasi-sdk was able to quickly and effectively guide me toward implementing part of WASI_SNAPSHOT_PREVIEW1 (including this very crypto thing).

It even told me what extern InternalCalls lacked bindings (i.e., TaskQueue.SetTimeout) so I quickly backfilled those through c and js.

Reproduction Steps

dotnet new wasmconsole
  • In Program.cs call Guid.NewGuid:
Console.WriteLine($"The guide is {Guid.NewGuid()}");
return 0;
  • Build and run
dotnet build
dotnet run

Expected behavior

I would expect Guid.NewGuid to work.
Given the workloads are experimental, I don't expect everything to work, but I think it's essential for you guys to receive feedback.

Also, I would suspect other capabilities to be lacking, such as TimerQueue.SetTimeout and whatnot, but those seem to work.

Actual behavior

You should be able to create a Guid in .NET 7 when targeting wasm and NodeJS by using a provided workload.

Regression?

I don't think this is a regression.

Known Workarounds

A mischievous workaround is falsifying the cryptographical strength of Math.random and adding right at the beginning of main.mjs:

globalThis.crypto = {
    getRandomValues(array) {
        for (let i = 0; i < array.length; i++) {
            const value = Math.floor(Math.random() * 256);
            array.set([value], i);
        }
    }
}

A better workaround is to turn the whole thing into a module project and install crypto.

Configuration

  • The problem is particular to the configuration, but not to the OS.
  • I am not using Blazor, but I am using .NET 7 compiled to wasm and running in NodeJS.

dotnet workload list

Installed Workload Id      Manifest Version      Installation Source
--------------------------------------------------------------------
wasm-experimental          7.0.1/7.0.100         SDK 7.0.100
wasm-tools                 7.0.1/7.0.100         SDK 7.0.100

dotnet --list-sdks

7.0.101 [C:\Program Files\dotnet\sdk]

Fwiw:

dotnet --list-runtimes

Microsoft.AspNetCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

node --version

v18.12.1

systeminfo

...
OS Name:                   Microsoft Windows 11 Enterprise
OS Version:                10.0.22000 N/A Build 22000
...

Other information

The call chain:

  • when calling Guid.NewGuid
  • it calls Sys.Interop.GetCryptographicallySecureRandom
  • which calls libSystem.Native/SystemNative_GetCryptographicallySecureRandomBytes
  • which calls the js-implemented extern called dotnet_browser_entropy
  • which returns non-zero if crypto is nowhere in sight
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Dec 14, 2022
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@eduard-dumitru eduard-dumitru changed the title Guid.NewGuid fails in .NET 7 wasmconsole It should be clearer why Guid.NewGuid fails in a .NET 7 wasmconsole (because crypto is not present in NodeJS by default) Dec 14, 2022
@vcsjones vcsjones added arch-wasm WebAssembly architecture area-System.Runtime labels Dec 14, 2022
@ghost
Copy link

ghost commented Dec 14, 2022

Tagging subscribers to 'arch-wasm': @lewing
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

Looks like the wasm-experimental workload doesn't allow for the successful invocation of Guid.NewGuid, when creating a wasmconsole project and running in NodeJS:

image

As it turns out, this is because crypto is not present in the global scope, and Math.random is considered unfit for cryptography.

NodeJS does not provide crypto out of the box, as is the case with browsers.
Yet the wasm-tools and wasm-experimental workloads do not guide the user programmer in such a way that they're aware of this conundrum while employing dotnet new wasmconsole and then going ahead and calling Guid.NewGuid.

Given how Guid.NewGuid can be called by any 3rd party lib, far out in the dependency tree, I think a better error message would be in order, if technically possible.

@SteveSandersonMS 's dotnet-wasi-sdk was able to quickly and effectively guide me toward implementing part of WASI_SNAPSHOT_PREVIEW1 (including this very crypto thing).

It even told me what extern InternalCalls lacked bindings (i.e., TaskQueue.SetTimeout) so I quickly backfilled those through c and js.

Reproduction Steps

dotnet new wasmconsole
  • In Program.cs call Guid.NewGuid:
Console.WriteLine($"The guide is {Guid.NewGuid()}");
return 0;
  • Build and run
dotnet build
dotnet run

Expected behavior

I would expect Guid.NewGuid to work.
Given the workloads are experimental, I don't expect everything to work, but I think it's essential for you guys to receive feedback.

Also, I would suspect other capabilities to be lacking, such as TimerQueue.SetTimeout and whatnot, but those seem to work.

Actual behavior

You should be able to create a Guid in .NET 7 when targeting wasm and NodeJS by using a provided workload.

Regression?

I don't think this is a regression.

Known Workarounds

A mischievous workaround is falsifying the cryptographical strength of Math.random and adding right at the beginning of main.mjs:

globalThis.crypto = {
    getRandomValues(array) {
        for (let i = 0; i < array.length; i++) {
            const value = Math.floor(Math.random() * 256);
            array.set([value], i);
        }
    }
}

A better workaround is to turn the whole thing into a module project and install crypto.

Configuration

  • The problem is particular to the configuration, but not to the OS.
  • I am not using Blazor, but I am using .NET 7 compiled to wasm and running in NodeJS.

dotnet workload list

Installed Workload Id      Manifest Version      Installation Source
--------------------------------------------------------------------
wasm-experimental          7.0.1/7.0.100         SDK 7.0.100
wasm-tools                 7.0.1/7.0.100         SDK 7.0.100

dotnet --list-sdks

7.0.101 [C:\Program Files\dotnet\sdk]

Fwiw:

dotnet --list-runtimes

Microsoft.AspNetCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 7.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

node --version

v18.12.1

systeminfo

...
OS Name:                   Microsoft Windows 11 Enterprise
OS Version:                10.0.22000 N/A Build 22000
...

Other information

The call chain:

  • when calling Guid.NewGuid
  • it calls Sys.Interop.GetCryptographicallySecureRandom
  • which calls libSystem.Native/SystemNative_GetCryptographicallySecureRandomBytes
  • which calls the js-implemented extern called dotnet_browser_entropy
  • which returns non-zero if crypto is nowhere in sight
Author: eduard-dumitru
Assignees: -
Labels:

arch-wasm, area-System.Runtime, untriaged

Milestone: -

@vcsjones
Copy link
Member

I believe this will be fixed when .NET 7.0.3 is released via #78766

Customers running node older than v19 are able to generate random bytes needed for example to generate guids. Without polyfill it fails with exception.

That pull request has 7.0.3 as a target milestone.

@maraf
Copy link
Member

maraf commented Dec 15, 2022

Duplicate of #77927

@maraf maraf marked this as a duplicate of #77927 Dec 15, 2022
@maraf maraf closed this as completed Dec 15, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Dec 15, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Jan 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
arch-wasm WebAssembly architecture area-System.Runtime
Projects
None yet
Development

No branches or pull requests

3 participants