Encryption and Decryption in .NET
|
|
Encrypting and decrypting sensitive information like usernames and passwords in .NET Core involves using cryptographic methods to protect the data.
Hashing Passwords (Recommended for Storage)
- For storing passwords in a database, hashing is the recommended approach. Hashing is a one-way process, meaning the original password cannot be retrieved from the hash.
- ASP.NET Core Identity: provides built-in mechanisms for securely hashing and salting passwords using
PasswordHasher.
- Salting: involves adding a unique, random value (the salt) to the password before hashing.
- Pepper: can be added as an additional secret key known only to the application.
Example using PasswordHasher
using Microsoft.AspNetCore.Identity;
public class UserService
{
private readonly IPasswordHasher<ApplicationUser> _passwordHasher;
public UserService(IPasswordHasher<ApplicationUser> passwordHasher)
{
_passwordHasher = passwordHasher;
}
public string HashPassword(ApplicationUser user, string password)
{
return _passwordHasher.HashPassword(user, password);
}
public PasswordVerificationResult VerifyPassword(ApplicationUser user, string hashedPassword, string providedPassword)
{
return _passwordHasher.VerifyHashedPassword(user, hashedPassword, providedPassword);
}
}
Symmetric Encryption (for Usernames or Data requiring Decryption)
- Use symmetric encryption like AES for data that must be retrievable in its original form.
- Same key is used for both encryption and decryption.
System.Security.Cryptography namespace provides cryptographic classes.
Aes.Create() creates an AES instance.
Rfc2898DeriveBytes derives a strong key and IV from a password.
Symmetric Encryption with AES
- Generate or supply a 256-bit key and a 128-bit IV.
- Create an Aes instance.
- Wrap streams in CryptoStream.
- Dispose objects to zero out sensitive data.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class AesEncryption
{
public static (byte[] Cipher, byte[] Key, byte[] IV) Encrypt(string plainText)
{
using var aes = Aes.Create();
aes.GenerateKey();
aes.GenerateIV();
var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using var ms = new MemoryStream();
using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
using (var writer = new StreamWriter(cs, Encoding.UTF8))
{
writer.Write(plainText);
}
return (ms.ToArray(), aes.Key, aes.IV);
}
public static string Decrypt(byte[] cipher, byte[] key, byte[] iv)
{
using var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using var ms = new MemoryStream(cipher);
using var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read);
using var reader = new StreamReader(cs, Encoding.UTF8);
return reader.ReadToEnd();
}
}
Asymmetric Encryption with RSA
- Uses a public/private key pair.
- Encrypt with the public key, decrypt with the private key.
- Use
RSA.Create() or RSACryptoServiceProvider.
- Use OAEP padding for secure encryption.
using System;
using System.Security.Cryptography;
using System.Text;
public class RsaEncryption
{
public static (string PublicKey, string PrivateKey) GenerateKeys()
{
using var rsa = RSA.Create(2048);
return (rsa.ToXmlString(false), rsa.ToXmlString(true));
}
public static byte[] Encrypt(string plainText, string publicKeyXml)
{
using var rsa = RSA.Create();
rsa.FromXmlString(publicKeyXml);
return rsa.Encrypt(Encoding.UTF8.GetBytes(plainText), RSAEncryptionPadding.OaepSHA256);
}
public static string Decrypt(byte[] cipher, string privateKeyXml)
{
using var rsa = RSA.Create();
rsa.FromXmlString(privateKeyXml);
var bytes = rsa.Decrypt(cipher, RSAEncryptionPadding.OaepSHA256);
return Encoding.UTF8.GetString(bytes);
}
}
Another Example of AES Encryption/Decryption
using System.Security.Cryptography;
using System.Text;
public class DataEncryptor
{
private const string EncryptionKey = "YourStrongEncryptionKeyHere";
public static string Encrypt(string plainText)
{
byte[] clearBytes = Encoding.Unicode.GetBytes(plainText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] {
0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64,
0x76, 0x65, 0x64, 0x65, 0x76
});
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
plainText = Convert.ToBase64String(ms.ToArray());
}
}
return plainText;
}
public static string Decrypt(string cipherText)
{
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] {
0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64,
0x76, 0x65, 0x64, 0x65, 0x76
});
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
}
Important Considerations
- Never store encryption keys directly in code or config files.
- Hashing is for passwords; encryption is for retrievable data.
- Regularly review and update security practices.
Best Practices
- Use
RandomNumberGenerator.Create() for secure randomness.
- Never reuse IVs with the same key.
- Protect and rotate keys using secure vaults.
- Prefer OAEP padding over PKCS#1 v1.5 for RSA.
- Dispose cryptographic objects to zero out secrets.
Clarifying Your Scenario
- Are you encrypting strings in memory, files on disk, or network streams?
- Do you need symmetric, asymmetric, or both?
- Will key management live in code, config, or an external vault?
Beyond Core APIs
Microsoft.AspNetCore.DataProtection simplifies encryption for ASP.NET Core apps.
- Use
Sodium.Core for high-performance encryption.
- Integrate with Azure Key Vault or AWS KMS for managed key storage.
- Use
X509Certificate2 for enterprise scenarios.
- Check FIPS-compliant algorithms for government-grade security.