Initial commit to new repository
This commit is contained in:
85
src/AxKeyEncryptor/CryptoHelper.cs
Normal file
85
src/AxKeyEncryptor/CryptoHelper.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace AxKeyEncryptor;
|
||||
|
||||
/// <summary>
|
||||
/// 앱 공용 키(Portable) 암호화/복호화 — CryptoService.cs와 동일한 로직.
|
||||
/// </summary>
|
||||
internal static class CryptoHelper
|
||||
{
|
||||
private static readonly byte[] AppSeed =
|
||||
{
|
||||
// "AX-Commander-Key-0104-sj.baeck" + 2-byte pad
|
||||
0x41, 0x58, 0x2D, 0x43, 0x6F, 0x6D, 0x6D, 0x61,
|
||||
0x6E, 0x64, 0x65, 0x72, 0x2D, 0x4B, 0x65, 0x79,
|
||||
0x2D, 0x30, 0x31, 0x30, 0x34, 0x2D, 0x73, 0x6A,
|
||||
0x2E, 0x62, 0x61, 0x65, 0x63, 0x6B, 0xA7, 0x5C
|
||||
};
|
||||
|
||||
private static readonly byte[] AppSalt =
|
||||
{
|
||||
0x58, 0x43, 0x4D, 0x44, 0x53, 0x61, 0x6C, 0x74,
|
||||
0x9E, 0x27, 0xC1, 0x4A, 0xB3, 0x06, 0x7F, 0xD8
|
||||
};
|
||||
|
||||
private static byte[]? _appKey;
|
||||
|
||||
private static byte[] GetAppKey()
|
||||
{
|
||||
if (_appKey != null) return _appKey;
|
||||
using var pbkdf2 = new Rfc2898DeriveBytes(AppSeed, AppSalt, 100_000, HashAlgorithmName.SHA256);
|
||||
_appKey = pbkdf2.GetBytes(32);
|
||||
return _appKey;
|
||||
}
|
||||
|
||||
public static string Encrypt(string plainText)
|
||||
{
|
||||
if (string.IsNullOrEmpty(plainText)) return "";
|
||||
var key = GetAppKey();
|
||||
using var aes = Aes.Create();
|
||||
aes.Key = key;
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.GenerateIV();
|
||||
|
||||
using var enc = aes.CreateEncryptor();
|
||||
var plainBytes = Encoding.UTF8.GetBytes(plainText);
|
||||
var cipher = enc.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
|
||||
|
||||
var result = new byte[16 + cipher.Length];
|
||||
Buffer.BlockCopy(aes.IV, 0, result, 0, 16);
|
||||
Buffer.BlockCopy(cipher, 0, result, 16, cipher.Length);
|
||||
return Convert.ToBase64String(result);
|
||||
}
|
||||
|
||||
public static (bool Success, string Result) Decrypt(string base64)
|
||||
{
|
||||
if (string.IsNullOrEmpty(base64)) return (false, "입력이 비어 있습니다.");
|
||||
try
|
||||
{
|
||||
var raw = Convert.FromBase64String(base64);
|
||||
if (raw.Length < 17) return (false, "데이터가 너무 짧습니다.");
|
||||
|
||||
var key = GetAppKey();
|
||||
var iv = new byte[16];
|
||||
Buffer.BlockCopy(raw, 0, iv, 0, 16);
|
||||
var cipher = new byte[raw.Length - 16];
|
||||
Buffer.BlockCopy(raw, 16, cipher, 0, cipher.Length);
|
||||
|
||||
using var aes = Aes.Create();
|
||||
aes.Key = key;
|
||||
aes.IV = iv;
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
|
||||
using var dec = aes.CreateDecryptor();
|
||||
var plain = dec.TransformFinalBlock(cipher, 0, cipher.Length);
|
||||
return (true, Encoding.UTF8.GetString(plain));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, $"복호화 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user