Code
·
62 lines
·
1885 bytes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62using System.Security.Cryptography;
namespace MailSharp.MailClient.Services;
public interface IPasswordProtector
{
string Protect(string plainText);
string Unprotect(string protectedText);
}
// AES-GCM encryption using a key material file kept outside wwwroot.
// Not a substitute for a real secrets manager, but avoids storing plaintext passwords in LiteDB.
public class AesPasswordProtector : IPasswordProtector
{
private readonly byte[] _key;
public AesPasswordProtector(IWebHostEnvironment env)
{
var keyPath = Path.Combine(env.ContentRootPath, "App_Data", "protect.key");
Directory.CreateDirectory(Path.GetDirectoryName(keyPath)!);
if (File.Exists(keyPath))
{
_key = Convert.FromBase64String(File.ReadAllText(keyPath));
}
else
{
_key = RandomNumberGenerator.GetBytes(32);
File.WriteAllText(keyPath, Convert.ToBase64String(_key));
}
}
public string Protect(string plainText)
{
var nonce = RandomNumberGenerator.GetBytes(12);
var plainBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
var cipher = new byte[plainBytes.Length];
var tag = new byte[16];
using (var aes = new AesGcm(_key, 16))
{
aes.Encrypt(nonce, plainBytes, cipher, tag);
}
var result = new byte[nonce.Length + tag.Length + cipher.Length];
Buffer.BlockCopy(nonce, 0, result, 0, nonce.Length);
Buffer.BlockCopy(tag, 0, result, nonce.Length, tag.Length);
Buffer.BlockCopy(cipher, 0, result, nonce.Length + tag.Length, cipher.Length);
return Convert.ToBase64String(result);
}
public string Unprotect(string protectedText)
{
var data = Convert.FromBase64String(protectedText);
var nonce = data[..12];
var tag = data[12..28];
var cipher = data[28..];
var plain = new byte[cipher.Length];
using (var aes = new AesGcm(_key, 16))
{
aes.Decrypt(nonce, cipher, tag, plain);
}
return System.Text.Encoding.UTF8.GetString(plain);
}
}