![]() |
VOOZH | about |
dotnet add package Davasorus.Utility.DotNet.Encryption --version 2026.2.3.1
NuGet\Install-Package Davasorus.Utility.DotNet.Encryption -Version 2026.2.3.1
<PackageReference Include="Davasorus.Utility.DotNet.Encryption" Version="2026.2.3.1" />
<PackageVersion Include="Davasorus.Utility.DotNet.Encryption" Version="2026.2.3.1" />Directory.Packages.props
<PackageReference Include="Davasorus.Utility.DotNet.Encryption" />Project file
paket add Davasorus.Utility.DotNet.Encryption --version 2026.2.3.1
#r "nuget: Davasorus.Utility.DotNet.Encryption, 2026.2.3.1"
#:package Davasorus.Utility.DotNet.Encryption@2026.2.3.1
#addin nuget:?package=Davasorus.Utility.DotNet.Encryption&version=2026.2.3.1Install as a Cake Addin
#tool nuget:?package=Davasorus.Utility.DotNet.Encryption&version=2026.2.3.1Install as a Cake Tool
V1 and V2 are retained for backward compatibility with existing ciphertext. Both use unauthenticated AES-CBC with fixed key-derivation parameters and should be considered obfuscation, not encryption, for new code. Use V3 for any new encryption needs.
V3 uses AES-256-GCM with a random IV per message, an authenticated envelope, and caller-supplied key material — no hardcoded secrets, no network dependencies.
Davasorus.Utility.DotNet.Encryption provides encryption and decryption utilities for .NET applications. The package ships three generations side by side:
[Obsolete], retained for backward compatibility).[Obsolete], retained for backward compatibility).string/byte[]/Stream overloads. This is the recommended API for new code.string, byte[] / ReadOnlyMemory<byte>, and Stream overloadsDecryptionResult for expected-failure outcomes; throws only on programmer errorsusing Microsoft.Extensions.DependencyInjection;
using Davasorus.Utility.DotNet.Encryption.V3.Configuration;
using Davasorus.Utility.DotNet.Encryption.V3.Service;
// At startup:
var key = Convert.FromBase64String(builder.Configuration["Encryption:Keys:Primary"]!); // 32 bytes
builder.Services.AddEncryptionServicesV3(opts => opts.AddKey("primary", key));
// In a scoped handler:
public class Handler(IEncryptionServiceV3 enc, IDecryptionServiceV3 dec)
{
public async Task<string> WrapAsync(string secret, CancellationToken ct)
=> await enc.EncryptAsync(secret, "primary", ct);
public async Task<string?> UnwrapAsync(string cipher, CancellationToken ct)
{
var result = await dec.DecryptAsync(cipher, ct);
return result.Success ? result.Value : null;
}
}
Lifecycles are fixed (not configurable): IEncryptionServiceV3/IDecryptionServiceV3 are Scoped, IEncryptionClientV3/IDecryptionClientV3 are Transient. The Service resolves a fresh Client per call and disposes it immediately — the Client zeros its key/plaintext buffers on dispose as a best-effort in-memory exposure mitigation.
Each V3 ciphertext is a base64url-encoded envelope:
| Offset | Size | Field |
|---|---|---|
| 0 | 1 byte | Version (0x01) |
| 1 | 1 byte | Key-name length N |
| 2 | N bytes | Key name (ASCII, [A-Za-z0-9._-], 1..64 chars) |
| 2+N | 12 bytes | Random IV |
| 14+N | L bytes | AES-GCM ciphertext |
| 14+N+L | 16 bytes | GCM auth tag |
The key name is embedded so that decrypt can look up the right key from the registered map. This enables key rotation: register the new key under a new name, start writing with it, and old data continues to decrypt as long as the old key is still registered.
builder.Services.AddEncryptionServicesV3(opts =>
{
opts.AddKey("2026-Q1", oldKeyBytes); // still decrypts old data
opts.AddKey("2026-Q2", newKeyBytes); // new data is encrypted under this
});
// App code chooses "2026-Q2" for new writes:
var cipher = await enc.EncryptAsync(value, "2026-Q2");
// Decrypt picks the right key based on the envelope:
var result = await dec.DecryptAsync(cipher); // works for both 2026-Q1 and 2026-Q2 ciphertext
When you're confident no 2026-Q1 ciphertext remains in the wild, remove it from the registration.
AES-GCM lets the caller bind a ciphertext to a piece of context without encrypting that context. The auth tag is computed over both the ciphertext and the AAD, so any tampering — including swapping ciphertexts between rows — is detected on decrypt.
AAD is not stored in the envelope. The caller MUST re-supply byte-identical AAD on decrypt, or decryption fails with DecryptionError.AuthenticationFailed.
Bind ciphertext to the context that should make it valid: the tenant id, customer id, record type, document version, or any other low-cardinality, deterministic value that identifies where this ciphertext belongs.
If the same caller wrote an encrypted SSN to row 42 and row 99, and AAD includes the row id, an attacker who swaps the two ciphertext blobs cannot bypass the auth tag — both decrypts now use the wrong AAD and fail loudly.
Imagine an encrypted DB column. Without AAD:
Row A: ciphertext = enc(key, "SSN-of-Alice")
Row B: ciphertext = enc(key, "SSN-of-Bob")
An attacker with write access copies row B's ciphertext into row A's cell. Decryption succeeds — the application reads Bob's SSN back as Alice's. AES-GCM can't tell the rows apart because the key is shared.
With AAD bound to the row identity:
var aadA = Encoding.UTF8.GetBytes("tenant=acme;record=user;id=A");
var aadB = Encoding.UTF8.GetBytes("tenant=acme;record=user;id=B");
var rowA = await enc.EncryptAsync("SSN-of-Alice", "primary", aadA);
var rowB = await enc.EncryptAsync("SSN-of-Bob", "primary", aadB);
// Attacker swaps blobs. Reader for row A loads rowB's blob but decrypts with aadA:
var swapped = await dec.DecryptAsync(rowB, aadA);
// swapped.Success == false; swapped.Error == DecryptionError.AuthenticationFailed
The auth tag was computed over rowB-ciphertext + aadB, so verifying with aadA mismatches and decryption rejects the message.
tenant=42 is a perfectly valid AAD.AuthenticationFailed on decrypt with AAD almost always means the AAD bytes don't match what was supplied on encrypt. Common causes:
Encoding.UTF8.GetBytes("Tenant-42") ≠ Encoding.ASCII.GetBytes("Tenant-42") if the string contains non-ASCII."tenant=42" ≠ "Tenant=42" ≠ "tenant=42 ".ReadOnlyMemory<byte>.Empty on encrypt decrypts cleanly with either the no-AAD overload or the AAD overload supplied with Empty. But no-AAD ciphertext cannot be decrypted by supplying non-empty AAD, and vice versa.The V1/V2 → V3 migrator does not add AAD to migrated ciphertext. Re-encrypted legacy values carry no AAD context. Callers who want AAD-protected storage for those rows must re-encrypt them explicitly (decrypt → encrypt with the desired AAD), not just rely on migration.
ArgumentNullException, EncryptionKeyNotFoundException, ObjectDisposedException, OperationCanceledException — for programmer errors and cancellation.DecryptionResult with Success = false and a DecryptionError for expected-failure decrypt outcomes: InvalidEnvelope, CiphertextTooShort, UnsupportedVersion, UnknownKey, AuthenticationFailed.Encrypt returns a plain string or byte[] on success (no result-wrapper — encrypt has no expected-failure mode once inputs validate).
This package includes comprehensive OpenTelemetry instrumentation for distributed tracing, metrics, and observability across all encryption and decryption operations (V1, V2, and V3).
Activities (Spans):
Encryption.EncryptValue - Service-level encryption operations (V2)Encryption.Encrypt - Client-level encryption operations (V2)Encryption.V1.Encrypt - Legacy encryption operations (V1)Decryption.DecryptValue - Service-level decryption operations (V2)Decryption.Decrypt - Client-level decryption operations (V2)Decryption.V1.Decrypt - Legacy decryption operations (V1)Tags (Attributes):
encryption.operation / decryption.operation - Operation type (encrypt/decrypt)encryption.input_length / decryption.input_length - Input data length in charactersencryption.output_length / decryption.output_length - Output data length in charactersencryption.valid_usage / decryption.valid_usage - Whether the usage type is validencryption.success / decryption.success - Whether the operation succeededencryption.version / decryption.version - API version (v1 for legacy APIs)crypto.algorithm - Encryption algorithm used (AES)crypto.key_derivation - Key derivation function (PBKDF2-HMAC-SHA512 for V2, PBKDF2-HMAC-SHA1 for V1)crypto.iterations - PBKDF2 iteration count (10,000)Note: The
encryption.usage/decryption.usagetags were removed. Because theUsageenum values (Static,Dynamic,api,web,desktop) are effectively the passwords used for V1/V2 PBKDF2 derivation, emitting them as trace tags would broadcast the secret. V3 has no such concern — keys are supplied at DI registration, and only the key name is exposed in traces.
Migrator (Davasorus.Utility.Encryption.V3.Migration source): one span per MigrateAsync call, named Encryption.V3.Migrate. Tags: migration.source_requested, migration.source_resolved, migration.target_key, migration.input_length, migration.output_length, error.type (failures only). See the Migrating legacy V1/V2 ciphertext to V3 section below for full details and the migration.target_key PII note.
Three instruments are emitted (via the shared Telemetry package's MeterHelper):
| Instrument | Kind | Unit | Dimensions |
|---|---|---|---|
encryption.operations.total |
Counter | {operation} |
version ∈ {v1,v2,v3}, operation ∈ {encrypt,decrypt}, success |
encryption.duration |
Histogram | ms | same dimensions |
encryption.input_bytes |
Histogram | bytes | same dimensions |
Events:
encoding.completed - Unicode encoding phase completed (encryption) with bytes_lengthdecoding.completed - Base64 decoding phase completed (decryption) with bytes_lengthcrypto.started - Cryptographic operation startedcrypto.completed - Cryptographic operation completedexception - Exception occurred with full exception details (type, message, stacktrace)The package uses Davasorus.Utility.Encryption as the ActivitySource name. To enable telemetry collection, configure OpenTelemetry in your application startup:
using OpenTelemetry.Trace;
// In Program.cs or Startup.cs
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("Davasorus.Utility.Encryption") // Enable encryption telemetry
.AddAspNetCoreInstrumentation() // Optional: ASP.NET Core tracing
.AddHttpClientInstrumentation() // Optional: HTTP client tracing
.AddConsoleExporter() // For development
// OR for production:
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri("http://your-otel-collector:4317");
})
);
All encryption and decryption operations automatically include trace context (TraceId, SpanId, ParentSpanId) in structured log messages. This enables seamless correlation between:
Example log output with trace context:
{
"timestamp": "2025-01-15T10:30:45.123Z",
"level": "Information",
"message": "Encryption complete",
"TraceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"SpanId": "00f067aa0ba902b7",
"ParentSpanId": "b7ad6b7169203331",
"InputLength": 256
}
The granular events enable detailed performance analysis:
Encoding Phase - Time spent converting data to bytes
encoding.completed event)decoding.completed event)Cryptographic Phase - Time spent in AES operations
crypto.started and crypto.completed eventsUse these events in your APM tool to identify bottlenecks and optimize performance.
No sensitive data is exposed in telemetry:
Exception messages are captured for debugging, but they do not contain sensitive cryptographic material.
Span: Encryption.EncryptValue [Service]
├─ Tags: encryption.operation=encrypt, encryption.input_length=256
├─ Child Span: Encryption.Encrypt [Client]
│ ├─ Tags: crypto.algorithm=AES, crypto.key_derivation=PBKDF2-HMAC-SHA512, crypto.iterations=10000
│ ├─ Event: encoding.completed (bytes_length=512)
│ ├─ Event: crypto.started
│ ├─ Event: crypto.completed
│ └─ Tags: encryption.output_length=344, encryption.success=true
└─ Status: Ok
If you have data encrypted under V1 or V2 that needs to be re-encrypted under V3, the package ships an IEncryptionMigrator (auto-registered by AddEncryptionServicesV3) that converts legacy ciphertext to V3 ciphertext without exposing plaintext to the caller. Plaintext exists only transiently inside the migrator while it decrypts the legacy value and immediately re-encrypts it as V3.
services.AddEncryptionServicesV3(b =>
b.AddKey("rotated-2026", keyBytes).SetActiveKey("rotated-2026"));
// Inside a scoped service:
public class ConfigMigration(IEncryptionMigrator migrator)
{
public async Task<string> RewrapAsync(string legacyCiphertext, string legacyUsage)
{
var result = await migrator.MigrateAsync(legacyCiphertext, legacyUsage);
if (!result.Success)
{
throw new InvalidOperationException(
$"Migration failed: {result.Error} — {result.ErrorMessage}");
}
return result.Value!;
}
}
The migrator exposes eight MigrateAsync overloads, organized along three axes:
| Axis | Choices |
|---|---|
| Input shape | Loose string (legacyCiphertext, legacyUsage) OR UtilitySettingsModel |
| Source version | Auto-detect (none specified) OR explicit LegacyVersion.V1 / V2 |
| Target V3 key | Active (uses SetActiveKey) OR explicit targetKeyName |
Two × two × two = eight overloads. Pick the one that matches your call site's available context.
When you don't pass a LegacyVersion, the migrator dispatches based on the legacy Usage value:
"api", "web", "desktop" → LegacyVersion.V1"Static", "Dynamic" → LegacyVersion.V2MigrationResult.Fail(InvalidLegacyUsage, ...)V1 and V2 Usage sets are disjoint, so dispatch is deterministic. There is no probing fallback — if Usage doesn't match either set, the call fails fast with InvalidLegacyUsage. Use the explicit-version overloads when you already know the source version (one less Usage validation roundtrip).
SetActiveKey setupThe parameterless-target overloads need a configured active key:
services.AddEncryptionServicesV3(b =>
b.AddKey("rotated-2026", keyBytes)
.SetActiveKey("rotated-2026")); // required for auto-target overloads
SetActiveKey validates at registration: if the named key wasn't added, registration throws InvalidOperationException.
Recommendation for batch migrations: prefer the explicit-key overloads. If a batch job runs while another tenant rotates the active key mid-flight, in-flight migrations could otherwise re-route to the new key unexpectedly. Explicit targetKeyName makes the rotation target visible at the call site.
MigrationResult.Error (MigrationError):
| Code | When |
|---|---|
InvalidLegacyUsage |
Legacy Usage isn't in V1's {api, web, desktop} or V2's {Static, Dynamic}. |
LegacyDecryptFailed |
V1/V2 returned empty (malformed ciphertext, wrong key, truncation). |
TargetKeyNotFound |
Explicit-key overload referenced an unregistered V3 key. |
NoActiveKeyConfigured |
Active-key overload but no SetActiveKey call. |
AmbiguousLegacyFormat |
Reserved for future use. Not currently produced. |
Programmer errors (null arguments, cancellation) throw ArgumentNullException / OperationCanceledException — they don't surface via MigrationResult.
V1 and V2 work in string plaintext, which the runtime can't securely zero (string is immutable, GC-managed). The migrator's plaintext-exposure window is the same as any caller using V1/V2 directly today — i.e., the plaintext lives in a heap-allocated string for the duration of the V1/V2 decrypt + V3 encrypt cycle, then becomes GC-eligible. V3's per-call client zeros its own scratch buffers via Dispose, so the V3 portion of the path is buffer-zeroed; the V1/V2 portion is not.
For workloads where this matters, consider re-encrypting from a controlled source (e.g., re-issue from an offline KMS) rather than reading from existing storage.
public sealed class CredentialsRotator(
IConfigurationStore store,
IEncryptionMigrator migrator)
{
public async Task<bool> RewrapRowAsync(int rowId, CancellationToken ct = default)
{
var row = await store.LoadAsync(rowId, ct);
var result = await migrator.MigrateAsync(row.EncryptedValue, row.Usage, ct);
if (!result.Success)
{
// Surface to caller without exposing plaintext.
return false;
}
await store.UpdateAsync(rowId, encryptedValue: result.Value!, ct);
return true;
}
}
The plaintext is never visible to RewrapRowAsync. The migrator's input and output are both encrypted strings.
Each migrate call emits an Activity span on the Davasorus.Utility.Encryption.V3.Migration ActivitySource and a metric datapoint on the existing Davasorus.Utility.Encryption.Operations meter (counter encryption.operations.total).
Span tags include migration.source_requested (v1 / v2 / auto), migration.source_resolved (v1 / v2, set when dispatch succeeds), migration.target_key, migration.input_length, and migration.output_length (success only). Failed calls additionally tag error.type with the MigrationError value.
migration.target_keyPII note. This tag emits the V3 key name on every migrate span. Most key names are fine to expose to a trace backend (Jaeger, Tempo, etc.). If your key naming scheme embeds tenant identifiers, customer IDs, or other PII (e.g.,tenant-12345-2026-q1), either rename your keys to opaque labels or filter the tag at your collector before export. The package emits the literal key name; sanitization is the consumer's responsibility.
Metric tags use version=migration and operation=v1->v3 / v2->v3 / auto->v3. The operation value reflects the caller's choice of overload, not the resolved version (so you can see "what overloads are consumers calling" in dashboards).
IEncryptionServiceV3/IDecryptionServiceV3 for new code, or IEncryptionService/IDecryptionService for V2) in your application code. The service manages all communication with the client internally.Note: Do not use the client classes directly in your application code. The service layer encapsulates all client logic, error handling, and logging.
V3 (Recommended for new code): see the V3 Quickstart above.
V1 (Synchronous, legacy):
var encrypt = new Encrypt(logger);
var encrypted = encrypt.EncryptValue(model);
var decrypt = new Decrypt(logger);
var decrypted = decrypt.DecryptValue(model);
V2 (Asynchronous, legacy):
// Register services and clients in DI (see below)
// In your consuming code, inject IEncryptionService and IDecryptionService
public class MyClass
{
private readonly IEncryptionService _encryptionService;
private readonly IDecryptionService _decryptionService;
public MyClass(IEncryptionService encryptionService, IDecryptionService decryptionService)
{
_encryptionService = encryptionService;
_decryptionService = decryptionService;
}
public async Task<string> EncryptAndDecrypt(UtilitySettingsModel model)
{
var encrypted = await _encryptionService.EncryptValue(model);
var decrypted = await _decryptionService.DecryptValue(model);
return decrypted;
}
}
IEncryptionServiceV3.EncryptAsync(string plaintext, string keyName, CancellationToken): Task<string>
Encrypts a UTF-8 string and returns the base64url-encoded envelope.
IEncryptionServiceV3.EncryptAsync(ReadOnlyMemory<byte> plaintext, string keyName, CancellationToken): Task<byte[]>
Encrypts raw bytes and returns the raw envelope bytes.
IEncryptionServiceV3.EncryptAsync(Stream input, Stream output, string keyName, CancellationToken): Task
Reads bytes from input and writes the envelope to output. Buffered, not streaming — see Known Limitations.
IDecryptionServiceV3.DecryptAsync(string ciphertext, CancellationToken): Task<DecryptionResult>
Decrypts a base64url-encoded envelope. Returns DecryptionResult with Success/Value/Error.
IDecryptionServiceV3.DecryptAsync(ReadOnlyMemory<byte> ciphertext, CancellationToken): Task<DecryptionResult<byte[]>>
Decrypts raw envelope bytes.
IDecryptionServiceV3.DecryptAsync(Stream input, Stream output, CancellationToken): Task<DecryptionResult<long>>
Decrypts envelope bytes from input into output; the result Value is the number of plaintext bytes written.
AAD overloads — every encrypt/decrypt method also has a variant accepting ReadOnlyMemory<byte> aad immediately before the CancellationToken. AAD is bound into the auth tag and MUST be re-supplied byte-identically on decrypt. See V3 Additional Authenticated Data (AAD).
Key registration is by name at DI time via EncryptionV3OptionsBuilder.AddKey(string name, byte[] key). Keys must be 32 bytes (AES-256). Names are ASCII [A-Za-z0-9._-], 1..64 chars, and embedded in each envelope so decrypt can route to the right key.
Error model: see V3 Error Model above. Decrypt returns DecryptionResult for expected failures; encrypt throws only on programmer errors.
EncryptValue(UtilitySettingsModel model): string
Synchronously encrypts the provided UtilitySettingsModel and returns the encrypted string. This method is part of the legacy V1 API and is intended for use in synchronous workflows.
DecryptValue(UtilitySettingsModel model): string
Synchronously decrypts the provided UtilitySettingsModel and returns the decrypted string. Use this method when asynchronous processing is not required.
Usage enum:
apiwebdesktopEncryptValueAsync(UtilitySettingsModel model): Task<string>
Asynchronously encrypts the provided UtilitySettingsModel. This method is internal to the service and not intended for direct use.
DecryptValueAsync(UtilitySettingsModel model): Task<string>
Asynchronously decrypts the provided UtilitySettingsModel. This method is internal to the service and not intended for direct use.
Service API:
EncryptValue(UtilitySettingsModel model): Task<string>UtilitySettingsModel via the service interface.DecryptValue(UtilitySettingsModel model): Task<string>UtilitySettingsModel via the service interface.Usage enum:
StaticDynamicIEncryptionClient/IDecryptionClient for V2, IEncryptionClientV3/IDecryptionClientV3 for V3) directly.IEncryptionServiceV3/IDecryptionServiceV3 for new code, or IEncryptionService/IDecryptionService for V2.| Feature/Behavior | V1 (Legacy) | V2 (Legacy) | V3 (Recommended) |
|---|---|---|---|
| API Design | Synchronous | Asynchronous | Asynchronous, with string/byte[]/Stream overloads |
| Algorithm | AES-CBC (unauthenticated) | AES-CBC (unauthenticated) | AES-256-GCM (authenticated) |
| IV / Nonce | Derived from password | Derived from password | Random 12-byte IV per message |
| Key Material | Hardcoded Usage enum value |
Hardcoded Usage enum value |
Caller-supplied 32-byte keys, registered by name in DI |
| Key Derivation | PBKDF2-HMAC-SHA1, static salt | PBKDF2-HMAC-SHA512, named salt | None — keys are used directly |
| Key Rotation | Not supported | Not supported | Supported via key-name embedded in envelope |
| Error Handling | Returns empty string on error | Returns empty string, logs, throws on invalid usage | Returns DecryptionResult for expected failures; throws only on programmer errors |
| .NET Support | .NET 8 | .NET 8 | .NET 8 |
| Status | [Obsolete] |
[Obsolete] |
Recommended for new code |
Usage enumstring / byte[] / Stream overloads on both servicesDecryptionResult distinguishes expected failures (bad envelope, unknown key, auth failure) from programmer errors (null args, disposed objects)Use AddEncryptionServicesV3 from Davasorus.Utility.DotNet.Encryption.V3.Configuration. At least one key must be registered or registration throws InvalidOperationException. Lifecycles are fixed: Service is Scoped, Client is Transient — these are part of the in-memory-exposure mitigation and are not configurable.
using Davasorus.Utility.DotNet.Encryption.V3.Configuration;
services.AddEncryptionServicesV3(opts =>
{
opts.AddKey("primary", primaryKeyBytes); // 32-byte AES-256 key
opts.AddKey("2026-Q1", oldKeyBytes); // optional: additional keys for rotation
});
V3 registration is independent of V2 — registering V3 does not modify V2 wiring, and the two can coexist during migration.
V2 uses the built-in extension methods from Davasorus.Utility.DotNet.Encryption.Configuration:
Recommended: Extension methods (registers both encryption and decryption)
using Davasorus.Utility.DotNet.Encryption.Configuration;
// Default (Scoped lifetime)
services.AddEncryptionServices();
// With custom lifetime
services.AddEncryptionServices(config => config.UseTransientLifetime());
services.AddEncryptionServices(config => config.UseSingletonLifetime());
Register only encryption or decryption:
services.AddEncryptionOnly();
services.AddDecryptionOnly();
Manual registration (alternative):
services.AddScoped<IEncryptionService, EncryptionService>();
services.AddScoped<IEncryptionClient, EncryptionClient>();
services.AddScoped<IDecryptionService, DecryptionService>();
services.AddScoped<IDecryptionClient, DecryptionClient>();
Note: Only inject and use the service interfaces (
IEncryptionServiceV3/IDecryptionServiceV3for V3, orIEncryptionService/IDecryptionServicefor V2) in your application code. The service manages all client interactions.
string, byte[], and Stream overloadsDecryptionResult { Success = false, Error = AuthenticationFailed }Error = UnknownKey; truncated/garbled envelope returns InvalidEnvelope / CiphertextTooShort / UnsupportedVersionMIT License
Contributions are welcome! Please submit issues or pull requests for improvements.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 3 NuGet packages that depend on Davasorus.Utility.DotNet.Encryption:
| Package | Downloads |
|---|---|
|
Davasorus.Utility.DotNet.SQS
Amazon SQS interaction for TEPS Utilities |
|
|
Davasorus.Utility.DotNet.Auth
Handles Authentication for TEPS Utilities |
|
|
SA.OpenSearchTool.Business
Package Description |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2026.2.3.1 | 150 | 6/13/2026 |
| 2026.2.2.14 | 2,195 | 5/31/2026 |
| 2026.2.2.13 | 2,060 | 5/25/2026 |
| 2026.2.2.12 | 1,296 | 5/23/2026 |
| 2026.2.2.11 | 731 | 5/17/2026 |
| 2026.2.2.10 | 1,087 | 5/15/2026 |
| 2026.2.2.9 | 101 | 5/14/2026 |
| 2026.2.2.8 | 94 | 5/14/2026 |
| 2026.2.2.7 | 1,301 | 5/5/2026 |
| 2026.2.2.6 | 113 | 5/5/2026 |
| 2026.2.2.5 | 100 | 5/5/2026 |
| 2026.2.2.4 | 111 | 5/5/2026 |
| 2026.2.2.3 | 101 | 5/5/2026 |
| 2026.2.2.2 | 1,109 | 5/1/2026 |
| 2026.2.2.1 | 165 | 5/1/2026 |
| 2026.2.1.7 | 295 | 4/23/2026 |
| 2026.2.1.6 | 139 | 4/23/2026 |
| 2026.2.1.5 | 143 | 4/22/2026 |
| 2026.2.1.4 | 189 | 4/16/2026 |
| 2026.2.1.3 | 5,843 | 4/9/2026 |