Plinth.Security 1.8.0

Prefix Reserved
dotnet add package Plinth.Security --version 1.8.0
                    
NuGet\Install-Package Plinth.Security -Version 1.8.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Plinth.Security" Version="1.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Plinth.Security" Version="1.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Plinth.Security" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Plinth.Security --version 1.8.0
                    
#r "nuget: Plinth.Security, 1.8.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Plinth.Security@1.8.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Plinth.Security&version=1.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Plinth.Security&version=1.8.0
                    
Install as a Cake Tool

README

Plinth.Security

Security, Cryptography, and Token Utilities

Provides production-ready cryptographic utilities for common security scenarios including data encryption, password hashing, and predictable hashing.

  • Crypto
    • ISecureData: Symmetric encryption utility for encrypting data in transit and at rest
    • IPasswordHasher: Secure storage and validation of passwords using PBKDF2
    • IPredictableHasher: Mechanism for producing a secure one-way hash of sensitive data that is repeatable for uniqueness checks
  • Tokens
    • A library for generating secure, Plinth-specific authentication tokens, loosely based on JWE

ISecureData - Data Encryption

ISecureData provides symmetric encryption for protecting sensitive data at rest and in transit using AES-CBC with HMAC authentication.

Setup with Single Key

using Plinth.Security.Crypto;

// Generate a 32-byte (256-bit) hex key (64 hex characters)
var encryptionKey = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";

var secureData = new SecureData(encryptionKey);
services.AddSingleton<ISecureData>(secureData);

Setup with Key Rotation

Support multiple keys for seamless key rotation:

var secureData = new SecureData(
    defaultKeyId: 1,
    keyRing: [
        (0, "old_key_64_hex_chars..."),
        (1, "current_key_64_hex_chars..."),  // default for new encryptions
        (2, "future_key_64_hex_chars...")
    ]
);
services.AddSingleton<ISecureData>(secureData);

Encrypting and Decrypting Data

public class UserService
{
    private readonly ISecureData _secureData;

    public UserService(ISecureData secureData)
    {
        _secureData = secureData;
    }

    public async Task SaveSensitiveDataAsync(string ssn)
    {
        // Encrypt to Base64 string (suitable for database storage)
        var encrypted = _secureData.EncryptToBase64(ssn);

        // Or encrypt to hex string
        var encryptedHex = _secureData.EncryptToHex(ssn);

        // Or encrypt to byte array
        var encryptedBytes = _secureData.Encrypt(ssn);

        // Save encrypted value...
    }

    public async Task<string> GetSensitiveDataAsync()
    {
        // Retrieve encrypted value...
        var encrypted = "...";

        // Decrypt from Base64 string
        var decrypted = _secureData.DecryptBase64ToString(encrypted);

        // Or decrypt from hex string
        var decryptedFromHex = _secureData.DecryptHexToString(encrypted);

        // Or decrypt to byte array
        var decryptedBytes = _secureData.DecryptBase64(encrypted);

        return decrypted;
    }
}

Using Different Keys

// Encrypt with specific key ID
var encrypted = _secureData.EncryptToBase64(data, keyId: 2);

// Decryption automatically uses the correct key based on the encrypted data
var decrypted = _secureData.DecryptBase64ToString(encrypted);

Key Requirements

  • Keys must be 16, 24, or 32 bytes (32, 48, or 64 hex characters)
  • 32 bytes (AES-256) is recommended for production
  • Store keys securely (Azure Key Vault, AWS Secrets Manager, etc.)

IPasswordHasher - Password Hashing

IPasswordHasher provides secure password hashing using PBKDF2 with SHA-256, following OWASP recommendations.

Setup

using Plinth.Security.Crypto;

var passwordHasher = new PBKDF2PasswordHasher();
services.AddSingleton<IPasswordHasher>(passwordHasher);

Hashing Passwords

public class AuthService
{
    private readonly IPasswordHasher _passwordHasher;

