Files
Akari.Prototype/Akari.Prototype.Server/Services/KeyManager.cs
Eveldee a3349e23c9 Fix IKeyManager
Now correctly delete key folder while avoiding issues
2021-06-07 16:12:20 +02:00

126 lines
4.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Akari.Prototype.Server.Models;
using Akari.Prototype.Server.Utils;
using Microsoft.Extensions.Logging;
namespace Akari.Prototype.Server.Services
{
public sealed class KeyManager : IKeyManager
{
public const string KeysPath = "Keys";
public const int KeyLength = 256 / 8;
private readonly ILogger<KeyManager> _logger;
private readonly IMasterKeyService _masterKeyService;
private readonly AkariPath _akariPath;
public KeyManager(ILogger<KeyManager> logger, IMasterKeyService masterKeyService, AkariPath akariPath)
{
_logger = logger;
_masterKeyService = masterKeyService;
_akariPath = akariPath;
CheckConfig();
}
private void CheckConfig()
{
string path = _akariPath.GetPath(KeysPath);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
public bool AddFingerprint(string applicationName, string fingerprintName, AesGcm fingerprintKey)
{
if (!Directory.Exists(GetKeyDirectoryPath(applicationName)) || !_masterKeyService.TryGetKey(out var masterKey))
{
return false;
}
// Read key
var encryptedKeyBytes = File.ReadAllBytes(GetMasterKeyPath(applicationName));
var decryptedKeyBytes = Security.AesGcmDecrypt(masterKey, encryptedKeyBytes);
var newEncryptedKeyBytes = Security.AesGcmEncrypt(fingerprintKey, decryptedKeyBytes);
File.WriteAllBytes(GetKeyPath(applicationName, fingerprintName), newEncryptedKeyBytes);
_logger.LogDebug($"Fingerprint '{fingerprintName}' added for {applicationName}");
return true;
}
public void Clear(Application application)
{
// Do it safely to avoid deleting unwanted files
File.Delete(GetMasterKeyPath(application.Name));
foreach (var fingerprint in application.Fingerprints)
{
File.Delete(GetKeyPath(application.Name, fingerprint));
}
Directory.Delete(GetKeyDirectoryPath(application.Name), recursive: false);
_logger.LogDebug($"Deleted keys for {application.Name}");
}
public bool Create(string applicationName)
{
if (!_masterKeyService.TryGetKey(out var masterKey))
{
_logger.LogDebug("Can't create key if master not logged in");
return false;
}
Directory.CreateDirectory(GetKeyDirectoryPath(applicationName));
Span<byte> keyBytes = KeyLength <= 1024 ? stackalloc byte[KeyLength]
: new byte[KeyLength];
RandomNumberGenerator.Fill(keyBytes);
var encryptedKeyBytes = Security.AesGcmEncrypt(masterKey, keyBytes);
File.WriteAllBytes(GetMasterKeyPath(applicationName), encryptedKeyBytes);
_logger.LogDebug($"Key created for {applicationName}");
return true;
}
public AesGcm RetrieveKey(string applicationName, string fingerprintName, AesGcm fingerprintKey)
{
if (!Directory.Exists(GetKeyDirectoryPath(applicationName)))
{
throw new IOException($"Can't find key files for {applicationName}");
}
// Read key
var encryptedKeyBytes = File.ReadAllBytes(GetKeyPath(applicationName, fingerprintName));
var decryptedKeyBytes = Security.AesGcmDecrypt(fingerprintKey, encryptedKeyBytes);
_logger.LogDebug($"Key retrieved for {applicationName} using {fingerprintName}");
return new AesGcm(decryptedKeyBytes);
}
private string GetKeyDirectoryPath(string applicationName) => Path.Combine(_akariPath.GetPath(KeysPath), applicationName);
private string GetMasterKeyPath(string applicationName) => Path.Combine(GetKeyDirectoryPath(applicationName), "key");
private string GetKeyPath(string applicationName, string fingerprintName) => $"{GetMasterKeyPath(applicationName)}-{fingerprintName}";
}
}