https://www.cnblogs.com/wuweimin/p/7839335.html
#region RSA签名
///
/// 私钥加密
///
///
///
private string SignWhithsha1Withrsa(string contentForSign) {
string result = "";
try {
RSACryptoServiceProvider tMerchantKey = DecodeRSAPrivateKey(private_key);
//将传递需要加签的字符串进行base64操作
byte[] base64 = Encoding.UTF8.GetBytes(contentForSign);
//签名
using (var sh = SHA1.Create()) {
byte[] tSigned = tMerchantKey.SignData(base64, sh);
result = Convert.ToBase64String(tSigned);
}
return result;
} catch (Exception e) {
Log("私钥加密失败,请检查证书路径及密码:" + e.Message);
return "";
}
}
///
/// RSA私钥格式转换
///
///
///
private static RSACryptoServiceProvider DecodeRSAPrivateKey(string privateKey) {
var privateKeyBits = System.Convert.FromBase64String(privateKey);
var RSA = new RSACryptoServiceProvider();
var RSAparams = 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()");
RSAparams.Modulus = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.Exponent = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.D = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.P = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.Q = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.DP = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.DQ = binr.ReadBytes(GetIntegerSize(binr));
RSAparams.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
}
RSA.ImportParameters(RSAparams);
return RSA;
}
private static int GetIntegerSize(BinaryReader binr) {
byte bt = 0;
byte lowbyte = 0x00;
byte highbyte = 0x00;
int count = 0;
bt = binr.ReadByte();
if (bt != 0x02)
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte();
else
if (bt == 0x82) {
highbyte = binr.ReadByte();
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;
}
#endregion
非对称密钥RSA算法加解密在C#和Java之间交互的问题,这两天看了很多其他人写的文章,碰到了几个问题,最终解决问题。
参考地址:http://xw-z1985.iteye.com/blog/1837376
需求目的:完成c#请求端RSA加密(签名)问题,客户端采用C#开发,服务器端采用Java开发。服务器端给客户端提供私钥,进行数据加密(签名),客户端加密(签名)后提数据提交给服务器,服务器用公钥对数据解密,进行验证。
解决过程碰到的问题:
1.JAVA 需要的 RSA私钥 格式和 C# 需要的 RSA私钥 不一致。
JAVA 需要是 PKCS8格式私钥:
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOwuOHH/OIRE+0if
mEPYGuhYRTyKdd6VLFIsNqy/SO5xZitHfA7xEymJKnpEUGgDJKr5zbFbytnWs5Jj
gen6TXkUh9LG/fhPGGHdUVB42pAHv5yzoyEaOnJxBAxd6UstoWTaEgbT6GUbzMr/
Az25zuxw7c+skAlnUETVE5GL3tD7AgMBAAECgYEAxdNZODMctb3J9OSo93rV3vPA
2prna87rVtDt4vg+MGsPtwSjZyiKcmoQCGWcK+MmHYgrwHkwihKKSv3KXZ9or3xQ
2wNZGuTHLymWEzqfEfVb0igvxbe85EGwsaN3qSK62CK8vok/Bi+fZVa3UNCn0WFs
lUS0qn+K3SECM9I1iwECQQD+2Pl2AJGQs2bRXSsnJk0FIwjpqdpGZFPlAUYaXkuT
MqpwefP/bwwiuWqq9QIt2vAAKgy5T16tpPBcGpT6cvxBAkEA7T+i1gVwrXcozTuT
9oCwkF2MGBaXkv3mN9H/Pfy/oIhTsgiDxX8t+0KapAEQogvCuAOq19JvGw5e91H2
g0suOwJAJOMnCIuAhl9RTJCdxGbo0wuFKL0rGPFAq28JxJtNeRrmTK16QcjDCuun
ouMf059TCdMMUG5Kl/u9xrcaRT4LgQJAZPiUYOnnzqvMHayhiGO0wXxOx2G2GMUe
Wdtx+fu7wqLCnB6rlj5OX4U1M1+QqKbAtHg7Gadhye4P1Mp5U9+HSQJBANLVzcCX
yAX2D12UPTPkhcNRaCRXFp3aJGMxI4iluUC+ukAdiapohqZ7vMQyWRq/tDyiwjir
qMcg/AJIuQWmPyc=
-----END PRIVATE KEY-----
C# 需要的是 PKCS1 格式私钥:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDsLjhx/ziERPtIn5hD2BroWEU8inXelSxSLDasv0jucWYrR3wO
8RMpiSp6RFBoAySq+c2xW8rZ1rOSY4Hp+k15FIfSxv34Txhh3VFQeNqQB7+cs6Mh
GjpycQQMXelLLaFk2hIG0+hlG8zK/wM9uc7scO3PrJAJZ1BE1RORi97Q+wIDAQAB
AoGBAMXTWTgzHLW9yfTkqPd61d7zwNqa52vO61bQ7eL4PjBrD7cEo2coinJqEAhl
nCvjJh2IK8B5MIoSikr9yl2faK98UNsDWRrkxy8plhM6nxH1W9IoL8W3vORBsLGj
d6kiutgivL6JPwYvn2VWt1DQp9FhbJVEtKp/it0hAjPSNYsBAkEA/tj5dgCRkLNm
0V0rJyZNBSMI6anaRmRT5QFGGl5LkzKqcHnz/28MIrlqqvUCLdrwACoMuU9eraTw
XBqU+nL8QQJBAO0/otYFcK13KM07k/aAsJBdjBgWl5L95jfR/z38v6CIU7IIg8V/
LftCmqQBEKILwrgDqtfSbxsOXvdR9oNLLjsCQCTjJwiLgIZfUUyQncRm6NMLhSi9
KxjxQKtvCcSbTXka5kytekHIwwrrp6LjH9OfUwnTDFBuSpf7vca3GkU+C4ECQGT4
lGDp586rzB2soYhjtMF8TsdhthjFHlnbcfn7u8Kiwpweq5Y+Tl+FNTNfkKimwLR4
OxmnYcnuD9TKeVPfh0kCQQDS1c3Al8gF9g9dlD0z5IXDUWgkVxad2iRjMSOIpblA
vrpAHYmqaIame7zEMlkav7Q8osI4q6jHIPwCSLkFpj8n
-----END RSA PRIVATE KEY-----
2.私钥格式之间的转换问题
转换工具:openssl工具:http://www.slproweb.com/products/Win32OpenSSL.html
转换参考地址: http://blog.csdn.net/hanzengyi/article/details/78029104
java 代码 , 注意这里的私钥:是Pem私钥文件中去除头(-----BEGIN PRIVATE KEY-----)和尾(-----END PRIVATE KEY-----)以及换行符后的字符串
1 /**
2 * @data: 待加密的字符串
3 * @privateKey: 私钥
4 */
5 public static String sign(byte[] data, String privateKey) throws Exception {
6
7 byte[] keyBytes = new BASE64Decoder().decodeBuffer(privateKey);
8 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
9
10 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
11
12 PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
13
14 Signature signature = Signature.getInstance("SHA1withRSA");
15 signature.initSign(priKey);
16 signature.update(data);
17
18 return byte2hex(signature.sign());
19 }
c# 代码,注意这里的私钥:是Pem私钥文件中去除头(-----BEGIN RSA PRIVATE KEY-----)和尾(-----END RSA PRIVATE KEY-----)以及换行符后的字符串
1 ///
2 /// 签名
3 ///
4 /// 待加密的字符串
5 /// 私钥
6 ///
7 public static string Sign(string data, string privateKey)
8 {
9 RSACryptoServiceProvider rsaCsp = LoadCertificate(privateKey);
10 byte[] dataBytes = Encoding.UTF8.GetBytes(data);
11 byte[] signatureBytes = rsaCsp.SignData(dataBytes, "SHA1");
12 return Hex_2To16(signatureBytes);
13 }
14
15 private static RSACryptoServiceProvider LoadCertificate(string privateKey)
16 {
17 byte[] res = res = Convert.FromBase64String(privateKey);
18 try
19 {
20 RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(res);
21 return rsa;
22 }
23 catch (Exception ex)
24 {
25 }
26 return null;
27 }
28
29 private static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
30 {
31 byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
32
33 // --------- Set up stream to decode the asn.1 encoded RSA private key ------
34 MemoryStream mem = new MemoryStream(privkey);
35 BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading
36 byte bt = 0;
37 ushort twobytes = 0;
38 int elems = 0;
39 try
40 {
41 twobytes = binr.ReadUInt16();
42 if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
43 binr.ReadByte(); //advance 1 byte
44 else if (twobytes == 0x8230)
45 binr.ReadInt16(); //advance 2 bytes
46 else
47 return null;
48
49 twobytes = binr.ReadUInt16();
50 if (twobytes != 0x0102) //version number
51 return null;
52 bt = binr.ReadByte();
53 if (bt != 0x00)
54 return null;
55
56
57 //------ all private key components are Integer sequences ----
58 elems = GetIntegerSize(binr);
59 MODULUS = binr.ReadBytes(elems);
60
61 elems = GetIntegerSize(binr);
62 E = binr.ReadBytes(elems);
63
64 elems = GetIntegerSize(binr);
65 D = binr.ReadBytes(elems);
66
67 elems = GetIntegerSize(binr);
68 P = binr.ReadBytes(elems);
69
70 elems = GetIntegerSize(binr);
71 Q = binr.ReadBytes(elems);
72
73 elems = GetIntegerSize(binr);
74 DP = binr.ReadBytes(elems);
75
76 elems = GetIntegerSize(binr);
77 DQ = binr.ReadBytes(elems);
78
79 elems = GetIntegerSize(binr);
80 IQ = binr.ReadBytes(elems);
81
82
83 // ------- create RSACryptoServiceProvider instance and initialize with public key -----
84 CspParameters CspParameters = new CspParameters();
85 CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
86 RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
87 RSAParameters RSAparams = new RSAParameters();
88 RSAparams.Modulus = MODULUS;
89 RSAparams.Exponent = E;
90 RSAparams.D = D;
91 RSAparams.P = P;
92 RSAparams.Q = Q;
93 RSAparams.DP = DP;
94 RSAparams.DQ = DQ;
95 RSAparams.InverseQ = IQ;
96 RSA.ImportParameters(RSAparams);
97 return RSA;
98 }
99 catch (Exception ex)
100 {
101 return null;
102 }
103 finally
104 {
105 binr.Close();
106 }
107 }
108
109 private static int GetIntegerSize(BinaryReader binr)
110 {
111 byte bt = 0;
112 byte lowbyte = 0x00;
113 byte highbyte = 0x00;
114 int count = 0;
115 bt = binr.ReadByte();
116 if (bt != 0x02) //expect integer
117 return 0;
118 bt = binr.ReadByte();
119
120 if (bt == 0x81)
121 count = binr.ReadByte(); // data size in next byte
122 else
123 if (bt == 0x82)
124 {
125 highbyte = binr.ReadByte(); // data size in next 2 bytes
126 lowbyte = binr.ReadByte();
127 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
128 count = BitConverter.ToInt32(modint, 0);
129 }
130 else
131 {
132 count = bt; // we already have the data size
133 }
134
135 while (binr.ReadByte() == 0x00)
136 { //remove high order zeros in data
137 count -= 1;
138 }
139 binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
140 return count;
141 }
142
143
144 ///
145 /// 2进制转16进制
146 ///
147 public static String Hex_2To16(Byte[] bytes)
148 {
149 String hexString = String.Empty;
150 Int32 iLength = 65535;
151 if (bytes != null)
152 {
153 StringBuilder strB = new StringBuilder();
154
155 if (bytes.Length < iLength)
156 {
157 iLength = bytes.Length;
158 }
159
160 for (int i = 0; i < iLength; i++)
161 {
162 strB.Append(bytes[i].ToString("X2"));
163 }
164 hexString = strB.ToString();
165 }
166 return hexString;
167 }