解决MySql布尔型新旧版本兼容问题,采用枚举来表示布尔型的数据表。由正向工程赋值
大石头 authored at 2018-05-15 21:21:05
5.49 KiB
X
using System.Security.Cryptography;
using System.Xml;

namespace NewLife.Security;

/// <summary>DSA算法</summary>
public static class DSAHelper
{
    #region 产生密钥
    /// <summary>产生非对称密钥对(私钥和公钥)</summary>
    /// <param name="keySize">密钥长度,默认1024位强密钥</param>
    /// <returns>私钥和公钥</returns>
    public static String[] GenerateKey(Int32 keySize = 1024)
    {
        var dsa = new DSACryptoServiceProvider(keySize);

        var ss = new String[2];
        _ = dsa.ExportParameters(true);
        ss[0] = dsa.ToXmlStringX(true);
        ss[1] = dsa.ToXmlStringX(false);

        return ss;
    }

    #endregion

    #region 数字签名
    /// <summary>签名</summary>
    /// <param name="buf"></param>
    /// <param name="priKey"></param>
    /// <returns></returns>
    public static Byte[] Sign(Byte[] buf, String priKey)
    {
        var dsa = new DSACryptoServiceProvider();
        dsa.FromXmlStringX(priKey);

        return dsa.SignData(buf);
    }

    /// <summary>验证</summary>
    /// <param name="buf"></param>
    /// <param name="pukKey"></param>
    /// <param name="rgbSignature"></param>
    /// <returns></returns>
    public static Boolean Verify(Byte[] buf, String pukKey, Byte[] rgbSignature)
    {
        var dsa = new DSACryptoServiceProvider();
        dsa.FromXmlStringX(pukKey);

        return dsa.VerifyData(buf, rgbSignature);
    }
    #endregion

    #region 兼容core
    /// <summary>从Xml加载DSA密钥</summary>
    /// <param name="rsa"></param>
    /// <param name="xmlString"></param>
    public static void FromXmlStringX(this DSACryptoServiceProvider rsa, String xmlString)
    {
        var parameters = new DSAParameters();

        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(xmlString);

        if (xmlDoc.DocumentElement == null || !xmlDoc.DocumentElement.Name.Equals("DSAKeyValue"))
        {
            throw new Exception("Invalid XML DSA key.");
        }

        foreach (var item in xmlDoc.DocumentElement.ChildNodes)
        {
            if (item is not XmlNode node) continue;
            switch (node.Name)
            {
                case "P": parameters.P = (String.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                case "Q": parameters.Q = (String.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                case "G": parameters.G = (String.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                case "Y": parameters.Y = (String.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                case "Seed": parameters.Seed = (String.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
                // PgenCounter 有两种格式:本库 ToXmlStringX 写入的十进制整数,以及历史/外部密钥写入的 Base64 编码整数
                case "PgenCounter":
                case "Counter": parameters.Counter = ParseCounter(node.InnerText); break;
                case "X": parameters.X = (String.IsNullOrEmpty(node.InnerText) ? null : Convert.FromBase64String(node.InnerText)); break;
            }
        }

        rsa.ImportParameters(parameters);
    }

    /// <summary>保存DSA密钥到Xml</summary>
    /// <param name="rsa"></param>
    /// <param name="includePrivateParameters"></param>
    /// <returns></returns>
    public static String ToXmlStringX(this DSACryptoServiceProvider rsa, Boolean includePrivateParameters)
    {
        var parameters = rsa.ExportParameters(includePrivateParameters);

        return String.Format("<DSAKeyValue><P>{0}</P><Q>{1}</Q><G>{2}</G><Y>{3}</Y><Seed>{4}</Seed><PgenCounter>{5}</PgenCounter><X>{6}</X></DSAKeyValue>",
            parameters.P != null ? Convert.ToBase64String(parameters.P) : null,
            parameters.Q != null ? Convert.ToBase64String(parameters.Q) : null,
            parameters.G != null ? Convert.ToBase64String(parameters.G) : null,
            parameters.Y != null ? Convert.ToBase64String(parameters.Y) : null,
            parameters.Seed != null ? Convert.ToBase64String(parameters.Seed) : null,
            parameters.Counter,
            parameters.X != null ? Convert.ToBase64String(parameters.X) : null);
    }

    /// <summary>解析DSA计数器</summary>
    /// <remarks>
    /// 兼容两种格式:十进制整数(本库 ToXmlStringX 写入),以及 Base64 编码整数(历史密钥或外部工具写入,如旧版 NewLife / OpenSSL 转换)。
    /// Counter 仅用于密钥生成验证,不影响签名验签,解析失败时返回 0。
    /// </remarks>
    /// <param name="text">XML 节点文本</param>
    /// <returns>计数器</returns>
    static Int32 ParseCounter(String text)
    {
        if (String.IsNullOrEmpty(text)) return 0;
        if (Int32.TryParse(text, out var counter)) return counter;

        // Base64 编码的整数,可能不足 4 字节,按小端补零
        try
        {
            var buf = Convert.FromBase64String(text);
            if (buf.Length == 0) return 0;
            if (buf.Length >= 4) return BitConverter.ToInt32(buf, 0);

            var arr = new Byte[4];
            Buffer.BlockCopy(buf, 0, arr, 0, buf.Length);
            return BitConverter.ToInt32(arr, 0);
        }
        catch { return 0; }
    }
    #endregion
}