非对称密钥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+0ifmEPYGuhYRTyKdd6VLFIsNqy/SO5xZitHfA7xEymJKnpEUGgDJKr5zbFbytnWs5Jjgen6TXkUh9LG/fhPGGHdUVB42pAHv5yzoyEaOnJxBAxd6UstoWTaEgbT6GUbzMr/Az25zuxw7c+skAlnUETVE5GL3tD7AgMBAAECgYEAxdNZODMctb3J9OSo93rV3vPA2prna87rVtDt4vg+MGsPtwSjZyiKcmoQCGWcK+MmHYgrwHkwihKKSv3KXZ9or3xQ2wNZGuTHLymWEzqfEfVb0igvxbe85EGwsaN3qSK62CK8vok/Bi+fZVa3UNCn0WFslUS0qn+K3SECM9I1iwECQQD+2Pl2AJGQs2bRXSsnJk0FIwjpqdpGZFPlAUYaXkuTMqpwefP/bwwiuWqq9QIt2vAAKgy5T16tpPBcGpT6cvxBAkEA7T+i1gVwrXcozTuT9oCwkF2MGBaXkv3mN9H/Pfy/oIhTsgiDxX8t+0KapAEQogvCuAOq19JvGw5e91H2g0suOwJAJOMnCIuAhl9RTJCdxGbo0wuFKL0rGPFAq28JxJtNeRrmTK16QcjDCuunouMf059TCdMMUG5Kl/u9xrcaRT4LgQJAZPiUYOnnzqvMHayhiGO0wXxOx2G2GMUeWdtx+fu7wqLCnB6rlj5OX4U1M1+QqKbAtHg7Gadhye4P1Mp5U9+HSQJBANLVzcCXyAX2D12UPTPkhcNRaCRXFp3aJGMxI4iluUC+ukAdiapohqZ7vMQyWRq/tDyiwjirqMcg/AJIuQWmPyc=-----END PRIVATE KEY-----
C# 需要的是 PKCS1 格式私钥:
-----BEGIN RSA PRIVATE KEY-----MIICXQIBAAKBgQDsLjhx/ziERPtIn5hD2BroWEU8inXelSxSLDasv0jucWYrR3wO8RMpiSp6RFBoAySq+c2xW8rZ1rOSY4Hp+k15FIfSxv34Txhh3VFQeNqQB7+cs6MhGjpycQQMXelLLaFk2hIG0+hlG8zK/wM9uc7scO3PrJAJZ1BE1RORi97Q+wIDAQABAoGBAMXTWTgzHLW9yfTkqPd61d7zwNqa52vO61bQ7eL4PjBrD7cEo2coinJqEAhlnCvjJh2IK8B5MIoSikr9yl2faK98UNsDWRrkxy8plhM6nxH1W9IoL8W3vORBsLGjd6kiutgivL6JPwYvn2VWt1DQp9FhbJVEtKp/it0hAjPSNYsBAkEA/tj5dgCRkLNm0V0rJyZNBSMI6anaRmRT5QFGGl5LkzKqcHnz/28MIrlqqvUCLdrwACoMuU9eraTwXBqU+nL8QQJBAO0/otYFcK13KM07k/aAsJBdjBgWl5L95jfR/z38v6CIU7IIg8V/LftCmqQBEKILwrgDqtfSbxsOXvdR9oNLLjsCQCTjJwiLgIZfUUyQncRm6NMLhSi9KxjxQKtvCcSbTXka5kytekHIwwrrp6LjH9OfUwnTDFBuSpf7vca3GkU+C4ECQGT4lGDp586rzB2soYhjtMF8TsdhthjFHlnbcfn7u8Kiwpweq5Y+Tl+FNTNfkKimwLR4OxmnYcnuD9TKeVPfh0kCQQDS1c3Al8gF9g9dlD0z5IXDUWgkVxad2iRjMSOIpblAvrpAHYmqaIame7zEMlkav7Q8osI4q6jHIPwCSLkFpj8n-----END RSA PRIVATE KEY-----
2.私钥格式之间的转换问题
转换工具:openssl工具:
转换参考地址: 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 finally104 {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 integer117 return 0;118 bt = binr.ReadByte();119 120 if (bt == 0x81)121 count = binr.ReadByte(); // data size in next byte122 else123 if (bt == 0x82)124 {125 highbyte = binr.ReadByte(); // data size in next 2 bytes126 lowbyte = binr.ReadByte();127 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };128 count = BitConverter.ToInt32(modint, 0);129 }130 else131 {132 count = bt; // we already have the data size133 }134 135 while (binr.ReadByte() == 0x00)136 { //remove high order zeros in data137 count -= 1;138 }139 binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte140 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 }