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)
Summary
AgeSharp 0.2.0-preview.2does not work in Blazor WebAssembly (or any other browser-WASM .NET host). Every age operation – encrypt and decrypt, passphrase mode and X25519 – throws:Root cause:
Age/Crypto/CryptoHelper.csusesSystem.Security.Cryptography.ChaCha20Poly1305directly. That BCL class is annotated[UnsupportedOSPlatform("browser")](API ref), so onmono-wasmthe constructor raisesPlatformNotSupportedException..IsSupportedreturnsfalseand there is no native browser substitute (WebCrypto doesn't expose ChaCha20-Poly1305).Affected files:
Age/Crypto/CryptoHelper.csAge/Crypto/EncryptStream.csAge/Crypto/DecryptStream.csAge/Crypto/StreamEncryption.csWhy this matters
ageis 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.ChaCha20Poly1305forOrg.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:This keeps
EncryptStream/DecryptStream/StreamEncryption/CryptoHelpersource code completely unchanged downstream of the type alias.Ready-made patch (PR-ready)
A working patch lives on the
PeteSparrowBTC:wasm-bouncy-chachabranch (one commit). It:Age/Crypto/BcChaCha20Poly1305.cs– the adapter.InvalidCipherTextExceptionto BCL'sAuthenticationTagMismatchExceptionso existing catch blocks inCryptoHelpercontinue 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 upstreammain(verified viagit stashround-trip), unrelated to this patch. Worth a separate triage.73c5da0afor the abandon-seed). The previousPlatformNotSupportedException: ChaCha20Poly1305is gone.Happy to open a PR.
Environment
AgeSharp0.2.0-preview.2 (NuGet)BouncyCastle.Cryptography2.6.2 (already a transitive dep)