using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using CellularManagement.Application.Services;
using CellularManagement.Infrastructure.Options;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
namespace CellularManagement.Infrastructure.Services;
///
/// 密钥轮换服务实现
///
public sealed class KeyRotationService : IKeyRotationService
{
private readonly JwtOptions _jwtOptions;
private readonly ILogger _logger;
private string _currentKey;
private string _nextKey;
private DateTime _lastRotationTime;
///
/// 构造函数
///
public KeyRotationService(IOptions jwtOptions, ILogger logger)
{
_jwtOptions = jwtOptions.Value;
_logger = logger;
_currentKey = _jwtOptions.SecretKey;
_nextKey = GenerateNewKey();
_lastRotationTime = DateTime.UtcNow;
}
///
public async Task InitializeAsync()
{
try
{
// 验证当前密钥强度
ValidateKeyStrength(_currentKey);
// 如果当前密钥即将过期,立即轮换
if (ShouldRotateKey())
{
await RotateKeyAsync();
}
_logger.LogInformation("密钥轮换服务初始化完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "密钥轮换服务初始化失败");
throw;
}
}
///
public string GetCurrentKey()
{
return _currentKey;
}
///
public string GetNextKey()
{
return _nextKey;
}
///
public async Task RotateKeyAsync()
{
try
{
// 验证新密钥强度
ValidateKeyStrength(_nextKey);
// 更新密钥
_currentKey = _nextKey;
_nextKey = GenerateNewKey();
_lastRotationTime = DateTime.UtcNow;
// 更新配置
_jwtOptions.SecretKey = _currentKey;
await Task.CompletedTask;
_logger.LogInformation("密钥轮换完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "密钥轮换失败");
throw;
}
}
///
public bool ShouldRotateKey()
{
var timeSinceLastRotation = DateTime.UtcNow - _lastRotationTime;
return timeSinceLastRotation.TotalDays >= _jwtOptions.KeyRotationDays;
}
///
/// 生成新的密钥
///
private string GenerateNewKey()
{
using var rng = RandomNumberGenerator.Create();
var keyBytes = new byte[_jwtOptions.MinKeyLength];
rng.GetBytes(keyBytes);
return Convert.ToBase64String(keyBytes);
}
///
/// 验证密钥强度
///
private void ValidateKeyStrength(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("密钥不能为空");
}
if (key.Length < _jwtOptions.MinKeyLength)
{
throw new ArgumentException($"密钥长度必须至少为 {_jwtOptions.MinKeyLength} 字节");
}
// 检查密钥是否包含足够的随机性
var entropy = CalculateEntropy(key);
if (entropy < 3.5) // 3.5 bits per character is considered good
{
throw new ArgumentException("密钥随机性不足");
}
}
///
/// 计算字符串的熵
///
private static double CalculateEntropy(string input)
{
var frequencies = new Dictionary();
foreach (var c in input)
{
if (frequencies.ContainsKey(c))
{
frequencies[c]++;
}
else
{
frequencies[c] = 1;
}
}
var length = input.Length;
var entropy = 0.0;
foreach (var frequency in frequencies.Values)
{
var probability = (double)frequency / length;
entropy -= probability * Math.Log2(probability);
}
return entropy;
}
}