Encryption and Security Reference
This page documents the encryption and security utilities available in Nextended.Core.
Overview
Nextended provides built-in encryption classes for securing sensitive string data using industry-standard algorithms:
- AesEncryption - AES encryption with PBKDF2 key derivation
- RijndaelEncryption - Rijndael (AES) encryption with CBC mode
Both classes implement the IStringEncryption interface for consistent usage patterns.
AesEncryption
Namespace: Nextended.Core.Encryption
Provides string encryption and decryption using the AES (Advanced Encryption Standard) algorithm with PBKDF2 (Password-Based Key Derivation Function 2) for secure key generation.
Features
- 256-bit key size for strong encryption
- PBKDF2 key derivation with configurable iterations
- Automatic IV generation for each encryption operation
- Configurable salt for key derivation
- Base64 encoding of encrypted output
Properties
| Property | Type | Default | Description |
|---|---|---|---|
Salt | byte[] | Default salt | Salt used for PBKDF2 key derivation |
Iterations | int | 1223 | Number of PBKDF2 iterations |
Methods
| Method | Description |
|---|---|
Encrypt(string clearText, string key) | Encrypts text and returns Base64 string |
Decrypt(string cipherText, string key) | Decrypts Base64 string back to text |
Example Usage
using Nextended.Core.Encryption;
var aes = new AesEncryption();
// Encrypt sensitive data
string password = "MySecretPassword";
string key = "MyEncryptionKey123";
string encrypted = aes.Encrypt(password, key);
Console.WriteLine($"Encrypted: {encrypted}");
// Decrypt data
string decrypted = aes.Decrypt(encrypted, key);
Console.WriteLine($"Decrypted: {decrypted}"); // "MySecretPassword"
// Custom configuration
var customAes = new AesEncryption
{
Iterations = 10000 // Higher iterations = more secure but slower
};
string secureEncrypted = customAes.Encrypt("SensitiveData", key);
Security Considerations
- Key Storage: Never store encryption keys in source code. Use secure key management systems.
- Iterations: Higher iteration counts increase security but reduce performance. Balance based on your needs.
- Salt: While a default salt is provided, consider using unique salts per user/application for enhanced security.
RijndaelEncryption
Namespace: Nextended.Core.Encryption
Provides string encryption and decryption using the Rijndael algorithm (the basis for AES) with CBC (Cipher Block Chaining) mode and PKCS7 padding.
Features
- 128-bit block size and 128-bit key size
- Random salt and IV generation for each encryption
- CBC mode with PKCS7 padding
- RFC2898 key derivation with configurable iterations
- Base64 encoding of encrypted output
Properties
| Property | Type | Default | Description |
|---|---|---|---|
Iterations | int | 1347 | Number of iterations for key derivation |
Methods
| Method | Description |
|---|---|
Encrypt(string str, string key) | Encrypts string and returns Base64 string |
Decrypt(string str, string key) | Decrypts Base64 string back to original text |
Example Usage
using Nextended.Core.Encryption;
var rijndael = new RijndaelEncryption();
// Encrypt credit card number
string cardNumber = "4111-1111-1111-1111";
string encryptionKey = "StrongKey!123";
string encrypted = rijndael.Encrypt(cardNumber, encryptionKey);
Console.WriteLine($"Encrypted card: {encrypted}");
// Decrypt when needed
string decrypted = rijndael.Decrypt(encrypted, encryptionKey);
Console.WriteLine($"Decrypted card: {decrypted}");
// Adjust security level
var secureRijndael = new RijndaelEncryption
{
Iterations = 5000
};
string moreSecure = secureRijndael.Encrypt("TopSecret", encryptionKey);
Technical Details
- Each encryption generates a random salt and random IV (Initialization Vector)
- The salt and IV are prepended to the ciphertext, allowing for decryption without storing them separately
- Key is derived using Rfc2898DeriveBytes (PBKDF2) with the provided password and random salt
IStringEncryption Interface
Namespace: Nextended.Core.Contracts
Common interface implemented by all encryption classes, enabling polymorphic usage.
public interface IStringEncryption
{
string Encrypt(string clearText, string key);
string Decrypt(string cipherText, string key);
int Iterations { get; set; }
}
Example Usage
using Nextended.Core.Contracts;
using Nextended.Core.Encryption;
// Use interface for flexibility
IStringEncryption encryption;
if (useAes)
encryption = new AesEncryption();
else
encryption = new RijndaelEncryption();
// Common usage pattern
string encrypted = encryption.Encrypt("MyData", "MyKey");
string decrypted = encryption.Decrypt(encrypted, "MyKey");
Best Practices
Key Management
- Never hardcode keys in source code
- Use environment variables or secure key vaults (Azure Key Vault, AWS KMS, etc.)
- Implement key rotation policies for long-lived applications
- Use different keys for different security domains
// Good: Key from secure source
string key = Environment.GetEnvironmentVariable("ENCRYPTION_KEY");
if (string.IsNullOrEmpty(key))
throw new InvalidOperationException("Encryption key not configured");
var aes = new AesEncryption();
string encrypted = aes.Encrypt(sensitiveData, key);
Data Storage
- Always encrypt sensitive data before storage
- Consider field-level encryption for databases
- Use encryption at rest for file storage
- Implement secure deletion for decrypted data in memory
using Nextended.Core.Encryption;
public class UserRepository
{
private readonly IStringEncryption _encryption;
private readonly string _key;
public UserRepository(IStringEncryption encryption, string key)
{
_encryption = encryption;
_key = key;
}
public void SaveUser(User user)
{
// Encrypt sensitive fields before saving
var encryptedUser = new UserDto
{
Id = user.Id,
Username = user.Username,
Email = _encryption.Encrypt(user.Email, _key),
SSN = _encryption.Encrypt(user.SSN, _key)
};
// Save to database
SaveToDatabase(encryptedUser);
}
public User GetUser(int id)
{
var dto = LoadFromDatabase(id);
// Decrypt sensitive fields
return new User
{
Id = dto.Id,
Username = dto.Username,
Email = _encryption.Decrypt(dto.Email, _key),
SSN = _encryption.Decrypt(dto.SSN, _key)
};
}
}
Configuration
- Increase iterations for better security (at the cost of performance)
- Test performance impact before deploying to production
- Use consistent settings across encryption and decryption
- Document your security configuration decisions
// Development: Lower iterations for faster testing
#if DEBUG
var encryption = new AesEncryption { Iterations = 1000 };
#else
// Production: Higher iterations for security
var encryption = new AesEncryption { Iterations = 10000 };
#endif
Error Handling
- Never expose encryption details in error messages
- Log security events (failed decryption attempts, etc.)
- Implement rate limiting to prevent brute force attacks
- Use generic error messages to avoid information leakage
try
{
string decrypted = encryption.Decrypt(cipherText, key);
return decrypted;
}
catch (CryptographicException)
{
// Log for security monitoring
_logger.LogWarning("Failed decryption attempt");
// Generic error to user
throw new InvalidOperationException("Unable to decrypt data");
}
Choosing Between AES and Rijndael
Both implementations are secure, but have subtle differences:
Use AesEncryption when:
- You need modern .NET APIs (available in newer frameworks)
- You want SHA-512 key derivation (non-.NET Standard 2.0)
- You need maximum compatibility with other systems
Use RijndaelEncryption when:
- You need explicit control over block size
- You’re working with legacy systems that require Rijndael
- You need CBC mode with specific configurations
For Most Applications:
AesEncryption is recommended as it uses modern cryptographic best practices and will receive ongoing security updates.
Performance Considerations
Iteration Count Impact
Higher iterations increase security but reduce performance:
| Iterations | Relative Speed | Security Level |
|---|---|---|
| 1,000 | Fastest | Basic |
| 10,000 | Medium | Recommended |
| 100,000 | Slower | High Security |
| 1,000,000 | Slowest | Maximum |
Benchmarks (Approximate)
On typical hardware:
- 1,000 iterations: ~1-2ms per encryption
- 10,000 iterations: ~10-20ms per encryption
- 100,000 iterations: ~100-200ms per encryption
Optimization Tips
- Cache encryption instances - creating new instances is expensive
- Batch encrypt when possible
- Consider async operations for UI applications
- Profile your specific use case before optimizing
// Good: Reuse instance
private static readonly AesEncryption _encryption = new AesEncryption();
public string EncryptData(string data, string key)
{
return _encryption.Encrypt(data, key);
}
// Async for UI responsiveness
public async Task<string> EncryptDataAsync(string data, string key)
{
return await Task.Run(() => _encryption.Encrypt(data, key));
}