Skip to content

Add WebAssembly (Blazor WASM) support — System.Security.Cryptography.ChaCha20Poly1305 is [UnsupportedOSPlatform("browser")] #2

Description

@petre-c

Summary

AgeSharp 0.2.0-preview.2 does not work in Blazor WebAssembly (or any other browser-WASM .NET host). Every age operation – encrypt and decrypt, passphrase mode and X25519 – throws:

PlatformNotSupportedException: Cryptography_AlgorithmNotSupported, ChaCha20Poly1305

Root cause: Age/Crypto/CryptoHelper.cs uses System.Security.Cryptography.ChaCha20Poly1305 directly. That BCL class is annotated [UnsupportedOSPlatform("browser")] (API ref), so on mono-wasm the constructor raises PlatformNotSupportedException. .IsSupported returns false and there is no native browser substitute (WebCrypto doesn't expose ChaCha20-Poly1305).

Affected files:

  • Age/Crypto/CryptoHelper.cs
  • Age/Crypto/EncryptStream.cs
  • Age/Crypto/DecryptStream.cs
  • Age/Crypto/StreamEncryption.cs

Why this matters

age is an obvious fit for client-side encryption in Blazor WASM apps (offline wallet tools, password-manager-style apps, Tails-friendly tooling). We hit this in PeteSparrowBTC/Seed-Phrase-Storage-SLIP39 – a SLIP-39 + age wallet-backup tool that needs to run airgapped in a browser – and had to fork to ship.

Suggested fix

Swap System.Security.Cryptography.ChaCha20Poly1305 for Org.BouncyCastle.Crypto.Modes.ChaCha20Poly1305 (pure-managed C#, works in WASM, already a transitive dep via the scrypt / X25519 paths).

The mechanical, minimum-diff approach is a small adapter class (BcChaCha20Poly1305) that mirrors the BCL surface (Encrypt(nonce, plaintext, ciphertext, tag, aad) / Decrypt(...) + IDisposable) and delegates to BC internally; then in each consuming file, a per-file type alias:

using ChaCha20Poly1305 = Age.Crypto.BcChaCha20Poly1305;

This keeps EncryptStream / DecryptStream / StreamEncryption / CryptoHelper source code completely unchanged downstream of the type alias.

Ready-made patch (PR-ready)

A working patch lives on the PeteSparrowBTC:wasm-bouncy-chacha branch (one commit). It:

  • Adds Age/Crypto/BcChaCha20Poly1305.cs – the adapter.
  • Adds the type alias to the 4 affected files.
  • Translates BC's InvalidCipherTextException to BCL's AuthenticationTagMismatchException so existing catch blocks in CryptoHelper continue to work unchanged.

Test results on that branch:

  • Age.Tests (323 tests): all pass on the patched branch.
  • Age.TestKit (61 failures): pre-existing on upstream main (verified via git stash round-trip), unrelated to this patch. Worth a separate triage.
  • Round-trip verified end-to-end in Blazor WASM by the consuming project: an age v1 ciphertext produced under WASM decrypts cleanly back to the original payload, and the derived BIP-32 master fingerprint matches the known-answer vector (73c5da0a for the abandon-seed). The previous PlatformNotSupportedException: ChaCha20Poly1305 is gone.

Happy to open a PR.

Environment

  • AgeSharp 0.2.0-preview.2 (NuGet)
  • BouncyCastle.Cryptography 2.6.2 (already a transitive dep)
  • .NET SDK 10.0.203 on Windows 11
  • Blazor WASM (Microsoft.AspNetCore.Components.WebAssembly 10.0.0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions