前言:公司项目对接了一个对数据保密性要求较高的java公司。api接口逻辑是这样的:他们提供 SHA1私钥 与 AES的秘钥。我们需要将 传递查询参数 通过SHA1 私钥加密再转换成 十六进制 字符串。传递查询参数 再通过 AES秘钥 加密转换成十六进制 字符串。
查询结果 也是一个十六进制字符串 需要转换成 byte 数组 再通过AES秘钥解密成 返回数据。
后面转换接口都需要十六进制字符串与byte数组 相互转换。这个具体得看开发者自己的接口要求了。我这边的项目要求 就是数据传递用十六进制字符串比较多。
1.十六进制字符串转换成byte数组
/// <summary> /// 十六进制字符串换成byte数组转 /// </summary> /// <param name="byteArray"></param> /// <returns></returns> private static byte[] HexStringToByteArray(string s) { s = s.Replace(" ", ""); byte[] buffer = new byte[s.Length / 2]; for (int i = 0; i < s.Length; i += 2) { buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16); } return buffer; }
2.byte数组转换成十六进制字符串
/// <summary> /// byte数组转换成十六进制字符串 /// </summary> /// <param name="byteArray"></param> /// <returns></returns> private string bytesToHexStr(byte[] byteArray) { StringBuilder sb = new StringBuilder(); foreach (byte b in byteArray) { sb.Append(b.ToString("X2")); } return sb.ToString(); }
一、privateKey私钥转换成xml
.net的RSA仅仅支持 xml格式。第一步需要将java那边提供的SHA1私钥转换成xml格式
/// <summary> /// 私钥=>十六进制字符串转换成xml /// </summary> /// <param name="privateKey"></param> /// <returns></returns> private static string RSAPrivateKeyJava2DotNet(string privateKey) { RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(HexStringToByteArray(privateKey)); return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>", Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()), Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())); }
二、c#SHA1加密
数据转换过程中 套有一个md5加密MD5Encrypt(都是按照乙方java的加密规则写的 我也觉得很繁琐)
/// <summary> /// ASYMMETRY_ALGORITHM 加密类 SHA1 /// </summary> /// <param name="signaturePrivateKey"></param> /// <param name="signatureData">请求参数</param> /// <returns></returns> private string signature(string signaturePrivateKey, string signatureData) { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); var privateJavaKey = signaturePrivateKey; var privateCSharpKey = RSAPrivateKeyJava2DotNet(privateJavaKey); rsa.FromXmlString(privateCSharpKey); var md5 = MD5Encrypt(signatureData); byte[] signatureBytes = rsa.SignData(Encoding.UTF8.GetBytes(md5), "SHA1"); var hexStr = bytesToHexStr(signatureBytes); return hexStr; }
MD5Encrypt
/// <summary> /// 用MD5加密字符串 /// </summary> /// <param name="jsonData">待加密的字符串</param> /// <returns></returns> public string MD5Encrypt(string jsonData) { MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider(); byte[] hashedDataBytes; hashedDataBytes = md5Hasher.ComputeHash(Encoding.GetEncoding("gb2312").GetBytes(jsonData)); StringBuilder tmp = new StringBuilder(); foreach (byte i in hashedDataBytes) { tmp.Append(i.ToString("x2")); } return tmp.ToString(); }
三、AES加密
/// <summary> /// AES解密 /// </summary> /// <param name="signaturePrivateKey"></param> /// <param name="signatureData"></param> /// <returns></returns> private string decrypt(string key, string str) { if (string.IsNullOrEmpty(str)) return null; Byte[] toEncryptArray = HexStringToByteArray(str); RijndaelManaged rm = new RijndaelManaged { Key = HexStringToByteArray(key), Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 }; ICryptoTransform cTransform = rm.CreateDecryptor(); Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); return Encoding.UTF8.GetString(resultArray); }
四、请求接口获取返回数据
public objcet callIntegrateService() { var date = DateTime.Now; var startTime = Convert.ToDateTime(date.ToString("yyyy-MM-dd") + " 00:00:00"); var endTime = date; var logstart = ConvertDateTimeInt(startTime); var logend = ConvertDateTimeInt(endTime); //var jsonData = "{}"; var jsonData ="{ startTime: \"" + logstart + "\",endTime:\"" + logend + "\" }"; var url = base_url + "/getProjectAttendanceDetail"; string signature = getSignatrue(jsonData); string encryptData = encrypt(secretKey, jsonData); var param = "{ clientSerial:\""+ clientSerial + "\",projectId:\"" + projectId + "\",jsonData:\"" + encryptData + "\",signature:\"" + signature + "\" }"; var result= webPost(url, param); var objresult = JsonConvert.DeserializeObject<request>(result); var response = objresult.response; var data = decrypt(secretKey, response); var objdata = JsonConvert.DeserializeObject(data); return objdata; }
五、解密返回数据
AES解密
/// <summary> /// AES解密 /// </summary> /// <param name="signaturePrivateKey"></param> /// <param name="signatureData"></param> /// <returns></returns> private string decrypt(string key, string str) { if (string.IsNullOrEmpty(str)) return null; Byte[] toEncryptArray = HexStringToByteArray(str); RijndaelManaged rm = new RijndaelManaged { Key = HexStringToByteArray(key), Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 }; ICryptoTransform cTransform = rm.CreateDecryptor(); Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length); return Encoding.UTF8.GetString(resultArray); }