SaQura .NET · Upgrade notes

Versions & compatibility — SaQura .NET

Before you update

Current version: 1.0.15 · NuGet · SaQura (NuGet) · to the documentation

  • Data from every published version (1.0.0.2 to 1.0.15) is read by 1.0.15. The one exception: AES ciphertexts of the byte[] API from 1.0.4.4 or older need the migration helper introduced in 1.0.8 (see there).
  • Your license file stays valid. Since 1.0.13 there are optional binding fields; a license without them behaves byte-identically to before.
  • The package targets net8.0 plus net10.0-android, net10.0-ios and net10.0-maccatalyst. Desktop and server projects keep using the net8.0 target.

The tables under each version answer the same five questions in the same order. “Drop-in update: yes” means: our cross-platform test corpus has shown that the new version reads the data of the previous one and no call needs to change.

Optional modules

  • No optional modules. Every feature (AES, RSA, password hashing, Quantum Gen1–Gen8, ML-DSA/SLH-DSA, SQS1 streaming, licensing) ships in one assembly.
  • Dependency: BouncyCastle (transitive via NuGet, installed automatically).
  • Trimming and AOT: the mobile assemblies (net10.0-*) work with the iOS/Android trimmer and the AOT runtime, verified on devices. No linker descriptors of your own are needed.

Licenses & app binding

  • Unbound licenses are not affected by app binding: no call changes, no re-issue needed.
  • Bound distribution licenses (from 1.0.13) check the package/bundle id and the signing certificate as reported by the operating system: Android (package + certificate), iOS/Mac Catalyst (bundle id), Windows (host Authenticode), macOS desktop from 1.0.14 (signing identifier + certificate). Linux has no OS-attested app identity: use an unbound license there.
  • From 1.0.15 a revocation of a standard license confirmed by the license server is enforced and persisted. Distribution licenses and fully offline installations are not affected; their lifetime ends with the expiry date.

1.0.15 · 2026-07-15

License revocation enforced online and persisted; diagnostics moved to stderr

  • When the license server reports a standard license as revoked, the license is disabled and the state is persisted. The revocation applies immediately and on the next launch, even offline. An unreachable server stays non-fatal as before (offline grace).
  • Distribution licenses and fully offline installations are not checked online and therefore cannot be revoked; their lifetime is bounded by the expiry date.
  • License diagnostics (registration failures, file errors) go to stderr instead of stdout. Programs that use stdout as a data channel (for example an MCP server over stdio) are no longer disturbed.
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)unchanged
License files (bound / unbound)unchangedFile format unchanged; only the behaviour for server-revoked standard licenses is new.
Native libraries / ABIunchanged
R8 / keep rules, trimming / linkerunchanged
Minimum platformunchanged.NET 8.0
Drop-in update?Yes

1.0.14 · 2026-07-15

App binding also on macOS desktop

  • Bound distribution licenses are now enforced in native macOS desktop apps as well. The library reads its own code signature from the operating system: the signing identifier (for a signed .app its bundle id) and the SHA-256 of the signing certificate (for distribution, the Developer ID Application certificate).
  • An unsigned macOS host has no attested identity: a bound license is rejected there, unbound licenses keep working.
  • Coverage of the optional binding is now: Android, iOS/Mac Catalyst, Windows, macOS desktop. Linux: binding unavailable, ship an unbound license.
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)unchanged
License files (bound / unbound)new, additivePurely additive; existing licenses byte-identical.
Native libraries / ABIunchanged
R8 / keep rules, trimming / linkerunchanged
Minimum platformunchanged.NET 8.0
Drop-in update?Yes

1.0.13 · 2026-07-04

App binding for distribution licenses; .NET MAUI targets

  • Two optional license fields, boundPackage and boundSignature, tie a distribution license to the app's package/bundle id and signing certificate. A copied license file in a foreign app is rejected at activation (ValidationResult.BindingMismatch). New properties: LicenseInfo.BoundPackage and LicenseInfo.BoundSignature.
  • The app identity comes from the operating system, never from the caller. A license without the two fields behaves exactly as before; the fields are appended to the signed text after hardwareId, so existing licenses stay byte-identical.
  • The package additionally targets net10.0-android, net10.0-ios and net10.0-maccatalyst; the net8.0 target is unchanged. Native device binding requires these .NET 10 MAUI targets. A MAUI app on the net8.0 base has no device identity and rejects a bound license; unbound licenses run there unchanged.
  • The mobile assemblies work with the iOS/Android trimmer and the AOT runtime; accept and reject of the binding were verified on iPhone, Android and Windows.
  • 1.0.11 and 1.0.12 were interim builds of this feature and are superseded by 1.0.13.
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)unchanged
License files (bound / unbound)new, additiveOptional fields; unbound licenses byte-identical.
Native libraries / ABIchangedNew targets net10.0-android/-ios/-maccatalyst; net8.0 unchanged.
R8 / keep rules, trimming / linkernew, additiveMobile assemblies trimmer- and AOT-compatible; no linker rules of your own needed.
Minimum platformunchanged.NET 8.0; mobile targets need the .NET 10 SDK.
Drop-in update?Yes

1.0.10 · 2026-06-06

