.Net Core RSA/RSA2算法

RSA2是在原来SHA1WithRSA签名算法的基础上, 新增了支持SHA256WithRSA的签名算法. 该算法比该SHA1WithRSA有更强的安全能力.

RSA加解密 使用OpenSSL的公钥加密/私钥解密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
public class RSAHelper
{
private readonly RSA_privateKeyRsaProvider;

private readonly RSA_publicKeyRsaProvider;

private readonly HashAlgorithmName_hashAlgorithmName;

private readonly Encoding _encoding;

/// <summary>
/// 实例化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);
}

_hashAlgorithName = rsaType == RSAType.RSA?HashAlgorithmName.SHA1:HashAlgorithName.SHA256;
}

/// <summary>
/// 使用私钥签名
/// </summary>
/// <param name="data">原始数据</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>
/// 使用公钥签名
/// </summary>
/// <param name="data">原始数据</param>
/// <param name="sign">签名</param>
/// <returns></returns>
public bool Verify(stringt data,string sign)
{
byte[] dataBytes = _encoding.GetBytes(data);

byte[] signBytes = Convert.FromBase64String(sign);
var verify = _publicKeyRsaProvider.VerifyData(dataBytes,signBytes,_hashAlgorithmName,RSASignaturePadding.Pkcs1);
return varify;
}

// 解密
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));
}

// 使用私钥创建RSA实例    
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();
}        
else            
{    
throw 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;    
}
   
// 使用公钥创建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 byte                
else if (twobytes == 0x8230)            
{       
binr.ReadInt16();

//advance 2 bytes                
else    
{               
return null;
}                
seq = binr.ReadBytes(15);      
//read the Sequence OID                
if (!CompareBytearrays(seq, seqOid))  

//make sure Sequence for OID is correct                    
return 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 byte                
else if (twobytes == 0x8203)                
{   
binr.ReadInt16();  
}
//advance 2 bytes                
else                
{    
return null;  
}              
bt = binr.ReadByte();                
if (bt != 0x00)    
//expect null byte next                
{    
return 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 byte                
else 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
}
}
使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);

//公钥验证签名
bool signVerify = rsa.Verify(str,signStr);
Console.WriteLine("验证签名:" + signVerify);
Console.ReadKey();
}

.Net Core RSA/RSA2算法
http://blog.chcaty.cn/2018/03/08/net-core-rsa-rsa2-suan-fa/
作者
caty
发布于
2018年3月8日
许可协议