EF core 에서 column encryption 하기

2023. 9. 25. 00:00EntityFramewok Core (EF Core)

반응형

요즘 같은 경우는 개인정보 보호로 인해 사용자 정보를 db 에 저장할 경우 

해당 data 를 encryption 해야 하는 경우가 많다. 

이번시간에는 ef core 에서 특정 column 을 encryption , decryption 하는 방법을 알아보자

 

기존에 사용했던 API Server 를 이용하겠다. 

https://yogingang.tistory.com/404

 

Rest API Template 만들기 - EP 01 (Create , Swagger, Logging)

Create visual studio 2022 를 실행하고 Create a new project 를 선택한다. asp.net core web api 선택 Project name 정하기 Additional Information 설정 Create 하면 Project 가 생성된다. F5 를 누르면 실행 된다. 위와 같이 swagger

yogingang.tistory.com

해당 강좌의 마지막까지 따라가면 api template 가 하나 만들어 질거고 그것을 이용할 것이다. 

조금씩 다를 수 있지만 크게 다르지 않다. 

강좌에서 사용하는 api server 는 ep 10 이후 encryption decryption  까지 적용된 버전이다.

 

이버전에서 특정 db 의 column 을 암호화 할 것이다. 

 

BaseDbContext.cs

...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Encryption>()
        .HasData(new Encryption
        {
            Id = "AesInfo",
            Key = "이게 32bytes 가 될때까지 이것 $%^&* 저것 넣어라 넘어도 된다. 알아서 자를거니까"u8.ToArray(),
            IV = "이건 16bytes가 되어야 할꺼라고 南李事Encryption"u8.ToArray(),
        });


    modelBuilder.Entity<User>()
        .Property(e => e.Name)
        .HasConversion(
            encryptedValue => AesHelper.EncryptString(encryptedValue),
            decryptedValue => AesHelper.DecryptString(decryptedValue)
        );

    base.OnModelCreating(modelBuilder);
}
...

AESHelper.cs

public class AesHelper
{
    public static byte[] Key { get; set; }
    public static byte[] IV { get; set; }

    public static string EncryptString(string plainText)
    {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");
        byte[] encrypted;

        // Create an Aes object
        // with the specified key and IV.
        using (Aes aesAlg = Aes.Create())
        {
            var pdb = new Rfc2898DeriveBytes(Key, IV, 1000, HashAlgorithmName.SHA512);
            aesAlg.Key = pdb.GetBytes(32);
            aesAlg.IV = pdb.GetBytes(16);

            // Create an encryptor to perform the stream transform.
            ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }

        // Return the encrypted bytes from the memory stream.
        //return encrypted;

        return Convert.ToBase64String(encrypted);
    }

    public static string DecryptString(string cipherText)
    {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("IV");

        // Declare the string used to hold
        // the decrypted text.
        string plaintext;

        // Create an Aes object
        // with the specified key and IV.
        using var aesAlg = Aes.Create();

        var pdb = new Rfc2898DeriveBytes(Key, IV, 1000, HashAlgorithmName.SHA512);
        aesAlg.Key = pdb.GetBytes(32);
        aesAlg.IV = pdb.GetBytes(16);

        // Create a decryptor to perform the stream transform.
        ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

        // Create the streams used for decryption.
        using (var msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
        {
            using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (var srDecrypt = new StreamReader(csDecrypt))
                {
                    // Read the decrypted bytes from the decrypting stream
                    // and place them in a string.
                    plaintext =  srDecrypt.ReadToEnd();
                }
            }
        }

        return plaintext;
    }
}

AbstractBaseHandler.cs

public abstract class AbstractBaseHandler
{
    protected readonly BaseDbContext _context;
    protected readonly IConfiguration _configuration;
    protected readonly IApiLogger _apiLogger;

    public AbstractBaseHandler(BaseDbContext context, IConfiguration configuration, IApiLogger apiLogger)
    {
        _context = context;
        _configuration = configuration;
        _apiLogger = apiLogger;
        if (AesHelper.Key != null && AesHelper.IV != null) return;
        var encryption = _context.Encryptions.SingleOrDefault(e => e.Id == "AesInfo");
        if (encryption != null)
        {
            AesHelper.Key = encryption.Key;
            AesHelper.IV = encryption.IV;
        }
    }
...
}

AesHelper.Key 와 IV 를 설정한다. (초기화)

이제 migration and update 이 후  User.Name 이 암호화 되어 Db 에 저장되어 진걸 확인할 수 있다. 

 

 

관련영상

https://youtu.be/nlWisDMnooU

 

반응형