using System.Security.Cryptography;
using System.Text;

namespace NPin.Framework.Core.Crypt.DES;

/// <summary>
/// DES加密解密(由于本库对密钥进行了hash算法处理.使用本库加密仅能用本库解密)
/// </summary>
public static class DesCrypt
{
    /// <summary>
    /// 盐
    /// </summary>
    private const string Slat = "Fo~@Ymf3w-!K+hYYoI^emXJeNt79pv@Sy,rpl0vXyIa-^jI{fU";

    /// <summary>
    /// 处理key
    /// </summary>
    /// <param name="pwd">输入的密码</param>
    /// <returns></returns>
    private static Tuple<byte[], byte[]> GetEesKey(string pwd)
    {
        var hash1 = $"{pwd}-{Slat}".Md5();
        var hash2 = $"{hash1}-{Slat}".Md5();
        var hash3 = $"{hash2}-{Slat}".To16Md5();
        var key = Encoding.UTF8.GetBytes($"{hash1}{hash2}".To16Md5()[..8]);
        var iv = Encoding.UTF8.GetBytes(hash3[..8]);
        return new(key, iv);
    }

    /// <summary>
    /// DES加密
    /// </summary>
    /// <param name="content">待加密数据</param>
    /// <param name="pwd">密钥</param>
    /// <param name="mode">加密模式</param>
    /// <param name="padding">填充模式</param>
    /// <returns>加密后的数据</returns>
    public static byte[] Encrypt(byte[] content, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
    {
        var (key, iv) = GetEesKey(pwd);
        
        var des = System.Security.Cryptography.DES.Create();
        des.Key = key;
        des.IV = iv;
        des.Mode = mode;
        des.Padding = padding;
        using var ms = new MemoryStream();
        using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
        cs.Write(content, 0, content.Length);
        cs.FlushFinalBlock();
        return ms.ToArray();
    }

    /// <summary>
    /// DES解密字符串
    /// </summary>
    /// <param name="secret">待解密数据</param>
    /// <param name="pwd">密钥</param>
    /// <param name="mode">加密模式</param>
    /// <param name="padding">填充模式</param>
    /// <returns>解密后的字符串</returns>
    public static byte[] Decrypt(byte[] secret, string pwd, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
    {
        var (key, iv) = GetEesKey(pwd);
        var des = System.Security.Cryptography.DES.Create();
        des.Key = key;
        des.IV = iv;
        des.Mode = mode;
        des.Padding = padding;
        using var ms = new MemoryStream();
        using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
        cs.Write(secret, 0, secret.Length);
        cs.FlushFinalBlock();
        return ms.ToArray();
    }
}