namespace Application.Abstractions.Crypto; /// /// Config 문자열 컬럼에 키 버전을 함께 담아 암호화 저장하는 헬퍼. /// 별도 KeyVersion 컬럼이 없는 Config 특성상 "enc:v{version}:{Base64}" 자체 포맷을 사용한다. /// 접두사가 없는 값은 레거시 평문으로 간주해 그대로 반환한다 (하위호환). /// public static class EncryptedConfigValue { private const string Prefix = "enc:v"; /// 평문을 현재 키 버전으로 암호화해 버전 접두사 포맷으로 반환 public static string Protect(IFieldEncryptor encryptor, string plaintext) { ArgumentNullException.ThrowIfNull(encryptor); return $"{Prefix}{encryptor.CurrentKeyVersion}:{encryptor.Encrypt(plaintext)}"; } /// 버전 접두사 포맷 여부 public static bool IsProtected(string? value) { return value is not null && value.StartsWith(Prefix, StringComparison.Ordinal); } /// 버전 접두사 포맷이면 복호화, 아니면(레거시 평문) 그대로 반환 public static string Unprotect(IFieldEncryptor encryptor, string value) { ArgumentNullException.ThrowIfNull(encryptor); ArgumentNullException.ThrowIfNull(value); if (!IsProtected(value)) { return value; } var rest = value.AsSpan(Prefix.Length); var separator = rest.IndexOf(':'); if (separator <= 0 || !int.TryParse(rest[..separator], out var version)) { throw new InvalidOperationException("암호화된 설정 값의 키 버전 형식이 올바르지 않습니다."); } return encryptor.Decrypt(rest[(separator + 1)..].ToString(), version); } }