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; } }