-(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 /// 8 /// 类名:RSAFromPkcs8 9 /// 功能:RSA解密、签名、验签 10 /// 详细:该类对Java生成的密钥进行解密和签名以及验签专用类,不需要修改 11 /// 版本:1.0 12 /// 日期:2013-09-30 13 /// 说明: 14 /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 15 /// 16 public sealed class RSAFromPkcs8 17 { 18 /// 19 /// 签名 20 /// 21 /// 待签名字符串 22 /// 私钥 23 /// 编码格式 24 /// 签名后字符串 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 /// 36 /// 验签 37 /// 38 /// 待验签字符串 39 /// 签名 40 /// 公钥 41 /// 编码格式 42 /// true(通过),false(不通过) 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 /// 58 /// 解密 59 /// 60 /// 加密字符串 61 /// 私钥 62 /// 编码格式 63 /// 明文 64 public static string decryptData(string resData, string privateKey, string input_charset) 65 { 66 byte[] DataToDecrypt = Convert.FromBase64String(resData); 67 List result = new List(); 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 else102 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 reading113 byte bt = 0;114 ushort twobytes = 0;115 116 try117 {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 byte121 else if (twobytes == 0x8230)122 binr.ReadInt16(); //advance 2 bytes123 else124 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 OID136 if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct137 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 count144 if (bt == 0x81)145 binr.ReadByte();146 else147 if (bt == 0x82)148 binr.ReadUInt16();149 //------ at this stage, the remaining sequence should be the RSA private key150 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 reading186 byte bt = 0;187 ushort twobytes = 0;188 int elems = 0;189 try190 {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 byte194 else if (twobytes == 0x8230)195 binr.ReadInt16(); //advance 2 bytes196 else197 return null;198 199 twobytes = binr.ReadUInt16();200 if (twobytes != 0x0102) //version number201 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 integer261 return 0;262 bt = binr.ReadByte();263 264 if (bt == 0x81)265 count = binr.ReadByte(); // data size in next byte266 else267 if (bt == 0x82)268 {269 highbyte = binr.ReadByte(); // data size in next 2 bytes270 lowbyte = binr.ReadByte();271 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };272 count = BitConverter.ToInt32(modint, 0);273 }274 else275 {276 count = bt; // we already have the data size277 }278 279 280 281 while (binr.ReadByte() == 0x00)282 { //remove high order zeros in data283 count -= 1;284 }285 binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte286 return count;287 }288 289 #endregion290 291 #region 解析- 生成的Pem292 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;//141324 byte[] pemPublicExponent = new byte[3];325 Array.Copy(keyData, index, pemPublicExponent, 0, 3);326 327 index += 3;328 index += 4;//148329 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);//279334 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);//346339 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/413344 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/480349 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/546354 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 #endregion369 370
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~