The DotNetExtras.Security library implements most commonly used security operations. For the detailed description of the library API, code samples, and usage scenarios, see the API documentation section.
The DotNetExtras.Security library groups the security classes and extension methods under the following namespaces:
DotNetExtras.Security: Implements generic security and cryptographic operations.
Crypto: Encrypts and decrypts a string value using the symmetric key (AES/Rijndael) algorithm with a 256-bit key derived from the specified password and a random salt.
Hash: Hashes a string value using a secure SHA algorithm and a random salt; validates the generated hash value accounting for the random salt.
Jwt: Generates and validates a JSON Web Token (JWT).
Password: Generates a random password. The generated password will start with either a letter (lower or upper case) or a number. The password longer than four characters is guaranteed to include at least one of the following: lower-case letter, upper-case letter, number, special character. Every four character group will include characters from one of the four categories. The password will not contain letters, numbers and special characters that may appear ambiguous, such as 1, l, or I. The list special characters that may be included in the password, includes: *$-+?_&=!%{}/[].,':;~().
DotNetExtras.Security.Json: Defines types and operations used for JSON serialization of sensitive properties.
JsonExtensions: Implements extension methods for JSON conversion of any objects with sensitive properties via the System.Text.Json (STJ) serialization.
MaskAttribute: Defines an attribute that can be applied to the custom class properties to mask the property values during JSON conversion via the System.Text.Json (STJ) serialization.
The following sections provide code examples and usage scenarios for the DotNetExtras.Security classes.
The Crypto class simplifies the symmetric key encryption and decryption operation. Before encrypting the plain text value, it generates a random salt that it adds in front of the plain text and includes the salt value in the cipher text. The cipher text value will be base64-encoded.
using DotNetExtras.Security;
...
string plainText = "Hello, World!";
string password = "never-hard-code-passwords!";
// Encrypt the plain text using the password to generate the symmetric key.
string encrypted = Crypto.Encrypt(plainText, password)
// Decrypt the cipher text using the same password to get the original plain text.
string decrypted = Crypto.Decrypt(encryptedText, password);The Hash class generates a random salt and appends it in front of the plain text value before hashing it. The hashed value will be hex-encoded. The validation method will use the salt included in the hash value.
using DotNetExtras.Security;
...
string plainText = "Hello, World!";
HashType hashType = HashType.SHA256;
// Use either option to generate the hash value.
// Option 1: Static class method (salt value must be explicitly passed in, if needed).
// string hashText = Hash.Generate(hashType, plainText);
// Option 2: Extension method (salt value will be generated automatically, if needed).
string hashText = plainText.ToHash(hashType)
// Given the hash value, validate the plain text
// (the method will account for the random salt assuming that it is appended to the hash).
bool valid = Hash.Validate(hashType, hashText, "Hello, World!")The Jwt class generates and validates JSON Web Tokens (JWTs). This class relies on the JWT implementation provided by the System.IdentityModel.Tokens.Jwt NuGet package.
using System.Security.Claims;
using DotNetExtras.Security;
...
string secret = "never-hard-code-passwords!";
string email = "joe.doe@sample.com";
int tokenExpirationSeconds = 3600; // 1 hour
Jwt jwt = new(secret, tokenExpirationSeconds);
string token = jwt.Generate(email);
ClaimsPrincipal principal = jwt.Validate(token);
email = principal.FindFirst(ClaimTypes.Email)?.Value;The Password class generates a random password without ambiguous characters (such as 1, I, l or 0, O). The password will contain at least one character from each of the following categories: lowercase letters (abcdefgijkmnopqrstwxyz), uppercase letters (ABCDEFGHJKLMNPQRSTWXYZ), digits (23456789), and special characters (*$-+?_&=!%{}/[].,':;~()). In each group of four characters, the password will contain at least one character from one of the four categories.
using DotNetExtras.Security;
...
// Generate a random password between 12 and 16 characters long.
string randomPassword = Password.Generate(12, 16);The JsonExtensions class offers extension methods for JSON conversion using the System.Text.Json that would null out or mask sensitive properties of the serialized object.
using DotNetExtras.Security.Json;
...
// Let's assume that this is someone else's class, so you cannot modify it.
User user = new()
{
UserName = "joe.doe",
Password = "never-hard-code-passwords!",
Email = "joe.doe@sample.com",
PersonalData = new()
{
Ssn = "123-45-6789"
}
};
string? json;
// Serialize the user object to JSON,
// replacing the Password property value with null.
json = user.ToJson("Password");
// Serialize the user object to JSON,
// replacing the Password and PersonalData.Ssn property values with "###".
json = user.ToJson("###", "Password", "PersonalData.Ssn");
// Serialize the user object to JSON,
// masking the Password and PersonalData.Ssn property values
// with the asterisk characters,
// but leaving the first and last 2 characters in plain text.
json = user.ToJson('*', 2, 2, "Password", "PersonalData.Ssn");The MaskAttribute class can be applied to the class properties, so that the property values are automatically masked by the JSON serialization operation performed using System.Text.Json (STJ).
using DotNetExtras.Security.Json;
...
public class Demo
{
// Value will be replaced with null.
[Mask()]
public string? Secret1 { get; set; }
// Value will be replaced with an empty string.
[Mask("")]
public string? Secret2 { get; set; }
// Value will be replaced with the literal string "***masked***".
[Mask("***masked***")]
public string? Secret3 { get; set; }
// All characters in the value will be replaced with asterisks
// except the first two and the last three which will remain in plain text.
[Mask('*', 2, 3)]
public string? Secret5 { get; set; }
// Value will be replaced with the hex-encoded SHA-256 hash.
[Mask(HashType.SHA256)]
public string? Secret4 { get; set; }
}For more examples of available functionality, see the unit test project.