.NET Core 使用RSA算法 加密/解密/签名/验证签名
前言
前不久移植了支付寶官方的SDK,以適用ASP.NET Core使用支付寶支付,但是最近有好幾位用戶反應(yīng)在Linux下使用會(huì)出錯(cuò),調(diào)試發(fā)現(xiàn)是RSA加密的錯(cuò)誤,下面具體講一講。
RSA在.NET Core的改動(dòng)
以前我們使用RSA加密主要是使用RSACryptoServiceProvider這個(gè)類,在.NET Core中也有這個(gè)類,但是這個(gè)類并不支持跨平臺(tái),所以如果你是用這個(gè)類來進(jìn)行加/解密在windows上運(yùn)行是完全沒有錯(cuò)誤的,但是只要你一放到Linux下就會(huì)出現(xiàn)異常。
查閱資料得知,要解決這個(gè)問題,需要改用?System.Security.Cryptography.RSA.Create()?工廠方法,使用它之后,在 Windows 上創(chuàng)建的是?System.Security.Cryptography.RSACng?的實(shí)例,在 Mac 與 Linux 上創(chuàng)建的是?System.Security.Cryptography.RSAOpenSsl?的實(shí)例,它們都繼承自?System.Security.Cryptography.RSA?抽象類。
RSACng:
相關(guān)資料:https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.rsacng?view=netcore-2.0
RSAOpenSsl :
相關(guān)資料:https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.rsaopenssl?view=netcore-2.0
在Windows上的調(diào)試截圖:
在Mac上使用Visual studio For Mac 調(diào)試截圖:
RSA公鑰/私鑰說明
這里的RSA加密/解密主要是針對于由OpenSSL生成的公鑰/私鑰字符串。ssh-keygen -t rsa 命令生成的公鑰私鑰是不行的。
公鑰示例:
-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7PyjMEuniN6BPn8oqzIZ6AO1N jSTO9R3adCCIwKfKIEoWXXM+tHDpktdPKSaAsWJPTNAGvEvtxOfzXib/EMXKqD0e Uy5MatfpRjRdf1hJVimmfrb09Qx2j7CsKLy7nD23m4xubdYBwvkjMwt/L3JxB5D6 qryW1wei/j1c+/OCxQIDAQAB -----END PUBLIC KEY-----私鑰示例:
-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQC7PyjMEuniN6BPn8oqzIZ6AO1NjSTO9R3adCCIwKfKIEoWXXM+ tHDpktdPKSaAsWJPTNAGvEvtxOfzXib/EMXKqD0eUy5MatfpRjRdf1hJVimmfrb09Qx2j7CsKLy7nD23m4xubdYBwvkjMwt/L3JxB5D6qryW1wei/j1c+/OCxQIDAQAB AoGAT7vGYJgRNf4f6qgNS4pKHTu10RcwPFyOOM7IZ9M5380+HyXuBB6MEjowKwpH1fcy+LepwaR+5KG7b5uBGY4H2ticMtdysBd9gLwnY4Eh4j7LCWE54HvELpeWXkWp FQdb/NQhcqMAGwYsTnRPdBqkrUmJBTYqEGkIlqCQ5vUJOCECQQDhe0KGmbq1RWp6 TDvgpA2dUmlt2fdP8oNW8O7MvbDaQRduoZnVRTPYCDKfzFqpNXL1hAYgth1N0vzD nv3VoLcpAkEA1JcY+rLv5js1g5Luv8LaI5/3uOg0CW7fmh/LfGuz8k/OxASN+cAO UjPHrxtc5xn1zat4/bnV5GEdlOp/DhquPQJBAIV2Fsdi4M+AueiPjPWHRQO0jvDV jfwFOFZSn5YSRUa6NmtmPY6tumUJXSWWqKb1GwlVTuc3xBqXYsNLLUWwLhkCQQDJ UJCiD0LohhdGEqUuSKnj5H9kxddJO4pZXFSI7UEJbJQDwcBkyn+FTm2BH+tZGZdQ fVnlA89OJr0poOpSg+eNAkAKY85SR9KASaTiDBoPpJ8N805XEhd0Kq+ghzSThxL3 fVtKUQLiCh7Yd8oMd/G5S3xWJHUXSioATT8uPRH2bOb/ -----END RSA PRIVATE KEY-----公鑰/私鑰生成
Windows&MAC_OSX可以使用有支付寶開發(fā)的RSA密鑰生成工具:
使用此工具生成的時(shí)候一定要選擇,PKCS1
下載地址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=105971&docType=1
此外還可以使用OpenSSL工具命令來生成:https://doc.open.alipay.com/docs/doc.htm?articleId=106130&docType=1
.NET Core 中的使用
這里要講一下RSA2算法。
什么是RSA2 ?RSA2 是在原來SHA1WithRSA簽名算法的基礎(chǔ)上,新增了支持SHA256WithRSA的簽名算法。該算法比SHA1WithRSA有更強(qiáng)的安全能力。
| RSA2 | SHA256WithRSA | (強(qiáng)烈推薦使用),強(qiáng)制要求RSA密鑰的長度至少為2048 |
| RSA | SHA1WithRSA | 對RSA密鑰的長度不限制,推薦使用2048位以上 |
簽名的作用:保證數(shù)據(jù)完整性,機(jī)密性和發(fā)送方角色的不可抵賴性
這里來一發(fā)干貨,我已經(jīng)封裝好的RSA/RSA2算法,支持加密/解密/簽名/驗(yàn)證簽名。
/// <summary>/// RSA加解密 使用OpenSSL的公鑰加密/私鑰解密
/// 作者:李志強(qiáng)
/// 創(chuàng)建時(shí)間:2017年10月30日15:50:14
/// QQ:501232752
/// </summary>
public class RSAHelper{ ?
? private readonly RSA _privateKeyRsaProvider; ?
??private readonly RSA _publicKeyRsaProvider; ?
??private readonly HashAlgorithmName _hashAlgorithmName; ?
??
??private readonly Encoding _encoding; ? ?/// <summary>/// 實(shí)例化RSAHelper/// </summary>/// <param name="rsaType">加密算法類型 RSA SHA1;RSA2 SHA256 密鑰長度至少為2048</param>/// <param name="encoding">編碼類型</param>/// <param name="privateKey">私鑰</param>/// <param name="publicKey">公鑰</param>public RSAHelper(RSAType rsaType, Encoding encoding, string privateKey, string publicKey = null) ? ?{_encoding = encoding; ? ? ?
?if (!string.IsNullOrEmpty(privateKey)){_privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);} ? ? ? ?if (!string.IsNullOrEmpty(publicKey)){_publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publicKey);}_hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;} ? ?/// <summary>/// 使用私鑰簽名/// </summary>/// <param name="data">原始數(shù)據(jù)</param>/// <returns></returns>public string Sign(string data) ? ?{ ? ?
? ?byte[] dataBytes = _encoding.GetBytes(data); ? ?
? ? ? ?var signatureBytes = _privateKeyRsaProvider.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1); ?
? ? ? ?? ? ?return Convert.ToBase64String(signatureBytes);} ? ?/// <summary>/// 使用公鑰驗(yàn)證簽名/// </summary>/// <param name="data">原始數(shù)據(jù)</param>/// <param name="sign">簽名</param>/// <returns></returns>public bool Verify(string data,string sign) ? ?{ ? ?
? ?byte[] dataBytes = _encoding.GetBytes(data); ? ? ?
? ? ?byte[] signBytes = Convert.FromBase64String(sign); ?
? ? ?var verify = _publicKeyRsaProvider.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1); ? ? ?
? ? ??return verify;} ? ?public string Decrypt(string cipherText) ? ?{ ? ? ? ?if (_privateKeyRsaProvider == null){ ? ? ? ?
? ?throw new Exception("_privateKeyRsaProvider is null");} ? ? ?
? ??return Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1));} ? ?public string Encrypt(string text) ? ?{ ? ? ?
? ?? ?if (_publicKeyRsaProvider == null){ ? ? ? ? ?
? ?? ??throw new Exception("_publicKeyRsaProvider is null");} ? ? ?
? ?? ???return Convert.ToBase64String(_publicKeyRsaProvider.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.Pkcs1));} ? ?public RSA CreateRsaProviderFromPrivateKey(string privateKey) ? ?{ ? ? ? ?var privateKeyBits = Convert.FromBase64String(privateKey); ? ?
? ?? ???? ?var rsa = RSA.Create(); ? ? ?
? ?? ???? ?var rsaParameters = new RSAParameters(); ?
? ?? ??? ?using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits))){ ? ? ? ? ? ?byte bt = 0; ? ? ? ?
? ?? ??? ? ? ?ushort twobytes = 0;twobytes = binr.ReadUInt16(); ? ? ?
? ?? ???? ? ?if (twobytes == 0x8130)binr.ReadByte(); ? ? ? ? ?
? ?? ???? ? ? ?else if (twobytes == 0x8230)binr.ReadInt16(); ? ? ? ?
? ?? ???? ? ? ? ? ?elsethrow new Exception("Unexpected value read binr.ReadUInt16()");twobytes = binr.ReadUInt16(); ? ? ?
? ?? ???? ?if (twobytes != 0x0102) ? ? ?
? ?? ???? ? ?throw new Exception("Unexpected version");bt = binr.ReadByte(); ? ? ? ?
? ?? ???? ?if (bt != 0x00) ?
? ?? ???? ? ? ?throw new Exception("Unexpected value read binr.ReadByte()");rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr));rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr));}rsa.ImportParameters(rsaParameters); ? ?
? ?? ??return rsa;} ? ?public RSA CreateRsaProviderFromPublicKey(string publicKeyString) ? ?{ ? ? ? ?// encoded OID sequence for ?PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; ? ?
? ??? ?byte[] seq = new byte[15]; ? ? ?
? ????var x509Key = Convert.FromBase64String(publicKeyString); ? ? ? ?// --------- ?Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ?------using (MemoryStream mem = new MemoryStream(x509Key)){ ? ? ? ? ? ?using (BinaryReader binr = new BinaryReader(mem)) ?//wrap Memory Stream with BinaryReader for easy reading{ ? ? ? ? ? ? ? ?byte bt = 0; ? ? ? ? ? ? ? ?ushort twobytes = 0;twobytes = binr.ReadUInt16(); ? ? ? ? ? ? ? ?if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)binr.ReadByte(); ? ?//advance 1 byteelse if (twobytes == 0x8230)binr.ReadInt16(); ? //advance 2 byteselsereturn null;seq = binr.ReadBytes(15); ? ? ? //read the Sequence OIDif (!CompareBytearrays(seq, seqOid)) ? ?//make sure Sequence for OID is correctreturn null;twobytes = binr.ReadUInt16(); ? ? ? ? ? ? ? ?if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)binr.ReadByte(); ? ?//advance 1 byteelse if (twobytes == 0x8203)binr.ReadInt16(); ? //advance 2 byteselsereturn null;bt = binr.ReadByte(); ? ? ? ? ? ? ? ?if (bt != 0x00) ? ? //expect null byte nextreturn null;twobytes = binr.ReadUInt16(); ? ? ? ? ? ? ? ?if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)binr.ReadByte(); ? ?//advance 1 byteelse if (twobytes == 0x8230) ? ? ? ? ? ? ? ? ? ?binr.ReadInt16(); ? //advance 2 bytes ? ? ? ? ? ? ? ?else ? ? ? ? ? ? ? ? ? ?return null; ? ? ? ? ? ? ? ?twobytes = binr.ReadUInt16(); ? ? ? ?
? ? ? ?byte lowbyte = 0x00; ? ? ? ? ? ?
? ? ? ? ? ?byte highbyte = 0x00; ? ? ? ?
? ? ? ?if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) ? ? ? ? ? ? ? ? ? ?lowbyte = binr.ReadByte(); ?// read next bytes which is bytes in modulus ? ? ? ? ? ? ? ?else if (twobytes == 0x8202) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?highbyte = binr.ReadByte(); //advance 2 bytes ? ? ? ? ? ? ? ? ? ?lowbyte = binr.ReadByte(); ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?else ? ? ? ? ? ? ? ? ? ?return null; ? ? ? ? ?
? ? ?byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; ? //reverse byte order since asn.1 key uses big endian order ? ? ? ? ? ? ? ?int modsize = BitConverter.ToInt32(modint, 0); ? ? ? ? ? ? ? ?int firstbyte = binr.PeekChar(); ? ? ? ? ? ?
? ? ? ? ?if (firstbyte == 0x00) ? ? ? ? ? ? ? ?{ ? //if first byte (highest order) of modulus is zero, don't include it ? ? ? ? ? ? ? ? ? ?binr.ReadByte(); ? ?//skip this null byte ? ? ? ? ? ? ? ? ? ?modsize -= 1; ? //reduce modulus buffer size by 1 ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ?byte[] modulus = binr.ReadBytes(modsize); ? //read the modulus bytes ? ? ? ? ? ? ? ?if (binr.ReadByte() != 0x02) ? ? ? ? ?
?//expect an Integer for the exponent data ? ? ? ? ? ? ? ? ? ?return null; ? ? ? ? ? ? ?
? ?int expbytes = (int)binr.ReadByte(); ? ?
? ?// should only need one byte for actual exponent data (for all useful values) ? ? ? ? ? ? ? ?byte[] exponent = binr.ReadBytes(expbytes); ? ? ? ? ? ? ? ?// ------- create RSACryptoServiceProvider instance and initialize with public key ----- ? ? ? ? ? ? ? ?var rsa = RSA.Create(); ? ? ? ? ? ? ? ?RSAParameters rsaKeyInfo = new RSAParameters ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?Modulus = modulus, ? ? ? ? ? ? ? ? ? ?Exponent = exponent ? ? ? ? ? ? ? ?}; ? ? ? ? ? ? ? ?rsa.ImportParameters(rsaKeyInfo); ? ? ? ?
? ? ? ?? ? ? ?return rsa; ? ? ? ? ? ?} ? ? ? ?} ? ?} ? ? ? ? ? ?private int GetIntegerSize(BinaryReader binr) ? ?{ ? ? ?
?byte bt = 0; ? ? ? ?int count = 0; ? ? ? ?bt = binr.ReadByte(); ? ?
? ? ?if (bt != 0x02) ? ? ? ? ?
? ? ? ?return 0; ? ? ? ?bt = binr.ReadByte(); ? ? ?
? ? ? ? ?if (bt == 0x81) ? ? ? ? ? ?count = binr.ReadByte(); ?
? ? ? ? ?else ? ? ? ?if (bt == 0x82) ? ? ? ?{ ? ? ?
? ? ? ? ? ? ? ?var highbyte = binr.ReadByte(); ?
? ? ? ? ? ? ? ?var lowbyte = binr.ReadByte();
? ? ? ? ? ? ? ?byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; ? ? ? ? ? ?count = BitConverter.ToInt32(modint, 0); ? ? ? ?} ? ? ?
? ? ? ??else ? ? ? ?{ ? ? ? ? ? ?count = bt; ? ? ? ?} ? ? ?
? ? ? ??while (binr.ReadByte() == 0x00) ? ? ? ?{ ? ? ? ? ? ?count -= 1; ? ? ? ?} ? ? ? ?binr.BaseStream.Seek(-1, SeekOrigin.Current); ?
? ? ?return count; ? ?} ?
? ? ?
? ? ??private bool CompareBytearrays(byte[] a, byte[] b) ? ?{ ? ?
? ? ?? ?if (a.Length != b.Length) ? ? ?
? ? ?? ?? ? ?return false; ? ?
? ? ?? ?int i = 0; ? ?
? ? ?? ?foreach (byte c in a) ? ? ? ?{ ? ? ? ? ?
? ? ?? ??if (c != b[i]) ? ? ? ? ?
? ? ?? ?? ? ? ?return false; ? ? ? ? ? ?i++; ? ? ? ?} ? ? ? ?return true; ? ?} ? ?}
/// <summary>
/// RSA算法類型
/// </summary>
public enum RSAType { ?
? ??/// <summary> ? ?/// SHA1 ? ?/// </summary> ? ?RSA = 0, ? ?/// <summary> ? ?/// RSA2 密鑰長度至少為2048 ? ?/// SHA256 ? ?/// </summary> ? ?RSA2 }
? ??
使用:
static void Main(string[] args){ ? ?//2048 公鑰string publicKey = ? ? ? ?"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoQh0wEqx/R2H1v00IU12Oc30fosRC/frhH89L6G+fzeaqI19MYQhEPMU13wpeqRONCUta+2iC1sgCNQ9qGGf19yGdZUfueaB1Nu9rdueQKXgVurGHJ+5N71UFm+OP1XcnFUCK4wT5d7ZIifXxuqLehP9Ts6sNjhVfa+yU+VjF5HoIe69OJEPo7OxRZcRTe17khc93Ic+PfyqswQJJlY/bgpcLJQnM+QuHmxNtF7/FpAx9YEQsShsGpVo7JaKgLo+s6AFoJ4QldQKir2vbN9vcKRbG3piElPilWDpjXQkOJZhUloh/jd7QrKFimZFldJ1r6Q59QYUyGKZARUe0KZpMQIDAQAB"; ? ?//2048 私鑰string privateKey = ? ? ? ?"MIIEpAIBAAKCAQEAoQh0wEqx/R2H1v00IU12Oc30fosRC/frhH89L6G+fzeaqI19MYQhEPMU13wpeqRONCUta+2iC1sgCNQ9qGGf19yGdZUfueaB1Nu9rdueQKXgVurGHJ+5N71UFm+OP1XcnFUCK4wT5d7ZIifXxuqLehP9Ts6sNjhVfa+yU+VjF5HoIe69OJEPo7OxRZcRTe17khc93Ic+PfyqswQJJlY/bgpcLJQnM+QuHmxNtF7/FpAx9YEQsShsGpVo7JaKgLo+s6AFoJ4QldQKir2vbN9vcKRbG3piElPilWDpjXQkOJZhUloh/jd7QrKFimZFldJ1r6Q59QYUyGKZARUe0KZpMQIDAQABAoIBAQCRZLUlOUvjIVqYvhznRK1OG6p45s8JY1r+UnPIId2Bt46oSLeUkZvZVeCnfq9k0Bzb8AVGwVPhtPEDh73z3dEYcT/lwjLXAkyPB6gG5ZfI/vvC/k7JYV01+neFmktw2/FIJWjEMMF2dvLNZ/Pm4bX1Dz9SfD/45Hwr8wqrvRzvFZsj5qqOxv9RPAudOYwCwZskKp/GF+L+3Ycod1Wu98imzMZUH+L5dQuDGg3kvf3ljIAegTPoqYBg0imNPYY/EGoFKnbxlK5S5/5uAFb16dGJqAz3XQCz9Is/IWrOTu0etteqV2Ncs8uqPdjed+b0j8CMsr4U1xjwPQ8WwdaJtTkRAoGBANAndgiGZkCVcc9975/AYdgFp35W6D+hGQAZlL6DmnucUFdXbWa/x2rTSEXlkvgk9X/PxOptUYsLJkzysTgfDywZwuIXLm9B3oNmv3bVgPXsgDsvDfaHYCgz0nHK6NSrX2AeX3yO/dFuoZsuk+J+UyRigMqYj0wjmxUlqj183hinAoGBAMYMOBgF77OXRII7GAuEut/nBeh2sBrgyzR7FmJMs5kvRh6Ck8wp3ysgMvX4lxh1ep8iCw1R2cguqNATr1klOdsCTOE9RrhuvOp3JrYzuIAK6MpH/uBICy4w1rW2+gQySsHcH40r+tNaTFQ7dQ1tef//iy/IW8v8i0t+csztE1JnAoGABdtWYt8FOYP688+jUmdjWWSvVcq0NjYeMfaGTOX/DsNTL2HyXhW/Uq4nNnBDNmAz2CjMbZwt0y+5ICkj+2REVQVUinAEinTcAe5+LKXNPx4sbX3hcrJUbk0m+rSu4G0B/f5cyXBsi9wFCAzDdHgBduCepxSr04Sc9Hde1uQQi7kCgYB0U20HP0Vh+TG2RLuE2HtjVDD2L/CUeQEiXEHzjxXWnhvTg+MIAnggvpLwQwmMxkQ2ACr5sd/3YuCpB0bxV5o594nsqq9FWVYBaecFEjAGlWHSnqMoXWijwu/6X/VOTbP3VjH6G6ECT4GR4DKKpokIQrMgZ9DzaezvdOA9WesFdQKBgQCWfeOQTitRJ0NZACFUn3Fs3Rvgc9eN9YSWj4RtqkmGPMPvguWo+SKhlk3IbYjrRBc5WVOdoX8JXb2/+nAGhPCuUZckWVmZe5pMSr4EkNQdYeY8kOXGSjoTOUH34ZdKeS+e399BkBWIiXUejX/Srln0H4KoHnTWgxwNpTsBCgXu8Q=="; ? ?var rsa = new RSAHelper(RSAType.RSA2,Encoding.UTF8, privateKey, publicKey); ? ?string str = "博客園 http://www.cnblogs.com/";Console.WriteLine("原始字符串:"+str); ? ?//加密string enStr = rsa.Encrypt(str);Console.WriteLine("加密字符串:"+enStr); ? ?//解密string deStr = rsa.Decrypt(enStr);Console.WriteLine("解密字符串:"+deStr); ? ?//私鑰簽名string signStr = rsa.Sign(str);Console.WriteLine("字符串簽名:" + signStr); ? ?//公鑰驗(yàn)證簽名bool signVerify = rsa.Verify(str,signStr);Console.WriteLine("驗(yàn)證簽名:" + signVerify);Console.ReadKey(); }運(yùn)行:
參考
-
http://www.cnblogs.com/dudu/p/dotnet-core-rsa-openssl.html
本文Demo:https://github.com/stulzq/DotnetCore.RSA
.NET Core 交流群:4656606原文地址:http://www.cnblogs.com/stulzq/p/7757915.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注
總結(jié)
以上是生活随笔為你收集整理的.NET Core 使用RSA算法 加密/解密/签名/验证签名的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅析Entity Framework C
- 下一篇: ASP.NET Core中的OWASP