닷넷관련/ASP.NET CORE 🍔
ASP.NET CORE : 대칭 암호화 알고리즘 AES-256 시나리오 2가지로 구현하기
재우니
2024. 8. 6. 11:58
ASP.NET CORE : 대칭 암호화 알고리즘 AES-256 (Advanced Encryption Standard) 구현하기 (Aes Class)
https://aspdotnet.tistory.com/3242
ASP.NET CORE : 대칭 암호화 알고리즘 AES 시나리오 2가지로 구현하기
전체적인 코드는 MSSQL 데이터베이스와 Dapper를 사용하여 데이터를 암호화하고 저장한 후, 복호화하여 반환하는 기능을 포함하고 있습니다. 아래에 제시된 단계를 따라 실제로 코드를 실행하고 결과를 확인할 수 있습니다.
📌 암호화 서비스 및 컨트롤러 코드: 두 가지 케이스에 맞게 재구성
- 문자열을 받아서 문자열로 암호화하고, 암호화된 문자열을 문자열로 복호화
- 문자열을 받아서 바이트 배열로 변환하여 암호화하고, 바이트 배열로 복호화한 후 문자열로 변환하여 반환
1. 데이터베이스 설정
SQL Server에 EncryptedData 테이블을 생성합니다:
CREATE TABLE EncryptedData (
Id INT PRIMARY KEY IDENTITY(1,1),
EncryptedValue VARBINARY(MAX) NOT NULL
);
2. 모델 클래스 생성
EncryptedData 모델 클래스를 생성합니다:
public class EncryptedData
{
public int Id { get; set; }
public byte[] EncryptedValue { get; set; }
}
3. AES 암호화 서비스 클래스 생성
AesEncryptionService 클래스를 생성합니다:
256비트 키와 128비트 초기화 벡터를 사용하는 AES-256 암호화를 사용합니다. 이 구성은 다양한 암호화 요구 사항에 적합한 높은 수준의 보안을 보장합니다.
AES-256:
- 키: 32바이트(256비트)
- IV: 16바이트(128비트)
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(byte[] key, byte[] iv)
{
if (key == null || key.Length != 32)
throw new ArgumentException("Key must be 32 bytes long.");
if (iv == null || iv.Length != 16)
throw new ArgumentException("IV must be 16 bytes long.");
Key = key;
IV = iv;
}
public byte[] EncryptStringToBytes(string plainText)
{
if (plainText == null)
throw new ArgumentNullException(nameof(plainText));
byte[] plainBytes = Encoding.UTF8.GetBytes(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))
{
csEncrypt.Write(plainBytes, 0, plainBytes.Length);
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
}
}
}
return encrypted;
}
public string DecryptBytesToString(byte[] cipherBytes)
{
if (cipherBytes == null || cipherBytes.Length <= 0)
throw new ArgumentNullException(nameof(cipherBytes));
byte[] plainBytes;
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(cipherBytes))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (MemoryStream msPlain = new MemoryStream())
{
csDecrypt.CopyTo(msPlain);
plainBytes = msPlain.ToArray();
}
}
}
}
plaintext = Encoding.UTF8.GetString(plainBytes);
return plaintext;
}
}
}
4. 컨트롤러 클래스 생성
EncryptionController 클래스를 생성합니다:
using Microsoft.AspNetCore.Mvc;
using AesEncryptionExample.Services;
using System.Data.SqlClient;
using System.Threading.Tasks;
using Dapper;
namespace AesEncryptionExample.Controllers
{
public class EncryptionController : Controller
{
private readonly AesEncryptionService _aesEncryptionService;
private readonly string _connectionString;
public EncryptionController(AesEncryptionService aesEncryptionService)
{
_aesEncryptionService = aesEncryptionService;
_connectionString = "YourConnectionString"; // 실제 연결 문자열로 대체
}
[HttpPost]
public async Task<IActionResult> Encrypt([FromBody] string text)
{
if (string.IsNullOrEmpty(text))
{
return BadRequest("Text cannot be null or empty");
}
var encryptedBytes = _aesEncryptionService.EncryptStringToBytes(text);
var encryptedData = new EncryptedData
{
EncryptedValue = encryptedBytes
};
using (var connection = new SqlConnection(_connectionString))
{
var sql = "INSERT INTO EncryptedData (EncryptedValue) VALUES (@EncryptedValue); SELECT CAST(SCOPE_IDENTITY() as int)";
var id = await connection.QuerySingleAsync<int>(sql, new { EncryptedValue = encryptedData.EncryptedValue });
encryptedData.Id = id;
}
return Ok(Convert.ToBase64String(encryptedBytes));
}
[HttpGet("{id}")]
public async Task<IActionResult> Decrypt(int id)
{
EncryptedData encryptedData;
using (var connection = new SqlConnection(_connectionString))
{
var sql = "SELECT * FROM EncryptedData WHERE Id = @Id";
encryptedData = await connection.QuerySingleOrDefaultAsync<EncryptedData>(sql, new { Id = id });
}
if (encryptedData == null)
{
return NotFound();
}
var decryptedText = _aesEncryptionService.DecryptBytesToString(encryptedData.EncryptedValue);
return Ok(decryptedText);
}
[HttpPost("EncryptBytes")]
public IActionResult EncryptBytes([FromBody] string text)
{
if (string.IsNullOrEmpty(text))
{
return BadRequest("Text cannot be null or empty");
}
var encryptedBytes = _aesEncryptionService.EncryptStringToBytes(text);
return Ok(encryptedBytes);
}
[HttpPost("DecryptBytes")]
public IActionResult DecryptBytes([FromBody] byte[] encryptedBytes)
{
if (encryptedBytes == null || encryptedBytes.Length == 0)
{
return BadRequest("Encrypted bytes cannot be null or empty");
}
var decryptedText = _aesEncryptionService.DecryptBytesToString(encryptedBytes);
return Ok(decryptedText);
}
}
}
5. Program.cs 설정
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
byte[] key = { 0x14, 0x22, 0x03, 0x05, 0x20, 0x89, 0x64, 0x1A, 0x29, 0x33,
0xAA, 0x97, 0x23, 0x33, 0x35, 0x58, 0x28, 0x9E, 0x70, 0x53,
0x3D, 0x02, 0x43, 0x3C, 0x1E, 0xC1, 0x82, 0xB5, 0x2C, 0x1F,
0x1F, 0x5B };
byte[] iv = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
builder.Services.AddSingleton(new AesEncryptionService(key, iv));
var app = builder.Build();
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();
테스트 실행
위의 코드를 설정한 후, Postman 또는 다른 HTTP 클라이언트를 사용하여 다음과 같은 요청을 보낼 수 있습니다:
암호화
- POST 요청: https://localhost:5001/Encryption/Encrypt
- 요청 본문: { "text": "Nice to meet you." }
- 응답 예시 (Base64로 인코딩된 암호화된 문자열): "QWJjMTIzIT8kKiYoKSctPUB+"
복호화
- GET 요청: https://localhost:5001/Encryption/Decrypt/{id}
- URL에서 {id}를 암호화된 데이터의 ID로 대체 : "Nice to meet you."
요약
- 데이터베이스 설정: EncryptedData 테이블을 생성합니다.
- AES 암호화 서비스: 문자열을 암호화하고 복호화하는 서비스를 구현합니다.
- Dapper를 사용한 컨트롤러: 암호화된 데이터를 저장하고 조회하여 복호화 합니다.