using System; using System.IO; using System.Security.Cryptography; using System.Text; using PaySharp.Core.Exceptions; namespace PaySharp.Core.Utils { /// /// 加密工具类 /// public static class EncryptUtil { #region 私有字段 /// /// 默认编码 /// private static readonly string _defaultCharset = "UTF-8"; #endregion #region MD5加密 /// /// MD5加密 /// /// 数据 public static string MD5(string data) { return MD5(data, Encoding.UTF8); } /// /// MD5加密 /// /// 数据 /// 编码 /// public static string MD5(string data, Encoding encoding) { var md5 = System.Security.Cryptography.MD5.Create(); var dataByte = md5.ComputeHash(encoding.GetBytes(data)); return BitConverter.ToString(dataByte).Replace("-", ""); } #endregion #region RSA加密 /// /// RSA加密 /// /// 数据 /// 私钥 /// 签名类型 /// public static string RSA(string data, string privateKey, string signType) { return RSA(data, privateKey, _defaultCharset, signType, false); } private static string RSA(string data, string privateKeyPem, string charset, string signType, bool keyFromFile) { byte[] signatureBytes = null; try { RSA rsaCsp = null; if (keyFromFile) { //文件读取 rsaCsp = LoadCertificateFile(privateKeyPem, signType); } else { //字符串获取 rsaCsp = LoadCertificateString(privateKeyPem, signType); } byte[] dataBytes = null; if (string.IsNullOrEmpty(charset)) { dataBytes = Encoding.UTF8.GetBytes(data); } else { dataBytes = Encoding.GetEncoding(charset).GetBytes(data); } if (null == rsaCsp) { throw new GatewayException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset); } if ("RSA2".Equals(signType)) { #if NETCOREAPP3_1 signatureBytes = rsaCsp.SignData(dataBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); #else signatureBytes = ((RSACryptoServiceProvider)rsaCsp).SignData(dataBytes, "SHA256"); #endif } else { #if NETCOREAPP3_1 signatureBytes = rsaCsp.SignData(dataBytes, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); #else signatureBytes = ((RSACryptoServiceProvider)rsaCsp).SignData(dataBytes, "SHA1"); #endif } } catch { throw new GatewayException("您使用的私钥格式错误,请检查RSA私钥配置" + ",charset = " + charset); } return Convert.ToBase64String(signatureBytes); } /// /// RSA2验签 /// /// 数据 /// 签名 /// 公钥 /// 签名类型 /// public static bool RSAVerifyData(string data, string sign, string publicKey, string signType) { return RSAVerifyData(data, sign, publicKey, _defaultCharset, signType, false); } private static bool RSAVerifyData(string signContent, string sign, string publicKeyPem, string charset, string signType, bool keyFromFile) { try { var sPublicKeyPEM = publicKeyPem; if (keyFromFile) { sPublicKeyPEM = File.ReadAllText(publicKeyPem); } var rsa = CreateRsaProviderFromPublicKey(sPublicKeyPEM, signType); var bVerifyResultOriginal = false; if ("RSA2".Equals(signType)) { #if NETCOREAPP3_1 bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), Convert.FromBase64String(sign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); #else bVerifyResultOriginal = ((RSACryptoServiceProvider)rsa).VerifyData( Encoding.GetEncoding(charset).GetBytes(signContent), "SHA256", Convert.FromBase64String(sign)); #endif } else { #if NETCOREAPP3_1 bVerifyResultOriginal = rsa.VerifyData(Encoding.GetEncoding(charset).GetBytes(signContent), Convert.FromBase64String(sign), HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); #else bVerifyResultOriginal = ((RSACryptoServiceProvider)rsa).VerifyData( Encoding.GetEncoding(charset).GetBytes(signContent), "SHA1", Convert.FromBase64String(sign)); #endif } return bVerifyResultOriginal; } catch { return false; } } private static RSA CreateRsaProviderFromPublicKey(string publicKeyString, string signType) { byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; var seq = new byte[15]; var x509Key = Convert.FromBase64String(publicKeyString); using var mem = new MemoryStream(x509Key); using var binr = new BinaryReader(mem); byte bt = 0; ushort twobytes = 0; twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) { binr.ReadByte(); } else if (twobytes == 0x8230) { binr.ReadInt16(); } else { return null; } seq = binr.ReadBytes(15); if (!CompareBytearrays(seq, seqOid)) { return null; } twobytes = binr.ReadUInt16(); if (twobytes == 0x8103) { binr.ReadByte(); } else if (twobytes == 0x8203) { binr.ReadInt16(); } else { return null; } bt = binr.ReadByte(); if (bt != 0x00) { return null; } twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) { binr.ReadByte(); } else if (twobytes == 0x8230) { binr.ReadInt16(); } else { return null; } twobytes = binr.ReadUInt16(); byte lowbyte = 0x00; byte highbyte = 0x00; if (twobytes == 0x8102) { lowbyte = binr.ReadByte(); } else if (twobytes == 0x8202) { highbyte = binr.ReadByte(); lowbyte = binr.ReadByte(); } else { return null; } byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; var modsize = BitConverter.ToInt32(modint, 0); var firstbyte = binr.PeekChar(); if (firstbyte == 0x00) { binr.ReadByte(); modsize -= 1; } var modulus = binr.ReadBytes(modsize); if (binr.ReadByte() != 0x02) { return null; } int expbytes = binr.ReadByte(); var exponent = binr.ReadBytes(expbytes); var rsa = System.Security.Cryptography.RSA.Create(); rsa.KeySize = signType == "RSA" ? 1024 : 2048; var rsaKeyInfo = new RSAParameters { Modulus = modulus, Exponent = exponent }; rsa.ImportParameters(rsaKeyInfo); return rsa; } private static bool CompareBytearrays(byte[] a, byte[] b) { if (a.Length != b.Length) { return false; } var i = 0; foreach (var c in a) { if (c != b[i]) { return false; } i++; } return true; } private static RSA LoadCertificateFile(string filename, string signType) { using var fs = File.OpenRead(filename); var data = new byte[fs.Length]; byte[] res = null; fs.Read(data, 0, data.Length); if (data[0] != 0x30) { res = GetPem("RSA PRIVATE KEY", data); } try { return DecodeRSAPrivateKey(res, signType); } catch { return null; } } private static RSA LoadCertificateString(string strKey, string signType) { var data = Convert.FromBase64String(strKey); try { return DecodeRSAPrivateKey(data, signType); } catch { return null; } } private static RSA DecodeRSAPrivateKey(byte[] privkey, string signType) { byte[] modulus, e, d, p, q, dP, dQ, iQ; var mem = new MemoryStream(privkey); var binr = new BinaryReader(mem); try { var twobytes = binr.ReadUInt16(); if (twobytes == 0x8130) { binr.ReadByte(); } else if (twobytes == 0x8230) { binr.ReadInt16(); } else { return null; } twobytes = binr.ReadUInt16(); if (twobytes != 0x0102) { return null; } var bt = binr.ReadByte(); if (bt != 0x00) { return null; } var elems = GetIntegerSize(binr); modulus = binr.ReadBytes(elems); elems = GetIntegerSize(binr); e = binr.ReadBytes(elems); elems = GetIntegerSize(binr); d = binr.ReadBytes(elems); elems = GetIntegerSize(binr); p = binr.ReadBytes(elems); elems = GetIntegerSize(binr); q = binr.ReadBytes(elems); elems = GetIntegerSize(binr); dP = binr.ReadBytes(elems); elems = GetIntegerSize(binr); dQ = binr.ReadBytes(elems); elems = GetIntegerSize(binr); iQ = binr.ReadBytes(elems); var bitLen = 1024; if ("RSA2".Equals(signType)) { bitLen = 2048; } var rsa = System.Security.Cryptography.RSA.Create(); rsa.KeySize = bitLen; var rsaParams = new RSAParameters { Modulus = modulus, Exponent = e, D = d, P = p, Q = q, DP = dP, DQ = dQ, InverseQ = iQ }; rsa.ImportParameters(rsaParams); return rsa; } catch { return null; } finally { binr.Close(); } } private static byte[] GetPem(string type, byte[] data) { var pem = Encoding.UTF8.GetString(data); var header = string.Format("-----BEGIN {0}-----\\n", type); var footer = string.Format("-----END {0}-----", type); var start = pem.IndexOf(header) + header.Length; var end = pem.IndexOf(footer, start); var base64 = pem.Substring(start, end - start); return Convert.FromBase64String(base64); } #endregion #region SHA256加密 /// /// SHA256加密 /// /// 数据 /// public static string SHA256(string data) { var byteData = Encoding.UTF8.GetBytes(data); var sha256 = new SHA256Managed(); var result = sha256.ComputeHash(byteData); return BitConverter.ToString(result).Replace("-", "").ToLower(); } #endregion #region HMACSHA1加密 /// /// HMACSHA1加密 /// /// 数据 /// 密钥 /// public static string HMACSHA1(string data, string key) { var byteData = Encoding.UTF8.GetBytes(data); var byteKey = Encoding.UTF8.GetBytes(key); var hmacsha1 = new HMACSHA1(byteKey); var result = hmacsha1.ComputeHash(byteData); return Convert.ToBase64String(result); } #endregion #region HMACSHA256加密 /// /// HMACSHA256加密 /// /// 数据 /// 密钥 /// public static string HMACSHA256(string data, string key) { var byteData = Encoding.UTF8.GetBytes(data); var byteKey = Encoding.UTF8.GetBytes(key); var hmacsha256 = new HMACSHA256(byteKey); var result = hmacsha256.ComputeHash(byteData); return BitConverter.ToString(result).Replace("-", "").ToLower(); } #endregion #region AES解密 /// /// AES解密 /// /// 待解密数据 /// 密钥 /// public static string AESDecrypt(string data, string key) { var keyArray = Encoding.UTF8.GetBytes(key); var toEncryptArray = Convert.FromBase64String(data); var rDel = new RijndaelManaged { Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 }; var cTransform = rDel.CreateDecryptor(); var resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); return Encoding.UTF8.GetString(resultArray); } #endregion #region from alipay signer /// /// 验证签名 /// /// 待验签的内容 /// 签名值的Base64串 /// 支付宝公钥 /// true:验证成功;false:验证失败 public static bool Verify(string content, string sign, string publicKeyPem) { try { using (RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider()) { rsaService.PersistKeyInCsp = false; rsaService.ImportParameters(ConvertFromPemPublicKey(publicKeyPem)); return rsaService.VerifyData(Encoding.UTF8.GetBytes(content), "SHA256", Convert.FromBase64String(sign)); } } catch (Exception e) { string errorMessage = "验签遭遇异常,content=" + content + " sign=" + sign + " publicKey=" + publicKeyPem + " reason=" + e.Message; throw new Exception(errorMessage, e); } } /// /// SHA256WithRSA 计算签名 /// /// 数据 /// 私钥 /// public static string Sign(string content, string privateKeyPem) { try { using (RSACryptoServiceProvider rsaService = BuildRSAServiceProvider(Convert.FromBase64String(privateKeyPem))) { byte[] data = Encoding.UTF8.GetBytes(content); byte[] sign = rsaService.SignData(data, "SHA256"); return Convert.ToBase64String(sign); } } catch (Exception e) { string errorMessage = "签名遭遇异常,content=" + content + " privateKeySize=" + privateKeyPem.Length + " reason=" + e.Message; throw new Exception(errorMessage, e); } } private static RSAParameters ConvertFromPemPublicKey(string pemPublickKey) { if (string.IsNullOrEmpty(pemPublickKey)) { throw new Exception("PEM格式公钥不可为空。"); } //移除干扰文本 pemPublickKey = pemPublickKey.Replace("-----BEGIN PUBLIC KEY-----", "") .Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", ""); byte[] keyData = Convert.FromBase64String(pemPublickKey); bool keySize1024 = (keyData.Length == 162); bool keySize2048 = (keyData.Length == 294); if (!(keySize1024 || keySize2048)) { throw new Exception("公钥长度只支持1024和2048。"); } byte[] pemModulus = (keySize1024 ? new byte[128] : new byte[256]); byte[] pemPublicExponent = new byte[3]; Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256)); Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3); RSAParameters para = new RSAParameters { Modulus = pemModulus, Exponent = pemPublicExponent }; return para; } private static RSACryptoServiceProvider BuildRSAServiceProvider(byte[] privateKey) { byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; byte bt = 0; ushort twobytes = 0; int elems = 0; //set up stream to decode the asn.1 encoded RSA private key //wrap Memory Stream with BinaryReader for easy reading using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(privateKey))) { twobytes = binaryReader.ReadUInt16(); //data read as little endian order (actual data order for Sequence is 30 81) if (twobytes == 0x8130) { //advance 1 byte binaryReader.ReadByte(); } else if (twobytes == 0x8230) { //advance 2 bytes binaryReader.ReadInt16(); } else { return null; } twobytes = binaryReader.ReadUInt16(); //version number if (twobytes != 0x0102) { return null; } bt = binaryReader.ReadByte(); if (bt != 0x00) { return null; } //all private key components are Integer sequences elems = GetIntegerSize(binaryReader); MODULUS = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); E = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); D = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); P = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); Q = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); DP = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); DQ = binaryReader.ReadBytes(elems); elems = GetIntegerSize(binaryReader); IQ = binaryReader.ReadBytes(elems); //create RSACryptoServiceProvider instance and initialize with public key RSACryptoServiceProvider rsaService = new RSACryptoServiceProvider(); RSAParameters rsaParams = new RSAParameters { Modulus = MODULUS, Exponent = E, D = D, P = P, Q = Q, DP = DP, DQ = DQ, InverseQ = IQ }; rsaService.ImportParameters(rsaParams); return rsaService; } } private static int GetIntegerSize(BinaryReader binaryReader) { byte bt = 0; byte lowbyte = 0x00; byte highbyte = 0x00; int count = 0; bt = binaryReader.ReadByte(); //expect integer if (bt != 0x02) { return 0; } bt = binaryReader.ReadByte(); if (bt == 0x81) { //data size in next byte count = binaryReader.ReadByte(); } else if (bt == 0x82) { //data size in next 2 bytes highbyte = binaryReader.ReadByte(); lowbyte = binaryReader.ReadByte(); byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; count = BitConverter.ToInt32(modint, 0); } else { //we already have the data size count = bt; } while (binaryReader.ReadByte() == 0x00) { //remove high order zeros in data count -= 1; } //last ReadByte wasn't a removed zero, so back up a byte binaryReader.BaseStream.Seek(-1, SeekOrigin.Current); return count; } #endregion } }