Files
hrynco-common/HrynCo.Common/Security/SecretProtector.cs
T
Anatolii Grynchuk 85b362e8cd chore: add hrynco common library solution
- add the standalone HrynCo.Common solution and projects
- include the shared common library source and tests
- add package metadata and a repo gitignore
2026-05-01 00:17:34 +03:00

62 lines
2.0 KiB
C#

namespace HrynCo.Common.Security;
using System;
using System.Security.Cryptography;
using System.Text;
public sealed class SecretProtector : ISecretProtector
{
private readonly byte[] _key;
public SecretProtector(string encryptionKey)
{
if (string.IsNullOrWhiteSpace(encryptionKey))
{
throw new InvalidOperationException("Secret encryption key is not configured.");
}
_key = Convert.FromBase64String(encryptionKey);
if (_key.Length != 32)
{
throw new InvalidOperationException("Secret encryption key must be 32 bytes encoded as Base64.");
}
}
public string Protect(string plaintext)
{
byte[] nonce = RandomNumberGenerator.GetBytes(12);
byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
byte[] ciphertext = new byte[plaintextBytes.Length];
byte[] tag = new byte[16];
using var aes = new AesGcm(_key, tagSizeInBytes: 16);
aes.Encrypt(nonce, plaintextBytes, ciphertext, tag);
byte[] payload = new byte[nonce.Length + tag.Length + ciphertext.Length];
Buffer.BlockCopy(nonce, 0, payload, 0, nonce.Length);
Buffer.BlockCopy(tag, 0, payload, nonce.Length, tag.Length);
Buffer.BlockCopy(ciphertext, 0, payload, nonce.Length + tag.Length, ciphertext.Length);
return $"v1:{Convert.ToBase64String(payload)}";
}
public string Unprotect(string protectedValue)
{
if (!protectedValue.StartsWith("v1:", StringComparison.Ordinal))
{
throw new InvalidOperationException("Unsupported protected value format.");
}
byte[] payload = Convert.FromBase64String(protectedValue[3..]);
byte[] nonce = payload[..12];
byte[] tag = payload[12..28];
byte[] ciphertext = payload[28..];
byte[] plaintext = new byte[ciphertext.Length];
using var aes = new AesGcm(_key, tagSizeInBytes: 16);
aes.Decrypt(nonce, ciphertext, tag, plaintext);
return Encoding.UTF8.GetString(plaintext);
}
}