    public AuthService(IPasswordHasher passwordHasher)
    {
        _passwordHasher = passwordHasher;
    }

    public async Task RegisterUserAsync(string email, string password)
    {
        // Hash the password (includes salt automatically)
        var hashedPassword = _passwordHasher.HashPassword(password);

        // Store hashedPassword in database...
        // Example: "04a1b2c3d4e5f6..."
    }

    public async Task<bool> LoginAsync(string email, string password)
    {
        // Retrieve hashed password from database...
        var storedHash = "...";

        // Verify password
        var isValid = _passwordHasher.VerifyPasswordHash(password, storedHash);

        return isValid;
    }
}

Version History

The implementation supports multiple versions for backward compatibility:

  • Version 1: 50k iterations, SHA-1 (legacy, don't use)
  • Version 2: 100k iterations, SHA-1 (legacy)
  • Version 3: 100k iterations, SHA-256 (2016-2021)
  • Version 4: 310k iterations, SHA-256 (2021-2022)
  • Version 5: 600k iterations, SHA-256 (2023-current, recommended)

The version is automatically detected during verification, allowing seamless migration.

IPredictableHasher - Deterministic Hashing

IPredictableHasher creates deterministic hashes for sensitive data that needs to be searchable or checked for uniqueness (e.g., SSNs, credit card numbers).

Setup

using Plinth.Security.Crypto;

// Generate a 32-byte (256-bit) hex key (64 hex characters)
var hashKey = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";

var predictableHasher = new PBKDF2PredictableHasher(
    hashKey: hashKey,
    hashLength: 32,        // 32 bytes recommended
    iterations: 310000     // 310k iterations recommended
);

services.AddSingleton<IPredictableHasher>(predictableHasher);

Usage Example

public class UserService
{
    private readonly IPredictableHasher _hasher;
    private readonly ISecureData _secureData;

    public UserService(IPredictableHasher hasher, ISecureData secureData)
    {
        _hasher = hasher;
        _secureData = secureData;
    }

    public async Task<bool> AddSsnAsync(string ssn)
    {
        // Create predictable hash for uniqueness check
        var ssnHash = _hasher.PredictableHash(ssn);

        // Check if SSN already exists (indexed column)
        if (await _db.Users.AnyAsync(u => u.SsnHash == ssnHash))
            return false; // SSN already exists

        // Encrypt the actual SSN for storage
        var encryptedSsn = _secureData.EncryptToBase64(ssn);

        // Store both encrypted SSN and hash
        var user = new User
        {
            SsnEncrypted = encryptedSsn,
            SsnHash = ssnHash  // For uniqueness checks
        };

        await _db.Users.AddAsync(user);
        await _db.SaveChangesAsync();

        return true;
    }

    public async Task<User?> FindBySsnAsync(string ssn)
    {
        // Hash the SSN to search
        var ssnHash = _hasher.PredictableHash(ssn);

        // Search by hash (indexed)
        return await _db.Users.FirstOrDefaultAsync(u => u.SsnHash == ssnHash);
    }
}

Use Cases

  • Social Security Numbers
  • Credit Card Numbers
  • Phone Numbers
  • Email Addresses (for duplicate detection while maintaining privacy)

Security Considerations

  • Use different keys for ISecureData and IPredictableHasher
  • Store the hash key securely
  • Use at least 310k iterations for production
  • Consider the trade-off: predictable hashes enable searching but reveal duplicates

Best Practices

  1. Key Management

    • Store all cryptographic keys in secure configuration (Azure Key Vault, AWS Secrets Manager, etc.)
    • Never commit keys to source control
    • Rotate encryption keys periodically
    • Use different keys for different purposes
  2. Password Hashing

    • Never try to decrypt password hashes (they're one-way)
    • Let the verifier handle version detection automatically
  3. Data Encryption

    • Use 32-byte (AES-256) keys for production
    • Encrypt sensitive data before storing in databases
    • Consider using predictable hashing for searchable encrypted data
  4. Predictable Hashing

    • Only use for data that needs to be searchable
    • Understand that identical inputs produce identical hashes
    • Use separate keys from ISecureData
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Plinth.Security:

Package Downloads
Plinth.AspNetCore

Plinth ASP.NET Core Services Utilities

Plinth.Storage

Plinth library for storing binary files

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.8.0 422 11/13/2025
1.8.0-b211.72089fd9 232 11/12/2025
1.7.4 1,473 8/6/2025
1.7.3 268 8/2/2025
1.7.2 3,741 3/16/2025
1.7.1 1,241 12/12/2024
1.7.0 2,474 11/12/2024
1.6.6 1,167 11/8/2024
1.6.5 3,348 8/31/2024
1.6.4 816 8/2/2024
1.6.3 2,161 5/15/2024
1.6.2 847 2/16/2024
1.6.1 5,310 1/5/2024
1.6.0 1,640 11/30/2023
1.5.10-b186.aca976b4 126 11/30/2023
1.5.9 504 11/29/2023
1.5.9-b174.64153841 147 11/23/2023
1.5.9-b172.dfc6e7bd 122 11/17/2023
1.5.9-b171.4e2b92e2 144 11/4/2023
1.5.8 1,111 10/23/2023
1.5.7 9,332 7/31/2023
1.5.6 7,243 7/13/2023
1.5.5 720 6/29/2023
1.5.4 1,848 3/7/2023
1.5.3 1,117 3/3/2023
1.5.2 1,373 1/11/2023
1.5.2-b92.7c961f5f 245 1/11/2023
1.5.0 1,770 11/9/2022
1.5.0-b88.7a7c20cd 221 11/9/2022
1.4.7 5,957 10/20/2022
1.4.6 2,931 10/17/2022
1.4.5 3,127 10/1/2022
1.4.4 3,227 8/16/2022
1.4.3 3,352 8/2/2022
1.4.2 3,276 7/19/2022
1.4.2-b80.7fdbfd04 249 7/19/2022
1.4.2-b74.acaf86f5 252 6/15/2022
1.4.1 3,306 6/13/2022
1.4.0 3,041 6/6/2022
1.3.8 4,340 4/12/2022
1.3.7 3,047 3/21/2022
1.3.6 3,068 3/17/2022
1.3.6-b67.ca5053f3 278 3/16/2022
1.3.6-b66.4a9683e6 263 3/16/2022
1.3.5 3,086 2/23/2022
1.3.4 3,569 1/20/2022
1.3.3 2,369 12/29/2021
1.3.2 1,884 12/11/2021
1.3.1 1,848 11/12/2021
1.3.0 1,854 11/8/2021
1.2.3 3,126 9/22/2021
1.2.2 2,114 8/20/2021
1.2.1 2,578 8/5/2021
1.2.0 3,990 8/1/2021
1.2.0-b37.a54030b9 305 6/24/2021
1.1.6 5,881 3/22/2021
1.1.5 2,195 3/9/2021
1.1.4 3,318 2/27/2021
1.1.3 2,102 2/17/2021
1.1.2 2,097 2/12/2021
1.1.1 2,473 2/1/2021
1.1.0 2,100 12/16/2020
1.1.0-b27.b66c309b 444 11/15/2020
1.0.12 4,138 10/18/2020
1.0.11 2,220 10/6/2020
1.0.10 2,225 9/30/2020
1.0.9 2,279 9/29/2020
1.0.8 2,331 9/26/2020
1.0.7 2,263 9/19/2020
1.0.6 2,229 9/3/2020
1.0.5 2,434 9/2/2020
1.0.4 2,546 9/1/2020
1.0.3 2,212 9/1/2020
1.0.2 2,300 8/29/2020
1.0.1 2,211 8/29/2020
1.0.0 2,258 8/29/2020
1.0.0-b1.c22f563d 393 8/28/2020

net10.0 support