Plinth.Security 1.8.1

Prefix Reserved
dotnet add package Plinth.Security --version 1.8.1
                    
NuGet\Install-Package Plinth.Security -Version 1.8.1
                    
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.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Plinth.Security" Version="1.8.1" />
                    
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.1
                    
#r "nuget: Plinth.Security, 1.8.1"
                    
#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.1
                    
#: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.1
                    
Install as a Cake Addin
#tool nuget:?package=Plinth.Security&version=1.8.1
                    
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.1 312 12/11/2025
1.8.0 444 11/13/2025
1.8.0-b211.72089fd9 241 11/12/2025
1.7.4 1,847 8/6/2025
1.7.3 288 8/2/2025
1.7.2 4,485 3/16/2025
1.7.1 1,296 12/12/2024
1.7.0 2,952 11/12/2024
1.6.6 1,178 11/8/2024
1.6.5 3,479 8/31/2024
1.6.4 830 8/2/2024
1.6.3 2,176 5/15/2024
1.6.2 862 2/16/2024
1.6.1 5,433 1/5/2024
1.6.0 1,647 11/30/2023
1.5.10-b186.aca976b4 132 11/30/2023
1.5.9 510 11/29/2023
1.5.9-b174.64153841 158 11/23/2023
1.5.9-b172.dfc6e7bd 128 11/17/2023
1.5.9-b171.4e2b92e2 150 11/4/2023
1.5.8 1,116 10/23/2023
1.5.7 9,368 7/31/2023
1.5.6 7,271 7/13/2023
1.5.5 728 6/29/2023
1.5.4 1,859 3/7/2023
1.5.3 1,133 3/3/2023
1.5.2 1,386 1/11/2023
1.5.2-b92.7c961f5f 257 1/11/2023
1.5.0 1,784 11/9/2022
1.5.0-b88.7a7c20cd 234 11/9/2022
1.4.7 5,972 10/20/2022
1.4.6 2,949 10/17/2022
1.4.5 3,146 10/1/2022
1.4.4 3,241 8/16/2022
1.4.3 3,369 8/2/2022
1.4.2 3,295 7/19/2022
1.4.2-b80.7fdbfd04 265 7/19/2022
1.4.2-b74.acaf86f5 269 6/15/2022
1.4.1 3,329 6/13/2022
1.4.0 3,057 6/6/2022
1.3.8 4,356 4/12/2022
1.3.7 3,062 3/21/2022
1.3.6 3,083 3/17/2022
1.3.6-b67.ca5053f3 290 3/16/2022
1.3.6-b66.4a9683e6 276 3/16/2022
1.3.5 3,103 2/23/2022
1.3.4 3,585 1/20/2022
1.3.3 2,431 12/29/2021
1.3.2 1,899 12/11/2021
1.3.1 1,865 11/12/2021
1.3.0 1,871 11/8/2021
1.2.3 3,144 9/22/2021
1.2.2 2,133 8/20/2021
1.2.1 2,594 8/5/2021
1.2.0 4,009 8/1/2021
1.2.0-b37.a54030b9 320 6/24/2021
1.1.6 5,899 3/22/2021
1.1.5 2,214 3/9/2021
1.1.4 3,337 2/27/2021
1.1.3 2,118 2/17/2021
1.1.2 2,113 2/12/2021
1.1.1 2,495 2/1/2021
1.1.0 2,119 12/16/2020
1.1.0-b27.b66c309b 460 11/15/2020
1.0.12 4,175 10/18/2020
1.0.11 2,240 10/6/2020
1.0.10 2,244 9/30/2020
1.0.9 2,298 9/29/2020
1.0.8 2,351 9/26/2020
1.0.7 2,287 9/19/2020
1.0.6 2,251 9/3/2020
1.0.5 2,453 9/2/2020
1.0.4 2,569 9/1/2020
1.0.3 2,236 9/1/2020
1.0.2 2,319 8/29/2020
1.0.1 2,230 8/29/2020
1.0.0 2,281 8/29/2020
1.0.0-b1.c22f563d 409 8/28/2020

net10.0 support