닷넷관련/ASP.NET CORE 🍔

ASP.NET CORE : 대칭 암호화 알고리즘 AES-256(Advanced Encryption Standard) 구현하기 (Aes Class)

재우니 2024. 8. 6. 11:22

 

 

📌 암호화 기술 개요


제공된 코드에 사용된 암호화 기술은 보안과 효율성으로 널리 알려진 대칭 암호화 알고리즘 AES(Advanced Encryption Standard)를 기반으로 합니다.

📌  주요 개념:


대칭 암호화:

대칭 암호화는 암호화와 복호화에 동일한 키를 사용합니다.
AES는 대칭 암호화 알고리즘입니다. 즉, 데이터 암호화 및 복호화에 동일한 KEY와 초기화 벡터(IV)가 사용됩니다.

 


📌  AES(고급 암호화 표준):

AES는 2001년 미국 국립표준기술연구소(NIST)에 의해 설립되었습니다.
128, 192, 256비트의 키 크기를 지원합니다. 제공된 코드는 128비트 키를 활용하는 AES-128을 사용합니다.
AES는 128비트의 고정 블록 크기에서 작동합니다.


📌  KEY 및 초기화 벡터(IV):

KEY 는 데이터를 암호화하고 복호화하는 데 사용됩니다. 제공된 코드에서는 주어진 12자 키를 채워서 키가 128비트로 확장됩니다.
IV는 동일한 평문이 다른 암호문으로 암호화되도록 보장하여 패턴 분석 공격을 방지하는 데 사용됩니다. 마찬가지로 IV는 128비트로 채워집니다.


📌  CBC(암호 블록 체인) 모드:

코드는 CBC 모드에서 AES를 사용합니다. 여기서 일반 텍스트의 각 블록은 암호화되기 전에 이전 암호 텍스트 블록과 XOR됩니다. 이렇게 하면 동일한 일반 텍스트 블록이 다른 암호문 블록으로 암호화됩니다.
첫 번째 블록을 암호화하려면 IV가 필요합니다.


📌  Base64 인코딩:

암호화된 바이트는 쉽게 전송하고 저장할 수 있도록 Base64 문자열로 변환됩니다. 이 인코딩은 이진 데이터를 텍스트 문자열로 변환하여 텍스트 데이터 형식에 적합하게 만듭니다.

 

 

 

제공된 코드의 프로세스 요약:

 

📌  암호화:

일반 텍스트를 바이트로 변환합니다.
지정된 키와 IV를 사용하여 AES 알고리즘 인스턴스를 만듭니다.
AES 암호화기를 사용하여 일반 텍스트 바이트를 암호화합니다.
암호화된 바이트를 출력을 위해 Base64 문자열로 변환합니다.


📌  암호해독:

Base64로 인코딩된 문자열을 다시 바이트로 변환합니다.
암호화에 사용된 것과 동일한 키와 IV를 사용하여 AES 알고리즘 인스턴스를 생성합니다.
AES 해독기를 사용하여 암호화된 바이트를 해독합니다.
해독된 바이트를 출력용 일반 텍스트 문자열로 다시 변환합니다.


📌  실제 구현:


아래 코드는 ASP.NET Core 애플리케이션에서 'AesEncryptionService' 클래스를 생성하고 암호화 및 암호 해독 논리를 캡슐화하는 방법을 보여줍니다. 이 서비스를 컨트롤러에 INJECT 하여 민감한 데이터를 안전하게 처리할 수 있습니다. 제공된 방법은 null 또는 빈 입력 값이 적절하게 관리되어 암호화 및 암호 해독 프로세스 중에 오류가 발생하지 않도록 합니다.

 

코드 설명

 

AesEncryptionService.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace AesEncryptionExample.Services
{
    public class AesEncryptionService
    {
        private readonly byte[] Key;
        private readonly byte[] IV;

        public AesEncryptionService(string key, string iv)
        {
            if (key.Length != 12 || iv.Length != 12)
                throw new ArgumentException("Key and IV must be 12 characters long.");

            Key = Encoding.UTF8.GetBytes(key.PadRight(16)); // 128-bit 키로 맞추기 위해 패딩 추가
            IV = Encoding.UTF8.GetBytes(iv.PadRight(16));  // 128-bit IV로 맞추기 위해 패딩 추가
        }

        public string EncryptString(string plainText)
        {
            if (plainText == null)
                plainText = "";

            byte[] encrypted;

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            return Convert.ToBase64String(encrypted);
        }

        public string DecryptString(string encryptedText)
        {
            if (string.IsNullOrEmpty(encryptedText))
                return "";

            byte[] cipherText = Convert.FromBase64String(encryptedText);
            string plaintext = null;

            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = Key;
                aesAlg.IV = IV;

                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }

            return plaintext ?? "";
        }
    }
}

 

 

EncryptionController.cs

 

using Microsoft.AspNetCore.Mvc;
using AesEncryptionExample.Services;

namespace AesEncryptionExample.Controllers
{
    public class EncryptionController : Controller
    {
        private readonly AesEncryptionService _aesEncryptionService;

        public EncryptionController(AesEncryptionService aesEncryptionService)
        {
            _aesEncryptionService = aesEncryptionService;
        }

        [HttpGet]
        public IActionResult Encrypt(string text)
        {
            if (text == null)
            {
                return BadRequest("Text cannot be null");
            }

            var encryptedText = _aesEncryptionService.EncryptString(text);

            return Ok(encryptedText);
        }

        [HttpGet]
        public IActionResult Decrypt(string encryptedText)
        {
            if (string.IsNullOrEmpty(encryptedText))
            {
                return BadRequest("Encrypted text cannot be null or empty");
            }

            var decryptedText = _aesEncryptionService.DecryptString(encryptedText);

            return Ok(decryptedText);
        }
    }
}

 

 

 

Program.cs (for .NET 6 and later)

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AesEncryptionExample.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

// Register AesEncryptionService with appropriate key and IV
builder.Services.AddSingleton(new AesEncryptionService("your-key-123", "your-iv-123"));

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

 

 

 

실행화면

curl "https://localhost:5001/Encryption/Encrypt?text=HelloWorld"

// "Encrypted: 3q2+7w=="

 

curl "https://localhost:5001/Encryption/Decrypt?encryptedText=3q2+7w=="

// "Decrypted: HelloWorld"