.net(c#)版RSA加密算法,拿走不谢

今天有同学对接一个支付平台,涉及到RSA的签名和验签。由于对方是java的sdk,翻成c#语言时,搞了半天也没搞定。网上搜的东西都是各种copy还不解决问题。 碰巧,我之前对接过连连银通的网银支付和代付。连连那边提供了c#版的RSA加密算法,立即破了这位同学的难题。在这里也分享出来,以便大家日后备用。

 

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.IO;
  5 using System.Security.Cryptography;
  6 
  7 /// <summary>
  8 /// 类名:RSAFromPkcs8
  9 /// 功能:RSA解密、签名、验签
 10 /// 详细:该类对Java生成的密钥进行解密和签名以及验签专用类,不需要修改
 11 /// 版本:1.0
 12 /// 日期:2013-09-30
 13 /// 说明:
 14 /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 15 /// </summary>
 16 public sealed class RSAFromPkcs8
 17 {
 18     /// <summary>
 19     /// 签名
 20     /// </summary>
 21     /// <param name="content">待签名字符串</param>
 22     /// <param name="privateKey">私钥</param>
 23     /// <param name="input_charset">编码格式</param>
 24     /// <returns>签名后字符串</returns>
 25     public static string sign(string content, string privateKey, string input_charset = "utf-8")
 26     {
 27         byte[] Data = Encoding.GetEncoding(input_charset).GetBytes(content);
 28         RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
 29         //SHA1 crypto = new SHA1CryptoServiceProvider();
 30         MD5 crypto = new MD5CryptoServiceProvider();
 31         byte[] signData = rsa.SignData(Data, crypto);
 32         return Convert.ToBase64String(signData);
 33     }
 34 
 35     /// <summary>
 36     /// 验签
 37     /// </summary>
 38     /// <param name="content">待验签字符串</param>
 39     /// <param name="signedString">签名</param>
 40     /// <param name="publicKey">公钥</param>
 41     /// <param name="input_charset">编码格式</param>
 42     /// <returns>true(通过),false(不通过)</returns>
 43     public static bool verify(string content, string signedString, string publicKey, string input_charset = "utf-8")
 44     {
 45         bool result = false;
 46         byte[] Data = Encoding.GetEncoding(input_charset).GetBytes(content);
 47         byte[] data = Convert.FromBase64String(signedString);
 48         RSAParameters paraPub = ConvertFromPublicKey(publicKey);
 49         RSACryptoServiceProvider rsaPub = new RSACryptoServiceProvider();                
 50         rsaPub.ImportParameters(paraPub);
 51         //SHA1 crypto = new SHA1CryptoServiceProvider();
 52         MD5 crypto = new MD5CryptoServiceProvider();
 53         result = rsaPub.VerifyData(Data, crypto, data);
 54         return result;
 55     }
 56 
 57     /// <summary>
 58     /// 解密
 59     /// </summary>
 60     /// <param name="resData">加密字符串</param>
 61     /// <param name="privateKey">私钥</param>
 62     /// <param name="input_charset">编码格式</param>
 63     /// <returns>明文</returns>
 64     public static string decryptData(string resData, string privateKey, string input_charset)
 65     {
 66         byte[] DataToDecrypt = Convert.FromBase64String(resData);
 67         List<byte> result = new List<byte>();
 68         for (int j = 0; j < DataToDecrypt.Length / 128; j++)
 69         {
 70             byte[] buf = new byte[128];
 71             for (int i = 0; i < 128; i++)
 72             {
 73                 buf[i] = DataToDecrypt[i + 128 * j];
 74             }
 75             result.AddRange(decrypt(buf, privateKey, input_charset));
 76         }
 77         byte[] source = result.ToArray();
 78         char[] asciiChars = new char[Encoding.GetEncoding(input_charset).GetCharCount(source, 0, source.Length)];
 79         Encoding.GetEncoding(input_charset).GetChars(source, 0, source.Length, asciiChars, 0);
 80         return new string(asciiChars);
 81     }
 82 
 83     #region 内部方法 
 84 
 85     private static byte[] decrypt(byte[] data, string privateKey, string input_charset)
 86     {
 87         RSACryptoServiceProvider rsa = DecodePemPrivateKey(privateKey);
 88         //SHA1 sh = new SHA1CryptoServiceProvider();
 89         return rsa.Decrypt(data, false);
 90     }
 91 
 92     private static RSACryptoServiceProvider DecodePemPrivateKey(String pemstr)
 93     {
 94         byte[] pkcs8privatekey;
 95         pkcs8privatekey = Convert.FromBase64String(pemstr);
 96         if (pkcs8privatekey != null)
 97         {
 98             RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8privatekey);
 99             return rsa;
100         }
101         else
102             return null;
103     }
104 
105     private static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)
106     {
107         byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
108         byte[] seq = new byte[15];
109 
110         MemoryStream mem = new MemoryStream(pkcs8);
111         int lenstream = (int)mem.Length;
112         BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
113         byte bt = 0;
114         ushort twobytes = 0;
115 
116         try
117         {
118             twobytes = binr.ReadUInt16();
119             if (twobytes == 0x8130)    //data read as little endian order (actual data order for Sequence is 30 81)
120                 binr.ReadByte();    //advance 1 byte
121             else if (twobytes == 0x8230)
122                 binr.ReadInt16();    //advance 2 bytes
123             else
124                 return null;
125 
126             bt = binr.ReadByte();
127             if (bt != 0x02)
128                 return null;
129 
130             twobytes = binr.ReadUInt16();
131 
132             if (twobytes != 0x0001)
133                 return null;
134 
135             seq = binr.ReadBytes(15);        //read the Sequence OID
136             if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
137                 return null;
138 
139             bt = binr.ReadByte();
140             if (bt != 0x04)    //expect an Octet string 
141                 return null;
142 
143             bt = binr.ReadByte();        //read next byte, or next 2 bytes is  0x81 or 0x82; otherwise bt is the byte count
144             if (bt == 0x81)
145                 binr.ReadByte();
146             else
147                 if (bt == 0x82)
148                     binr.ReadUInt16();
149             //------ at this stage, the remaining sequence should be the RSA private key
150 
151             byte[] rsaprivkey = binr.ReadBytes((int)(lenstream - mem.Position));
152             RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey);
153             return rsacsp;
154         }
155 
156         catch (Exception)
157         {
158             return null;
159         }
160 
161         finally { binr.Close(); }
162 
163     }
164 
165     private static bool CompareBytearrays(byte[] a, byte[] b)
166     {
167         if (a.Length != b.Length)
168             return false;
169         int i = 0;
170         foreach (byte c in a)
171         {
172             if (c != b[i])
173                 return false;
174             i++;
175         }
176         return true;
177     }
178 
179     private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
180     {
181         byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
182 
183         // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
184         MemoryStream mem = new MemoryStream(privkey);
185         BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
186         byte bt = 0;
187         ushort twobytes = 0;
188         int elems = 0;
189         try
190         {
191             twobytes = binr.ReadUInt16();
192             if (twobytes == 0x8130)    //data read as little endian order (actual data order for Sequence is 30 81)
193                 binr.ReadByte();    //advance 1 byte
194             else if (twobytes == 0x8230)
195                 binr.ReadInt16();    //advance 2 bytes
196             else
197                 return null;
198 
199             twobytes = binr.ReadUInt16();
200             if (twobytes != 0x0102)    //version number
201                 return null;
202             bt = binr.ReadByte();
203             if (bt != 0x00)
204                 return null;
205 
206 
207             //------  all private key components are Integer sequences ----
208             elems = GetIntegerSize(binr);
209             MODULUS = binr.ReadBytes(elems);
210 
211             elems = GetIntegerSize(binr);
212             E = binr.ReadBytes(elems);
213 
214             elems = GetIntegerSize(binr);
215             D = binr.ReadBytes(elems);
216 
217             elems = GetIntegerSize(binr);
218             P = binr.ReadBytes(elems);
219 
220             elems = GetIntegerSize(binr);
221             Q = binr.ReadBytes(elems);
222 
223             elems = GetIntegerSize(binr);
224             DP = binr.ReadBytes(elems);
225 
226             elems = GetIntegerSize(binr);
227             DQ = binr.ReadBytes(elems);
228 
229             elems = GetIntegerSize(binr);
230             IQ = binr.ReadBytes(elems);
231 
232             // ------- create RSACryptoServiceProvider instance and initialize with public key -----
233             RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
234             RSAParameters RSAparams = new RSAParameters();
235             RSAparams.Modulus = MODULUS;
236             RSAparams.Exponent = E;
237             RSAparams.D = D;
238             RSAparams.P = P;
239             RSAparams.Q = Q;
240             RSAparams.DP = DP;
241             RSAparams.DQ = DQ;
242             RSAparams.InverseQ = IQ;
243             RSA.ImportParameters(RSAparams);
244             return RSA;
245         }
246         catch (Exception)
247         {
248             return null;
249         }
250         finally { binr.Close(); }
251     }
252 
253     private static int GetIntegerSize(BinaryReader binr)
254     {
255         byte bt = 0;
256         byte lowbyte = 0x00;
257         byte highbyte = 0x00;
258         int count = 0;
259         bt = binr.ReadByte();
260         if (bt != 0x02)        //expect integer
261             return 0;
262         bt = binr.ReadByte();
263 
264         if (bt == 0x81)
265             count = binr.ReadByte();    // data size in next byte
266         else
267             if (bt == 0x82)
268             {
269                 highbyte = binr.ReadByte();    // data size in next 2 bytes
270                 lowbyte = binr.ReadByte();
271                 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
272                 count = BitConverter.ToInt32(modint, 0);
273             }
274             else
275             {
276                 count = bt;        // we already have the data size
277             }
278 
279 
280 
281         while (binr.ReadByte() == 0x00)
282         {    //remove high order zeros in data
283             count -= 1;
284         }
285         binr.BaseStream.Seek(-1, SeekOrigin.Current);        //last ReadByte wasn't a removed zero, so back up a byte
286         return count;
287     }
288 
289     #endregion
290 
291     #region 解析.net 生成的Pem
292     private static RSAParameters ConvertFromPublicKey(string pemFileConent)
293     {
294 
295         byte[] keyData = Convert.FromBase64String(pemFileConent);
296         if (keyData.Length < 162)
297         {
298             throw new ArgumentException("pem file content is incorrect.");
299         }
300         byte[] pemModulus = new byte[128];
301         byte[] pemPublicExponent = new byte[3];
302         Array.Copy(keyData, 29, pemModulus, 0, 128);
303         Array.Copy(keyData, 159, pemPublicExponent, 0, 3);
304         RSAParameters para = new RSAParameters();
305         para.Modulus = pemModulus;
306         para.Exponent = pemPublicExponent;
307         return para;
308     }
309 
310     private static RSAParameters ConvertFromPrivateKey(string pemFileConent)
311     {
312         byte[] keyData = Convert.FromBase64String(pemFileConent);
313         if (keyData.Length < 609)
314         {
315             throw new ArgumentException("pem file content is incorrect.");
316         }
317 
318         int index = 11;
319         byte[] pemModulus = new byte[128];
320         Array.Copy(keyData, index, pemModulus, 0, 128);
321 
322         index += 128;
323         index += 2;//141
324         byte[] pemPublicExponent = new byte[3];
325         Array.Copy(keyData, index, pemPublicExponent, 0, 3);
326 
327         index += 3;
328         index += 4;//148
329         byte[] pemPrivateExponent = new byte[128];
330         Array.Copy(keyData, index, pemPrivateExponent, 0, 128);
331 
332         index += 128;
333         index += ((int)keyData[index + 1] == 64 ? 2 : 3);//279
334         byte[] pemPrime1 = new byte[64];
335         Array.Copy(keyData, index, pemPrime1, 0, 64);
336 
337         index += 64;
338         index += ((int)keyData[index + 1] == 64 ? 2 : 3);//346
339         byte[] pemPrime2 = new byte[64];
340         Array.Copy(keyData, index, pemPrime2, 0, 64);
341 
342         index += 64;
343         index += ((int)keyData[index + 1] == 64 ? 2 : 3);//412/413
344         byte[] pemExponent1 = new byte[64];
345         Array.Copy(keyData, index, pemExponent1, 0, 64);
346 
347         index += 64;
348         index += ((int)keyData[index + 1] == 64 ? 2 : 3);//479/480
349         byte[] pemExponent2 = new byte[64];
350         Array.Copy(keyData, index, pemExponent2, 0, 64);
351 
352         index += 64;
353         index += ((int)keyData[index + 1] == 64 ? 2 : 3);//545/546
354         byte[] pemCoefficient = new byte[64];
355         Array.Copy(keyData, index, pemCoefficient, 0, 64);
356 
357         RSAParameters para = new RSAParameters();
358         para.Modulus = pemModulus;
359         para.Exponent = pemPublicExponent;
360         para.D = pemPrivateExponent;
361         para.P = pemPrime1;
362         para.Q = pemPrime2;
363         para.DP = pemExponent1;
364         para.DQ = pemExponent2;
365         para.InverseQ = pemCoefficient;
366         return para;
367     }
368     #endregion
369 
370 }

 

转载于:https://www.cnblogs.com/buguge/p/6086631.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值