using System.Text; using N_JsonProperty = Newtonsoft.Json.JsonPropertyAttribute; using S_JsonProperty = System.Text.Json.Serialization.JsonPropertyNameAttribute; namespace System.Security.Cryptography { /// /// 非对称加密算法 - RSA /// public static partial class RSAUtils { #region FromJsonString static RSAParameters GetRSAParametersFromJsonString(string jsonString) { var rsaParams = Serializable.DJSON(jsonString); if (rsaParams == null) throw new NullReferenceException(nameof(rsaParams)); return rsaParams.ToStruct(); } /// /// 通过 JSON 字符串中的密钥信息初始化 RSA 对象。 /// /// /// public static void FromJsonString(RSA rsa, string jsonString) { if (rsa == null) throw new ArgumentNullException(nameof(rsa)); var rsaParams = GetRSAParametersFromJsonString(jsonString); rsa.ImportParameters(rsaParams); } #endregion #region FromXmlString static string? SearchForTextOfLocalName(string str, string name) { if (name == null) return null; var leftStr = $"<{name}>"; var rightStr = $""; var leftIndex = str.IndexOf(leftStr, StringComparison.OrdinalIgnoreCase); if (leftIndex < 0) return null; var rightIndex = str.IndexOf(rightStr, StringComparison.OrdinalIgnoreCase); var startIndex = leftIndex + leftStr.Length; var length = rightIndex - (leftIndex + leftStr.Length); return str.Substring(startIndex, length); } static RSAParameters GetRSAParametersFromXmlString(string xmlString) { var rsaParams = new RSAParameters(); var modulusString = SearchForTextOfLocalName(xmlString, "Modulus"); if (modulusString == null) throw new CryptographicException("Cryptography_InvalidFromXmlString_RSA_Modulus"); rsaParams.Modulus = modulusString.Base64DecodeToByteArray_Nullable(); var exponentString = SearchForTextOfLocalName(xmlString, "Exponent"); if (exponentString == null) throw new CryptographicException("Cryptography_InvalidFromXmlString_RSA_Exponent"); rsaParams.Exponent = exponentString.Base64DecodeToByteArray_Nullable(); var pString = SearchForTextOfLocalName(xmlString, "P"); if (pString != null) rsaParams.P = pString.Base64DecodeToByteArray_Nullable(); var qString = SearchForTextOfLocalName(xmlString, "Q"); if (qString != null) rsaParams.Q = qString.Base64DecodeToByteArray_Nullable(); var dpString = SearchForTextOfLocalName(xmlString, "DP"); if (dpString != null) rsaParams.DP = dpString.Base64DecodeToByteArray_Nullable(); var dqString = SearchForTextOfLocalName(xmlString, "DQ"); if (dqString != null) rsaParams.DQ = dqString.Base64DecodeToByteArray_Nullable(); var inverseQString = SearchForTextOfLocalName(xmlString, "InverseQ"); if (inverseQString != null) rsaParams.InverseQ = inverseQString.Base64DecodeToByteArray_Nullable(); var dString = SearchForTextOfLocalName(xmlString, "D"); if (dString != null) rsaParams.D = dString.Base64DecodeToByteArray_Nullable(); return rsaParams; } /// /// 通过 XML 字符串中的密钥信息初始化 RSA 对象。 /// /// /// public static void FromXmlString(RSA rsa, string xmlString) { if (rsa == null) throw new ArgumentNullException(nameof(rsa)); var rsaParams = GetRSAParametersFromXmlString(xmlString); rsa.ImportParameters(rsaParams); } #endregion #region 创建 RSA 实例 /// /// 创建 对象。 /// /// /// public static RSA CreateFromXmlString(string xmlString) { var rsaParams = GetRSAParametersFromXmlString(xmlString); var rsa = RSA.Create(rsaParams); return rsa; } /// /// 创建 对象。 /// /// /// public static RSA CreateFromJsonString(string jsonString) { var rsaParams = GetRSAParametersFromJsonString(jsonString); var rsa = RSA.Create(rsaParams); return rsa; } #endregion #region 从 RSA 实例中获取密钥 /// /// 创建并返回包含当前 对象的密钥的 JSON 字符串。 /// /// /// 表示同时包含 RSA 公钥和私钥; 表示仅包含公钥。 /// 包含当前 对象的密钥的 JSON 字符串。 public static string ToJsonString(this RSA rsa, bool includePrivateParameters) { var rsaParams = rsa.ExportParameters(includePrivateParameters).ToObject(); var jsonString = Serializable.SJSON(rsaParams, ignoreNullValues: true); return jsonString; } #endregion /// /// RSA 填充,不可更改此值! /// internal static RSAEncryptionPadding Padding => RSAEncryptionPadding.OaepSHA256; #region 加密(Encrypt) /// /// RSA加密(ByteArray → ByteArray) /// /// /// /// public static byte[] Encrypt(this RSA rsa, byte[] data) => rsa.Encrypt(data, Padding); /// /// RSA加密(ByteArray → ByteArray) /// /// /// /// public static byte[]? Encrypt_Nullable(this RSA rsa, byte[]? data) { if (data == default) return default; return Encrypt(rsa, data); } /// /// RSA加密(String → ByteArray) /// /// /// /// public static byte[] EncryptToByteArray(this RSA rsa, string text) { var data = Encoding.UTF8.GetBytes(text); return Encrypt(rsa, data); } /// /// RSA加密(String → ByteArray) /// /// /// /// public static byte[]? EncryptToByteArray_Nullable(this RSA rsa, string? text) { if (text == default) return default; return EncryptToByteArray(rsa, text); } /// /// RSA加密(String → String) /// /// /// /// public static string Encrypt(this RSA rsa, string text) { var bytes = EncryptToByteArray(rsa, text); return bytes.Base64UrlEncode(); } /// /// RSA加密(String → String) /// /// /// /// public static string? Encrypt_Nullable(this RSA rsa, string? text) { if (text == default) return default; return Encrypt(rsa, text); } /// /// RSA加密(ByteArray → String) /// /// /// /// public static string EncryptToString(this RSA rsa, byte[] data) { var bytes = Encrypt(rsa, data); return bytes.Base64UrlEncode(); } /// /// RSA加密(ByteArray → String) /// /// /// /// public static string? EncryptToString_Nullable(this RSA rsa, byte[]? data) { if (data == default) return default; return EncryptToString(rsa, data); } #endregion #region 解密(Decrypt) /// /// RSA解密(ByteArray → ByteArray) /// /// /// /// public static byte[] Decrypt(this RSA rsa, byte[] data) => rsa.Decrypt(data, Padding); /// /// RSA解密(ByteArray → ByteArray) /// /// /// /// public static byte[]? Decrypt_Nullable(this RSA rsa, byte[]? data) { if (data == default) return default; return Decrypt(rsa, data); } /// /// RSA解密(String → ByteArray) /// /// /// /// public static byte[] DecryptToByteArray(this RSA rsa, string text) { var bytes = text.Base64UrlDecodeToByteArray(); return Decrypt(rsa, bytes); } /// /// RSA解密(String → ByteArray) /// /// /// /// public static byte[]? DecryptToByteArray_Nullable(this RSA rsa, string? text) { if (text == default) return default; return DecryptToByteArray(rsa, text); } /// /// RSA解密(ByteArray → String) /// /// /// /// public static string DecryptToString(this RSA rsa, byte[] data) { var bytes = Decrypt(rsa, data); return Encoding.UTF8.GetString(bytes); } /// /// RSA解密(ByteArray → String) /// /// /// /// public static string? DecryptToString_Nullable(this RSA rsa, byte[]? data) { if (data == default) return default; return DecryptToString(rsa, data); } /// /// RSA解密(String → String) /// /// /// /// public static string Decrypt(this RSA rsa, string text) { var result = DecryptToByteArray(rsa, text); return Encoding.UTF8.GetString(result); } /// /// RSA解密(String → String) /// /// /// /// public static string? Decrypt_Nullable(this RSA rsa, string? text) { if (text == default) return default; return Decrypt(rsa, text); } #endregion /// /// 密钥 模型类 /// 可使用 JSON 序列化此模型,不支持 MessagePack /// internal sealed class Parameters { /// /// Represents the D parameter for the algorithm. /// [N_JsonProperty("z")] [S_JsonProperty("z")] public string? D { get; set; } /// /// Represents the DP parameter for the algorithm. /// [N_JsonProperty("x")] [S_JsonProperty("x")] public string? DP { get; set; } /// /// Represents the DQ parameter for the algorithm. /// [N_JsonProperty("c")] [S_JsonProperty("c")] public string? DQ { get; set; } /// Represents the Exponent parameter for the algorithm. /// [N_JsonProperty("v")] [S_JsonProperty("v")] public string? Exponent { get; set; } /// /// Represents the InverseQ parameter for the algorithm. /// [N_JsonProperty("b")] [S_JsonProperty("b")] public string? InverseQ { get; set; } /// /// Represents the Modulus parameter for the algorithm. /// [N_JsonProperty("n")] [S_JsonProperty("n")] public string? Modulus { get; set; } /// /// Represents the P parameter for the algorithm. /// [N_JsonProperty("m")] [S_JsonProperty("m")] public string? P { get; set; } /// /// Represents the Q parameter for the algorithm. /// [N_JsonProperty("a")] [S_JsonProperty("a")] public string? Q { get; set; } public bool Equals(Parameters? other) { if (other == null) return false; return string.Equals(D, other.D, StringComparison.Ordinal) && string.Equals(DP, other.DP, StringComparison.Ordinal) && string.Equals(DQ, other.DQ, StringComparison.Ordinal) && string.Equals(Exponent, other.Exponent, StringComparison.Ordinal) && string.Equals(InverseQ, other.InverseQ, StringComparison.Ordinal) && string.Equals(Modulus, other.Modulus, StringComparison.Ordinal) && string.Equals(P, other.P, StringComparison.Ordinal) && string.Equals(Q, other.Q, StringComparison.Ordinal); } } static RSAParameters ToStruct(this Parameters parms) => new RSAParameters { D = parms.D.Base64UrlDecodeToByteArray_Nullable(), DP = parms.DP.Base64UrlDecodeToByteArray_Nullable(), DQ = parms.DQ.Base64UrlDecodeToByteArray_Nullable(), Exponent = parms.Exponent.Base64UrlDecodeToByteArray_Nullable(), InverseQ = parms.InverseQ.Base64UrlDecodeToByteArray_Nullable(), Modulus = parms.Modulus.Base64UrlDecodeToByteArray_Nullable(), P = parms.P.Base64UrlDecodeToByteArray_Nullable(), Q = parms.Q.Base64UrlDecodeToByteArray_Nullable() }; static Parameters ToObject(this RSAParameters parms) => new Parameters { D = parms.D.Base64UrlEncode_Nullable(), DP = parms.DP.Base64UrlEncode_Nullable(), DQ = parms.DQ.Base64UrlEncode_Nullable(), Exponent = parms.Exponent.Base64UrlEncode_Nullable(), InverseQ = parms.InverseQ.Base64UrlEncode_Nullable(), Modulus = parms.Modulus.Base64UrlEncode_Nullable(), P = parms.P.Base64UrlEncode_Nullable(), Q = parms.Q.Base64UrlEncode_Nullable() }; } }