using System.Security.Cryptography; using System.Text; using FoodLabeling.Th.Application.Contracts.Options; using Microsoft.Extensions.Options; using Volo.Abp; using Volo.Abp.DependencyInjection; namespace FoodLabeling.Th.Application.MultiTenancy; /// /// 租户下拉默认管理员密码 AES-CBC 加密(随机 IV 作为 passwordSalt 返回前端) /// public class TenantSelectCredentialCipher : ITransientDependency { private readonly byte[] _key; public TenantSelectCredentialCipher(IOptions options) { var secretKey = options.Value.SecretKey?.Trim(); if (string.IsNullOrEmpty(secretKey)) { throw new AbpException("未配置 FoodLabeling:TenantSelectCrypto:SecretKey"); } _key = SHA256.HashData(Encoding.UTF8.GetBytes(secretKey)); } /// /// 加密明文密码,返回 Base64 密文与 Base64 IV(passwordSalt) /// public (string Password, string PasswordSalt) EncryptPassword(string plainPassword) { if (plainPassword is null) { throw new ArgumentNullException(nameof(plainPassword)); } var iv = RandomNumberGenerator.GetBytes(16); using var aes = Aes.Create(); aes.Key = _key; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using var encryptor = aes.CreateEncryptor(); var plainBytes = Encoding.UTF8.GetBytes(plainPassword); var cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); return (Convert.ToBase64String(cipherBytes), Convert.ToBase64String(iv)); } /// /// 解密前端传入的 AES-CBC 密码(Base64 密文 + Base64 IV) /// public string DecryptPassword(string password, string passwordSalt) { if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(passwordSalt)) { throw new UserFriendlyException("密码解密失败"); } try { var cipherBytes = Convert.FromBase64String(password); var iv = Convert.FromBase64String(passwordSalt); using var aes = Aes.Create(); aes.Key = _key; aes.IV = iv; aes.Mode = CipherMode.CBC; aes.Padding = PaddingMode.PKCS7; using var decryptor = aes.CreateDecryptor(); var plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); return Encoding.UTF8.GetString(plainBytes); } catch (Exception ex) when (ex is not UserFriendlyException) { throw new UserFriendlyException("密码解密失败"); } } }