Previous part: Validations with DataAnnotations and User Creation [GamesCatalog] 19
Step 1. Let's encrypt the password that will be saved in the database. To do this, we will create a class called EncryptionService in the Services project.
![EncryptionService]()
Code
using System.Security.Cryptography;
using System.Text;
namespace Services.Functions;
public interface IEncryptionService
{
string Decrypt(string cipherText);
string Encrypt(string plainText);
}
public class EncryptionService(string Key32, string IV16) : IEncryptionService
{
private readonly byte[] Key = Encoding.UTF8.GetBytes(Key32);
private readonly byte[] IV = Encoding.UTF8.GetBytes(IV16);
public string Encrypt(string plainText)
{
string encrypted = "";
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msEncrypt = new();
using (CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write))
using (StreamWriter swEncrypt = new(csEncrypt))
{
swEncrypt.Write(plainText);
}
encrypted = Convert.ToBase64String(msEncrypt.ToArray());
}
return encrypted;
}
public string Decrypt(string cipherText)
{
try
{
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using Aes aesAlg = Aes.Create();
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using MemoryStream msDecrypt = new(cipherBytes);
using CryptoStream csDecrypt = new(msDecrypt, decryptor, CryptoStreamMode.Read);
using StreamReader srDecrypt = new(csDecrypt);
string plainText = srDecrypt.ReadToEnd();
return plainText;
}
catch (Exception /*ex*/) { throw; }
}
}
Step 2. Right-click on the EncryptionService function and create a test class.
![Solution explorer]()
Code
using Services.Functions;
namespace ServicesTests.Functions;
[TestClass()]
public class EncryptionServiceTests
{
public static EncryptionService BuildEncryptionService()
{
string key32 = "12345678901234567890123456789012";
string IV16 = "1234567890123456";
return new EncryptionService(key32, IV16);
}
[TestMethod()]
public void CompareEncryptionTest()
{
string password = "131313";
var encryptionService = BuildEncryptionService();
string encryptedString = encryptionService.Encrypt(password);
string decryptedString = encryptionService.Decrypt(encryptedString);
Assert.AreEqual(password, decryptedString);
}
[TestMethod()]
public void Compare_Diferent_EncryptionTest()
{
string passworda = "123456";
var encryptionService = BuildEncryptionService();
string encryptedaString = encryptionService.Encrypt(passworda);
string passwordb = "654321";
string encryptedbString = encryptionService.Encrypt(passwordb);
Assert.AreNotEqual(encryptedaString, encryptedbString);
}
[TestMethod()]
public void DecrypTest()
{
string encrypted = "CwY0Vg1K6wNlHSMLMDy2Fw==";
string decrypted = "131313";
var encryptionService = BuildEncryptionService();
string DecryptedString = encryptionService.Decrypt(encrypted);
Assert.AreEqual(DecryptedString, decrypted);
}
[TestMethod()]
public void EncrypTest()
{
string decrypted = "131313";
string encrypted = "CwY0Vg1K6wNlHSMLMDy2Fw==";
var encryptionService = BuildEncryptionService();
string EncryptedString = encryptionService.Encrypt(decrypted);
Assert.AreEqual(EncryptedString, encrypted);
}
}
Step 3. This way, we have an efficient method to confirm that our encryption function works, and we also have a tool to run focused tests on it.
![Methd]()
Step 4. Add your keys to the appsettings.json file.
![Appsetting]()
Step 5. Configure the DI (Dependency Injection) of EncryptionService, passing the two keys.
![DI]()
Step 6. This way, we can use our password encryption function when creating the user.
![User]()
Code for CreateAsync() with password encryption
public async Task<BaseResp> CreateAsync(ReqUser reqUser)
{
string? validateError = reqUser.Validate();
if (!string.IsNullOrEmpty(validateError)) return new BaseResp(null, validateError);
UserDTO user = new()
{
Name = reqUser.Name,
Email = reqUser.Email,
Password = reqUser.Password,
CreatedAt = DateTime.Now
};
string? existingUserMessage = await ValidateExistingUserAsync(user);
if (existingUserMessage != null) { return new BaseResp(null, existingUserMessage); }
if (user.Password != null)
user.Password = encryptionService.Encrypt(user.Password);
else throw new NullReferenceException(nameof(user.Password));
await userRepo.CreateAsync(user);
ResUser? resUser = new()
{
Id = user.Id,
Name = user.Name,
Email = user.Email,
CreatedAt = user.CreatedAt
};
return new BaseResp(resUser);
}
Step 7. So when we create a user, their password will be stored encrypted in the database.
![Stored encrypted]()
![Output]()
In the next step, we will generate a token as a way to authenticate the API user.
Code on git: GamesCatalogBackEnd