Streaming encryption for large files (SQS1)

  • New stream API in the SaQura namespace: EncryptStreamAsync / DecryptStreamAsync, EncryptFileAsync / DecryptFileAsync, ReadStreamInfoAsync and CountCompleteSegments (resume). Encrypts in fixed segments at constant memory (about twice the segment size, default 1 MiB), regardless of file size.
  • Two AEAD cipher suites, selected automatically from the header: AES-256-GCM and ChaCha20-Poly1305.
  • Post-quantum envelope (Pro): a random file key is wrapped once with a SaQura Quantum key pair (for example Gen8); stored as a sidecar .saqkey file (default) or embedded.
  • The new format carries its own SQS1 magic and is purely additive; no existing call and no format changed. Streaming from the Standard tier, the envelope from Pro.
  • License enforcement and free-tier marking hardened; no API or format change.
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)new, additiveNew SQS1 format; all previous formats unchanged.
License files (bound / unbound)unchanged
Native libraries / ABIunchanged
R8 / keep rules, trimming / linkerunchanged
Minimum platformunchanged.NET 8.0
Drop-in update?Yes

1.0.9 · 2026-06-05

NIST post-quantum algorithms: Gen8, ML-DSA, SLH-DSA

  • Generation 8: hybrid key encapsulation from X25519 and ML-KEM (FIPS 203). Both secrets are combined via HKDF-SHA256, then AES-256-GCM.
  • Signatures ML-DSA (FIPS 204) in strengths 44 / 65 / 87 and SLH-DSA (FIPS 205, SHA2) in 128f / 192f / 256f. Signing from Pro, verifying in every tier.
  • Gen8, ML-DSA and SLH-DSA are byte-identical to the Swift and Kotlin SDKs (verified in both directions).
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)new, additiveNew algorithms; Gen1–Gen7, AES, RSA unchanged.
License files (bound / unbound)unchanged
Native libraries / ABIunchanged
R8 / keep rules, trimming / linkerunchanged
Minimum platformunchanged.NET 8.0
Drop-in update?Yes

1.0.8 · 2026-05-19

Cross-platform alignment (includes the unpublished 1.0.5–1.0.7 builds)

  • AES-256-GCM byte[] API: the ciphertext is now emitted directly in the [nonce 12][ciphertext][tag 16] layout, without the earlier extra Base64 wrapping. The string API is unchanged. Stored byte[] ciphertexts from 1.0.4.4 or older: MigrateLegacyAESByteCiphertextAsync returns the plaintext bytes, then re-encrypt with EncryptWithAESAsync. The regular DecryptWithAESAsync(byte[]) reads only the new format.
  • PBKDF2-SHA512 password hashes: JSON field names in long form (algorithm, version, parameters, createdUtc), timestamps without fractional seconds. Verify reads both forms; existing hashes stay valid.
  • RSA-4096 hybrid: format unchanged for .NET; Swift and Kotlin aligned to it in their parallel releases.
  • Fixed: Quantum Generation 6 in strengths Medium and Highest (a wrong length in the header caused a decryption error). All 15 generation × strength combinations round-trip.
  • From 1.0.5: Quantum operations throw QuantumOperationException (with the subtypes QuantumKeyGenerationException, QuantumEncryptionException, QuantumDecryptionException) on internal failures instead of returning null. Authentication failures on decryption (wrong key, tampered data) still return string.Empty. Callers that checked for null add a try/catch.
  • From 1.0.6 and 1.0.7: internal diagnostic switches removed from release builds; the Quantum API rejects empty and zero-wiped key buffers with ArgumentException.
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)changedAES byte[] and PBKDF2 JSON changed; old PBKDF2 hashes still verify, old AES byte[] ciphertexts via the migration helper. RSA, Quantum, licenses unchanged.
License files (bound / unbound)unchanged
Native libraries / ABIunchanged
R8 / keep rules, trimming / linkerunchanged
Minimum platformunchanged.NET 8.0
Drop-in update?With migrationOnly for callers of the AES byte[] API with stored ciphertexts from 1.0.4.4 or older (one-time migration per record) and for code that evaluated null returns of the Quantum API. Every other caller: drop-in.

1.0.0.2 – 1.0.4.4 · 2025-12-30 – 2026-01-10

First releases

  • 1.0.0.2: first release with AES-256-GCM, RSA-4096, password hashing, digital signatures, post-quantum encryption (generations 1–7), license tiers, offline activation via .lic file, plus iOS and Android.
  • 1.0.1.2: distribution licenses (LicenseType.Distribution) for App Store and Play Store apps: no device binding, unlimited activations, signature-only validation. License keys accept any two- to four-character tier prefix.
  • 1.0.2.2: AES-GCM on iOS and macOS fixed (previously PlatformNotSupportedException).
  • 1.0.3.2: license-server registration runs in the background without blocking; server rejections are reported to the caller.
  • 1.0.4.2: documentation. 1.0.4.4: better mobile platform detection, no more activation timeout on iOS.
CompatibilityStatusNote
Data formats (keys, ciphertexts, streams)unchangedUnchanged within this series; the AES byte[] change came with 1.0.8.
License files (bound / unbound)new, additiveDistribution license type from 1.0.1.2.
Native libraries / ABIunchanged
R8 / keep rules, trimming / linkerunchanged
Minimum platformunchanged.NET 8.0
Drop-in update?Yes