1 using System;
2 using System.Text;
3 using System.Security.Cryptography;
4 using System.Web;
5 using System.IO;
6
7 namespace Aop.Api.Util
8 {
9 /// <summary>
10 /// RSA签名工具类。
11 /// </summary>
12 public class RSAUtil
13 {
14
15 public static string RSASign(string data, string privateKeyPem)
16 {
17 RSACryptoServiceProvider rsaCsp = LoadCertificateFile(privateKeyPem);
18 byte[] dataBytes = Encoding.UTF8.GetBytes(data);
19 byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1");
20 return Convert.ToBase64String(signatureBytes);
21 }
22
23 private static byte[] GetPem(string type, byte[] data)
24 {
25 string pem = Encoding.UTF8.GetString(data);
26 string header = String.Format("-----BEGIN {0}-----\\n", type);
27 string footer = String.Format("-----END {0}-----", type);
28 int start = pem.IndexOf(header) + header.Length;
29 int end = pem.IndexOf(footer, start);
30 string base64 = pem.Substring(start, (end - start));
31 return Convert.FromBase64String(base64);
32 }
33
34 private static RSACryptoServiceProvider LoadCertificateFile(string filename)
35 {
36 using (System.IO.FileStream fs = System.IO.File.OpenRead(filename))
37 {
38 byte[] data = new byte[fs.Length];
39 byte[] res = null;
40 fs.Read(data, 0, data.Length);
41 if (data[0] != 0x30)
42 {
43 res = GetPem("RSA PRIVATE KEY", data);
44 }
45 try
46 {
47 RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(res);
48 return rsa;
49 }
50 catch (Exception ex)
51 {
52 }
53 return null;
54 }
55 }
56
57 private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
58 {
59 byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
60
61 // --------- Set up stream to decode the asn.1 encoded RSA private key ------
62 MemoryStream mem = new MemoryStream(privkey);
63 BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
64 byte bt = 0;
65 ushort twobytes = 0;
66 int elems = 0;
67 try
68 {
69 twobytes = binr.ReadUInt16();
70 if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
71 binr.ReadByte(); //advance 1 byte
72 else if (twobytes == 0x8230)
73 binr.ReadInt16(); //advance 2 bytes
74 else
75 return null;
76
77 twobytes = binr.ReadUInt16();
78 if (twobytes != 0x0102) //version number
79 return null;
80 bt = binr.ReadByte();
81 if (bt != 0x00)
82 return null;
83
84
85 //------ all private key components are Integer sequences ----
86 elems = GetIntegerSize(binr);
87 MODULUS = binr.ReadBytes(elems);
88
89 elems = GetIntegerSize(binr);
90 E = binr.ReadBytes(elems);
91
92 elems = GetIntegerSize(binr);
93 D = binr.ReadBytes(elems);
94
95 elems = GetIntegerSize(binr);
96 P = binr.ReadBytes(elems);
97
98 elems = GetIntegerSize(binr);
99 Q = binr.ReadBytes(elems);
100
101 elems = GetIntegerSize(binr);
102 DP = binr.ReadBytes(elems);
103
104 elems = GetIntegerSize(binr);
105 DQ = binr.ReadBytes(elems);
106
107 elems = GetIntegerSize(binr);
108 IQ = binr.ReadBytes(elems);
109
110
111 // ------- create RSACryptoServiceProvider instance and initialize with public key -----
112 CspParameters CspParameters = new CspParameters();
113 CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
114 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
115 RSAParameters RSAparams = new RSAParameters();
116 RSAparams.Modulus = MODULUS;
117 RSAparams.Exponent = E;
118 RSAparams.D = D;
119 RSAparams.P = P;
120 RSAparams.Q = Q;
121 RSAparams.DP = DP;
122 RSAparams.DQ = DQ;
123 RSAparams.InverseQ = IQ;
124 RSA.ImportParameters(RSAparams);
125 return RSA;
126 }
127 catch (Exception ex)
128 {
129 return null;
130 }
131 finally
132 {
133 binr.Close();
134 }
135 }
136
137 private static int GetIntegerSize(BinaryReader binr)
138 {
139 byte bt = 0;
140 byte lowbyte = 0x00;
141 byte highbyte = 0x00;
142 int count = 0;
143 bt = binr.ReadByte();
144 if (bt != 0x02) //expect integer
145 return 0;
146 bt = binr.ReadByte();
147
148 if (bt == 0x81)
149 count = binr.ReadByte(); // data size in next byte
150 else
151 if (bt == 0x82)
152 {
153 highbyte = binr.ReadByte(); // data size in next 2 bytes
154 lowbyte = binr.ReadByte();
155 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
156 count = BitConverter.ToInt32(modint, 0);
157 }
158 else
159 {
160 count = bt; // we already have the data size
161 }
162
163 while (binr.ReadByte() == 0x00)
164 { //remove high order zeros in data
165 count -= 1;
166 }
167 binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn‘t a removed zero, so back up a byte
168 return count;
169 }
170 }
171 }