대칭키 암호화 알고리즘으로, 키 값을 가지고 암호화/복호화를 하므로 키 값을 모른다면 데이터를 확인 할 수 없다.
암호화 키는 128, 192, 256 세 가지 중 하나가 될 수 있으며, 각각 AES-128, AES-192, AES-256라고 불린다.
AES 암호화 알고리즘을 사용하기 위해서는 Key 값과 IV 값을 가지고 있어야 한다.
Key : 데이터를 암호화/복호화를 하기 위해 필요한 값 즉, 키 값을 모른다면 데이터를 저장하거나 불러올 수 없다.
IV : 초기화 벡터로, 암호화 과정에서 입력 데이터의 패턴을 깨뜨려 동일한 텍스트가 동일하게 암호화되지 않도록 한다.
C#에서 C# 에서 AES 암호화 알고리즘을 사용하기 위해서는 아래 라이브러리를 사용한다고 선언해야한다.
using System.Security.Cryptography;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Moti_PhysioLicenseManager
{
/// <summary>
/// AES-256 대칭 암·복호화 헬퍼.
/// <para>
/// ⚠️ <strong>주의</strong><br/>
/// 아래 <see cref="ExampleKey"/> / <see cref="ExampleIV"/> 는
/// "예제"용 임시 값입니다. 실제 서비스에선 <c>RandomNumberGenerator</c> 등으로
/// 안전하게 생성한 값을 사용하세요.
/// </para>
/// <example>
/// <code>
/// // ────────────────────────── 예제 사용법 ──────────────────────────
/// using var cryptor = new DataCryptor();
///
/// string plain = "Hello Moti-Physio!";
///
/// // ① 암호화 (문자열 → 바이트)
/// byte[] cipher = cryptor.Encrypt(
/// Encoding.UTF8.GetBytes(plain), // 평문
/// DataCryptor.ExampleKey, // ★ 예제 Key
/// DataCryptor.ExampleIV); // ★ 예제 IV
///
/// // ② (선택) 전송/저장을 위해 Base64 문자열화
/// string cipherText = Convert.ToBase64String(cipher);
///
/// // ③ 복호화
/// byte[] cipherBytes = Convert.FromBase64String(cipherText);
/// string decrypted = Encoding.UTF8.GetString(
/// cryptor.Decrypt(cipherBytes,
/// DataCryptor.ExampleKey,
/// DataCryptor.ExampleIV));
///
/// Console.WriteLine(decrypted); // Hello Moti-Physio!
/// // ────────────────────────────────────────────────────────────────
/// </code>
/// </example>
/// </summary>
public sealed class DataCryptor : IDisposable
{
#region 🔑 예제 Key / IV (절대로 실서비스에 쓰지 마세요!)
/// <summary>32 바이트 AES-256 키 (0x00~0x1F 순차값)</summary>
public static readonly byte[] ExampleKey =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
};
/// <summary>16 바이트 IV (0xA0~0xAF 순차값)</summary>
public static readonly byte[] ExampleIV =
{
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF
};
#endregion
private readonly Aes _aes = Aes.Create();
private bool _disposed;
#region Encrypt
/// <summary>
/// UTF-8 문자열을 받아 암호 바이트 배열을 반환합니다.
/// </summary>
public byte[] Encrypt(string plainText, byte[] key, byte[] iv) =>
Encrypt(Encoding.UTF8.GetBytes(plainText), key, iv);
/// <summary>
/// 바이트 배열을 암호화합니다.
/// </summary>
public byte[] Encrypt(byte[] plain, byte[] key, byte[] iv)
{
if (plain is null || plain.Length == 0)
throw new ArgumentException(nameof(plain));
InitKeyIv(key, iv);
using MemoryStream ms = new();
using CryptoStream cs = new(ms, _aes.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(plain, 0, plain.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
#endregion
#region Decrypt
/// <summary>
/// Base64 문자열을 복호화해 UTF-8 문자열로 돌려줍니다.
/// </summary>
public string Decrypt(string base64CipherText, byte[] key, byte[] iv)
{
byte[] cipher = Convert.FromBase64String(base64CipherText);
return Encoding.UTF8.GetString(Decrypt(cipher, key, iv));
}
/// <summary>
/// 암호 바이트 배열을 복호화해 평문 바이트를 반환합니다.
/// </summary>
public byte[] Decrypt(byte[] cipher, byte[] key, byte[] iv)
{
if (cipher is null || cipher.Length == 0)
throw new ArgumentException(nameof(cipher));
InitKeyIv(key, iv);
using MemoryStream ms = new(cipher);
using CryptoStream cs = new(ms, _aes.CreateDecryptor(), CryptoStreamMode.Read);
using MemoryStream plain = new();
cs.CopyTo(plain);
return plain.ToArray();
}
#endregion
#region Helpers / Dispose
private void InitKeyIv(byte[] key, byte[] iv)
{
_aes.Key = (key is { Length: > 0 }) ? key : ExampleKey;
_aes.IV = (iv is { Length: > 0 }) ? iv : ExampleIV;
}
/// <inheritdoc/>
public void Dispose()
{
if (_disposed) return;
_aes.Dispose();
_disposed = true;
}
#endregion
}
}