Skip to content

android.runtime.JavaProxyThrowable: [System.Security.Cryptography.CryptographicException]: Cryptography_ConcurrentUseNotSupported #9752

Open

Description

@aritchie

Android framework version

net9.0-android

Affected platform version

.NET 9.0.100, 9.0.102

Description

Trying to perform SHA1 hash with android assembly compression disabled ComputeHash to throw an exception: [System.Security.Cryptography.CryptographicException]: Cryptography_ConcurrentUseNotSupported

Steps to Reproduce

  1. Create a blank .net9.0 android application
  2. Add msbuild property:
<AndroidEnableAssemblyCompression>false</AndroidEnableAssemblyCompression>
  1. Add the following code:
  var hash = sha.ComputeHash(bytes); // will die here
  var hi = Convert.ToHexString(hash);
  Console.WriteLine("SAMPLE HASH: " + hi);
  1. Run in release mode
  2. Observe logcat for exception (shown in log output field)

Repro Sample: https://github.com/aritchie/android_net9_crypto_crash

Did you find any workaround?

No

Tried the following and causes an crypto loop internal mono crash

#if NET9_0 && ANDROID
this will cause an internal crash with mono
var hash = SHA1.HashData(bytes);
var hi = Convert.ToHexString(hash);
#endif

Relevant log output

ndroid.runtime.JavaProxyThrowable: [System.Security.Cryptography.CryptographicException]: Cryptography_ConcurrentUseNotSupported
02-04 15:00:51.928 I/MonoDroid(30757): 	at System.Security.Cryptography.ConcurrencyBlock.Enter + 0x1a(Unknown Source)
02-04 15:00:51.928 I/MonoDroid(30757): 	at System.Security.Cryptography.HashProviderDispenser+EvpHashProvider.FinalizeHashAndReset + 0x0(Unknown Source)
02-04 15:00:51.928 I/MonoDroid(30757): 	at System.Security.Cryptography.HashProvider.FinalizeHashAndReset + 0x13(Unknown Source)
02-04 15:00:51.928 I/MonoDroid(30757): 	at System.Security.Cryptography.SHA1+Implementation.HashFinal + 0x0(Unknown Source)
02-04 15:00:51.928 I/MonoDroid(30757): 	at System.Security.Cryptography.HashAlgorithm.CaptureHashCodeAndReinitialize + 0x0(Unknown Source)
02-04 15:00:51.928 I/MonoDroid(30757): 	at System.Security.Cryptography.HashAlgorithm.ComputeHash + 0x22(Unknown Source)
02-04 15:00:51.928 I/MonoDroid(30757): 	at Sentry.Internal.Extensions.HashExtensions.GetHashString + 0x11(Unknown Source)

Activity

  1. grendello commented on Feb 4, 2025

    @grendello
    Contributor

    Please record output of logcat using the following steps:

    $ adb shell setprop debug.mono.log default,assembly,mono_log_level=debug,mono_log_mask=all
    $ adb logcat -G 64M
    $ adb logcat -c
    # Start the application, wait for it to crash, then wait 5s and:
    $ adb logcat -d > log.txt

    Please attach the resulting file, thanks!

  2. added
    need-infoIssues that need more information from the author.
    and removed
    needs-triageIssues that need to be assigned.
    on Feb 4, 2025
  3. aritchie commented on Feb 4, 2025

    @aritchie
    Author
  4. added
    need-attentionA xamarin-android contributor needs to review
    and removed
    need-infoIssues that need more information from the author.
    on Feb 4, 2025
  5. removed their assignment
    on Mar 26, 2026
  6. yasmoradi commented on Oct 23, 2026

    @yasmoradi

    This one matters a lot to us. We ship .NET MAUI Android apps to Google Play, and assembly compression is the main reason their updates are big.

    Play builds update patches from the uncompressed contents of each file in the APK, but it can't see through the compression inside libassembly-store.so (LZ4 on .NET 10, zstd on .NET 11). A few changed bytes in an assembly cost its whole compressed size, and on CoreCLR the composite ReadyToRun image changes with any code change. On one of our apps, an update that only touches the app's own code comes to about 7.3 MB with compression and about 4.1 MB without it (bsdiff over the APK entries, the way Play builds its patches). The first install doesn't get bigger, because Play compresses downloads itself: the store is 23.6 MB with brotli when left raw, against 29.5 MB when it's LZ4 compressed. And the app no longer has to decompress assemblies at startup

    So AndroidEnableAssemblyCompression=false should be a plain win for any app on Play, but this bug turns it into a crash: anything that computes a hash, the Sentry SDK included, throws Cryptography_ConcurrentUseNotSupported.

    This has been open since February 2025, with a repro and the logs that were asked for, and it's still under consideration. Could someone take a look? 😥

    @jonathanpeppers

  7. jonathanpeppers commented on Oct 23, 2026

    @jonathanpeppers
    Member

    So AndroidEnableAssemblyCompression=false should be a plain win for any app on Play

    Why is it a plain win? It will increase your download and install size. From what we measured, the only gain is a minor improvement to startup time.

    The code example looks like BCL, this is code in the dotnet/runtime repo:

    var hash = SHA1.HashData(bytes);
    var hi = Convert.ToHexString(hash);

    Really, the only relevance here is that AndroidEnableAssemblyCompression=false is involved.

    There is a lot of mention of Mono above. Is the problem solved in .NET 11, which uses CoreCLR?

  8. yasmoradi commented on Oct 23, 2026

    @yasmoradi

    I'll check it on .NET 11 with CoreCLR and get back to you.

    On download size: Google Play compresses downloads itself, so for an app that only ships through Play, compressing the assemblies doesn't make the first download smaller. In our app it's actually larger (the store is 23.6 MB with brotli when raw, 29.5 MB when LZ4 compressed). Install size does grow, and we're fine with that.

    As I mentioned in my first comment, turning it off:

    1. Improves startup time
    2. Makes updates much smaller, which is my main concern (about 7.3 MB vs 4.1 MB for the same update)
  9. yasmoradi commented on Oct 23, 2026

    @yasmoradi

    I checked on .NET 11 RC2 with CoreCLR: with AndroidEnableAssemblyCompression=false, a Release build hashes fine (ComputeHash, HashData, IncrementalHash, HMAC), so this looks fixed there.

    On .NET 10 (Microsoft.Android.Sdk 36.1.118) the same app doesn't start at all, on both Mono and CoreCLR:
    dlopen failed: cannot locate symbol "compressed_assembly_count" referenced by libmonodroid.so

  10. yasmoradi commented on Oct 23, 2026

    @yasmoradi
  11. jonathanpeppers commented on Oct 23, 2026

    @jonathanpeppers
    Member

    So, this is likely an issue with the Mono runtime, which is removed in .NET 11.

    .NET 11 is "go live" since RC 1, I would recommend just upgrading: https://devblogs.microsoft.com/dotnet/dotnet-11-rc-1/

    Do you have other details on why you'd need AndroidEnableAssemblyCompression=false in the first place?

  12. yasmoradi commented on Oct 23, 2026

    @yasmoradi

    It doesn't work on CoreCLR on dotnet 10 as well
    Nope, I've no more details
    Thanks!

  13. jonathanpeppers commented on Oct 23, 2026

    @jonathanpeppers
    Member

    So, can you just not use AndroidEnableAssemblyCompression=false?

  14. yasmoradi commented on Oct 23, 2026

    @yasmoradi

    This is the first time I've gotten an answer like this, and I don't know what to say (":
    What happens if I say no? Would that force you to fix it?

    I'm just reporting a bug, nothing more. If it can be fixed, great.

    My app is 43 MB on Google Play, and every new version I publish comes as a 25 MB+ update 😓 (the 7.3 vs 4.1 MB I mentioned was the part that I believe is related to AndroidEnableAssemblyCompression).
    That's ridiculous, and it's sad to see other apps update with a few megabytes.

    I'd rather not move to .NET 11. Our solution uses Blazor Hybrid, Blazor WebAssembly, shared code and the backend API together, and Blazor WebAssembly on .NET 11 has gotten even worse for us: not many new features, not faster, and about 700 KB bigger for our web app.

    I know you're doing your best, and I trust your decision. I've seen MAUI Android get much better since you joined, so please take this as a bug report, nothing more.

    Regards 🙏

    P.S. I'm thinking about updating only the Maui-BlazorHybrid part of the project though to .NET 11 RC 2

  15. radimitrov commented on Oct 23, 2026

    @radimitrov

    @jonathanpeppers There are edge cases where compressed assemblies are a considerable overhead, because they incur extra "dead" RAM usage with the current implementation. This matters for apps that must function without IL trimming and without AOT, making DLLs larger and there are very few such apps but I assure you they do exist.
    And because of that I run a patched version of dotnet/android that replaces full-memory heap copies (malloc + memcpy) of assemblies with kernel-level Copy-On-Write (COW) memory management using mapped pointers directly in place. And while this is a minor security tradeoff because of PROT_WRITE, it reduces RAM usage on memory constrained devices by about 10% which was about 90 MB in my app. But for most apps those 10% will likely be 2% or likely less, I never tested that.
    The option for AndroidEnableAssemblyCompression=false should work and unless I am mistaken, it did work at some point so this is a bug.

  16. jonathanpeppers commented on Oct 23, 2026

    @jonathanpeppers
    Member

    Thanks, there seems to be enough interest to do something about this. I'll look into it next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area: App RuntimeIssues in `libmonodroid.so`.need-attentionA xamarin-android contributor needs to review

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions