先说下RSA概率:
公钥和私钥是通过本地openssl软件生成。
正常:
公钥加密=》私钥解密;
私钥签名=》公钥校验签名
最近做一个项目,对方用java公钥去校验签名,这边java的Demo使用私钥来加密的。
代码如下:
public class SignAccess { public String REQ_SERIAL_NO=""; public String REQ_TIME=""; public String ENV_FLAG=""; public String APP_ID=""; public String PRIVATE_KEY=""; public SignAccess(String REQ_SERIAL_NO, String REQ_TIME, String ENV_FLAG, String APP_ID,String PRIVATE_KEY) { this.REQ_SERIAL_NO = REQ_SERIAL_NO; this.REQ_TIME = REQ_TIME; this.ENV_FLAG = ENV_FLAG; this.APP_ID = APP_ID; this.PRIVATE_KEY = PRIVATE_KEY; } /** * 获取对应的sign值 * @return */ public String getSign(){ //组装输入参数map Map<String,Object> map = new HashMap<>(); map.put("REQ_SERIAL_NO", REQ_SERIAL_NO); map.put("REQ_TIME", REQ_TIME); map.put("ENV_FLAG", ENV_FLAG); map.put("APP_ID", APP_ID); //给map排序后转换为字符串 StringBuilder sb = new StringBuilder(); final Map<String,Object> sortMap = new TreeMap(new Comparator<String>() { @Override public int compare(String str1, String str2) { return str1.compareTo(str2); } }); sortMap.putAll(map); for (final Map.Entry<String,Object> entry : sortMap.entrySet()) { sb = sb.append(entry.getKey()).append(entry.getValue()); } String dest = sb.toString(); //sha256加密 String strDes=encrypt(dest); //私钥加密 byte[] enBytes = null; byte[] data; try { data = strDes.getBytes("UTF-8"); final Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(PRIVATE_KEY)); for (int i = 0; i < data.length; i += 128) { final byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + 128)); enBytes = ArrayUtils.addAll(enBytes, doFinal); } try { return Base64.encodeBase64String(enBytes); } catch (final Exception e) { System.err.println("Base64出错"); } } catch (final Exception e) { System.err.println("私钥加密出错"); } return ""; } /** * 秘钥转换方法 * @param key * @return */ public PrivateKey getPrivateKey(String key){ java.security.Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider() ); byte[] keyBytes; keyBytes = Base64.decodeBase64(key); final PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance("RSA"); final PrivateKey privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } catch (final Exception e) { System.err.println("获取私钥出错"); } return null; } private String encrypt(final String strSrc) { MessageDigest md = null; String strDes = null; try { // byte[] bt = strSrc.getBytes(); md = MessageDigest.getInstance("SHA-256"); // md.update(bt); try { strDes = bytesToHexString(md.digest(strSrc.getBytes("UTF-8"))); } catch (final UnsupportedEncodingException e) { System.err.println("编码失败"); } } catch (final NoSuchAlgorithmException e) { System.err.println("编码失败"); } return strDes; } /** * 转16进制 * * @param src * @return */ private String bytesToHexString(final byte[] src) { final StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { final int v = src[i] & 0xFF; final String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } public static void main(String args[]) { String privateKey="MIICWwIBAAKBgQC2TSwydOrZ0Ija3YbloMWXQP6xOIn1DUOiOHCYJkRYTk+FviR+ P6EOOSwPLFcd91k65jHZOF91pifQf6tHzFQjhc0phTGWsjpHPhGeJ6tgzSZr5xIQ mCp4xPW4x7N0Y1vciz3ZBfTZyMu2k3iHgbxT8uPeKDKD2vZhC0FEOVU0oQIDAQAB AoGAarwma2he9KaO6i4XxCxsY9GPDW3///UDK2CGM9771wQKtVCNh0lz36MDs+KP IyFmIgETII5L/dMJrp6BRylP/PsWWQAZqfoI7FQbKFWKnvTGhDxCtW7FvZOq9MhG VMA5BfdE4zBgauo9kYdqzsKxIzndE5EJg4j86pFZwn6BWb0CQQDjWnoh25AXEHhw Fo5Gd0N5aceK4uFQ5DukTUSH1y5b/z4Q5OvC3JopjUMVfDYk32C+sSw3zF9PuCK8 XmIE476rAkEAzUV/P6onzngqIiXPtpd5EuDKDM+4pvxJine7+2onY3rCtA1LFaLn laIrAQ/2/b0Ub4cJMNxID4v1WDfBYo1p4wJADe2qE87uuesBZeSL3NdLo/GODv0t TpZc7QjqzOOq7GnrtH9BzlNTgn4sAPH2IzYoKCaUjeqQYELopd+mY6RMNwJAJO8s RjhHkU7txdcn2KLIliz8LfHyN5mNYezJViNzkuKzxdHegLYfFT1on3hP6LfsxWR2 suPv01xLeOQPV7w6IQJAO/bB2Ul7hRAgyHzlBMZoVEMY4LGfd41yDzrrpNjr2JUT dsrXPbduLGGEdqE4M4uM/T+Vg3elAWM+eW7tGD2v5w=="; String reqSerialNo="1234567890"; String reqTime="1234567890"; String envFlag="0"; String appId="1234567890"; SignAccess signAccess=new SignAccess(reqSerialNo,reqTime,envFlag,appId,privateKey); System.out.println(signAccess.getSign()); } }
c#试了N多方式,没有做到签名一致。这里贴下c#的加密和签名的代码
加密解密代码:
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace RSA加密 { public class RSACSharp { public static void test() { string de = "iBILuPJFgPMxgpbgN3F2JjD6XjcqRSApjVVbvBBEBDV21Pjj7lTrfhEjSVnJX/MVoZrmX0lxsvoXTMvvVwVF7K7W5hs7Qo+aMN96yWke7wiLEM9M4pPz60A/KSckskiona67tXcqOLXb8N18TKaNCKHv0Ce+GyEKK5+MT7e1vao="; //string encrypt = RSAEncrypt("", "chenhailong"); byte[] encrypt = RSAEncrypt("APP_IDA2018030910304500031ENV_FLAG0REQ_SERIAL_NO20170310155124REQ_TIME20170310155124"); string name = RSADecrypt(encrypt); //string name = RSADecrypt(Convert.FromBase64String(de)); Console.WriteLine(encrypt.Length); Console.WriteLine(Convert.ToBase64String(encrypt)); Console.WriteLine(name); Console.ReadKey(); } /// <summary> /// RSA encrypt /// </summary> /// <param name="publickey"></param> /// <param name="content"></param> /// <returns></returns> public static byte[] RSAEncrypt(string content) { string publickey = @"<RSAKeyValue><Modulus>5m9m14XH3oqLJ8bNGw9e4rGpXpcktv9MSkHSVFVMjHbfv+SJ5v0ubqQxa5YjLN4vc49z7SVju8s0X4gZ6AzZTn06jzWOgyPRV54Q4I0DCYadWW4Ze3e+BOtwgVU1Og3qHKn8vygoj40J6U85Z/PTJu3hN1m75Zr195ju7g9v4Hk=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"; string pKey = @"-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2TSwydOrZ0Ija3YbloMWXQP6x OIn1DUOiOHCYJkRYTk+FviR+P6EOOSwPLFcd91k65jHZOF91pifQf6tHzFQjhc0p hTGWsjpHPhGeJ6tgzSZr5xIQmCp4xPW4x7N0Y1vciz3ZBfTZyMu2k3iHgbxT8uPe KDKD2vZhC0FEOVU0oQIDAQAB -----END PUBLIC KEY-----"; string pk= EncryptionHelper.RSA_KeyJavaToCsharp(pKey, false); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); byte[] cipherbytes; rsa.FromXmlString(pk); cipherbytes = rsa.Encrypt(Encoding.UTF8.GetBytes(content), false); //return Convert.ToBase64String(cipherbytes); return cipherbytes; } /// <summary> /// RSA decrypt /// </summary> /// <param name="privatekey"></param> /// <param name="content"></param> /// <returns></returns> public static string RSADecrypt(byte[] content) { string privatekey = @"<RSAKeyValue><Modulus>5m9m14XH3oqLJ8bNGw9e4rGpXpcktv9MSkHSVFVMjHbfv+SJ5v0ubqQxa5YjLN4vc49z7SVju8s0X4gZ6AzZTn06jzWOgyPRV54Q4I0DCYadWW4Ze3e+BOtwgVU1Og3qHKn8vygoj40J6U85Z/PTJu3hN1m75Zr195ju7g9v4Hk=</Modulus><Exponent>AQAB</Exponent><P>/hf2dnK7rNfl3lbqghWcpFdu778hUpIEBixCDL5WiBtpkZdpSw90aERmHJYaW2RGvGRi6zSftLh00KHsPcNUMw==</P><Q>6Cn/jOLrPapDTEp1Fkq+uz++1Do0eeX7HYqi9rY29CqShzCeI7LEYOoSwYuAJ3xA/DuCdQENPSoJ9KFbO4Wsow==</Q><DP>ga1rHIJro8e/yhxjrKYo/nqc5ICQGhrpMNlPkD9n3CjZVPOISkWF7FzUHEzDANeJfkZhcZa21z24aG3rKo5Qnw==</DP><DQ>MNGsCB8rYlMsRZ2ek2pyQwO7h/sZT8y5ilO9wu08Dwnot/7UMiOEQfDWstY3w5XQQHnvC9WFyCfP4h4QBissyw==</DQ><InverseQ>EG02S7SADhH1EVT9DD0Z62Y0uY7gIYvxX/uq+IzKSCwB8M2G7Qv9xgZQaQlLpCaeKbux3Y59hHM+KpamGL19Kg==</InverseQ><D>vmaYHEbPAgOJvaEXQl+t8DQKFT1fudEysTy31LTyXjGu6XiltXXHUuZaa2IPyHgBz0Nd7znwsW/S44iql0Fen1kzKioEL3svANui63O3o5xdDeExVM6zOf1wUUh/oldovPweChyoAdMtUzgvCbJk1sYDJf++Nr0FeNW1RB1XG30=</D></RSAKeyValue>"; string priK = @"-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQC2TSwydOrZ0Ija3YbloMWXQP6xOIn1DUOiOHCYJkRYTk+FviR+ P6EOOSwPLFcd91k65jHZOF91pifQf6tHzFQjhc0phTGWsjpHPhGeJ6tgzSZr5xIQ mCp4xPW4x7N0Y1vciz3ZBfTZyMu2k3iHgbxT8uPeKDKD2vZhC0FEOVU0oQIDAQAB AoGAarwma2he9KaO6i4XxCxsY9GPDW3///UDK2CGM9771wQKtVCNh0lz36MDs+KP IyFmIgETII5L/dMJrp6BRylP/PsWWQAZqfoI7FQbKFWKnvTGhDxCtW7FvZOq9MhG VMA5BfdE4zBgauo9kYdqzsKxIzndE5EJg4j86pFZwn6BWb0CQQDjWnoh25AXEHhw Fo5Gd0N5aceK4uFQ5DukTUSH1y5b/z4Q5OvC3JopjUMVfDYk32C+sSw3zF9PuCK8 XmIE476rAkEAzUV/P6onzngqIiXPtpd5EuDKDM+4pvxJine7+2onY3rCtA1LFaLn laIrAQ/2/b0Ub4cJMNxID4v1WDfBYo1p4wJADe2qE87uuesBZeSL3NdLo/GODv0t TpZc7QjqzOOq7GnrtH9BzlNTgn4sAPH2IzYoKCaUjeqQYELopd+mY6RMNwJAJO8s RjhHkU7txdcn2KLIliz8LfHyN5mNYezJViNzkuKzxdHegLYfFT1on3hP6LfsxWR2 suPv01xLeOQPV7w6IQJAO/bB2Ul7hRAgyHzlBMZoVEMY4LGfd41yDzrrpNjr2JUT dsrXPbduLGGEdqE4M4uM/T+Vg3elAWM+eW7tGD2v5w== -----END RSA PRIVATE KEY-----"; string pk = EncryptionHelper.RSA_KeyJavaToCsharp(priK, true); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); byte[] cipherbytes; rsa.FromXmlString(pk); cipherbytes = rsa.Decrypt(content, false); return Encoding.UTF8.GetString(cipherbytes); } } }
将java密钥转换为c#密钥方法:
///RSA秘钥 ///是否为RSA私钥:true:是|false:否 /// public static string RSA_KeyJavaToCsharp(string rsakeys, bool isPrivateKey) { try { using (var memoryStream = new MemoryStream()) using (var streamWriter = new StreamWriter(memoryStream)) using (var streamReader = new StreamReader(memoryStream)) { streamWriter.Write(rsakeys); streamWriter.Flush(); memoryStream.Position = 0; var pemReader = new PemReader(streamReader); object keys = pemReader.ReadObject(); RSA rsaservice = isPrivateKey ? GetPrivateRSACSharp(keys) : GetPublicRSACsharp(keys); return rsaservice.ToXmlString(isPrivateKey); } } catch (Exception ex) { throw new Exception("Asymmetric cipher key is error"); } } /// /// 传入RSA秘钥对象返回读取秘钥后的RSA对象 /// ///RSA私钥 /// private static RSA GetPrivateRSACSharp(object rsakeys) { //根据传入对象 强制转化为需要的对象 提供已经读取私钥的RSA对象 if ((rsakeys as RsaPrivateCrtKeyParameters) != null) return DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)rsakeys); var keys = (AsymmetricCipherKeyPair)rsakeys; return DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)keys.Private); } /// /// 传入RSA秘钥对象返回读取秘钥后的RSA对象 /// ///RSA公钥 /// private static RSA GetPublicRSACsharp(object rsakeys) { //提供已经读取公钥钥的RSA对象 var keys = (RsaKeyParameters)rsakeys; return DotNetUtilities.ToRSA(keys); }
签名的方法:
/// /// RSA C# 填充签名 /// ///私钥 ///待签名字符串 ///编码对象 ///加密算法 /// public static string RSA_GetSignCsharp(string privateKey, string body, Encoding encoding, EncryptType encryptType = EncryptType.MD5) { try { using (RSACryptoServiceProvider rsaservice = new RSACryptoServiceProvider()) { rsaservice.FromXmlString(privateKey); RSAPKCS1SignatureFormatter rsasignformatter = new RSAPKCS1SignatureFormatter(rsaservice); rsasignformatter.SetHashAlgorithm(encryptType.ToString()); encoding = encoding ?? Encoding.UTF8; byte[] hashBytes = GetComputeHash(body, encoding, encryptType); byte[] signBytes = rsasignformatter.CreateSignature(hashBytes); return Convert.ToBase64String(signBytes); } } catch (Exception ex) { throw ex; } } /// /// 根据编码及Hash类型计算Hash值 /// ///待计算Hash值得字符串 ///编码对象 ///Hash类型 /// public static byte[] GetComputeHash(string body, Encoding encoding, EncryptType encryptType) { encoding = encoding ?? Encoding.UTF8; byte[] sourceBytes = encoding.GetBytes(body); return GetComputeHash(sourceBytes, encryptType); }
校验签名方法:
/// /// RSA C# 验证签名 /// ///公钥 ///待验证数据 ///签名结果 ///编码 可传NULL ///签名时加密方式 可传NULL /// public static bool RSA_GetVerifyCsharp(string publicKey, string body, string signature, Encoding encoding, EncryptType encryptType = EncryptType.MD5) { try { using (RSACryptoServiceProvider rsaservice = new RSACryptoServiceProvider()) { rsaservice.FromXmlString(publicKey);//加载公钥 RSAPKCS1SignatureDeformatter rsasignformatter = new RSAPKCS1SignatureDeformatter(rsaservice); rsasignformatter.SetHashAlgorithm(encryptType.ToString());//设置算法 encoding = encoding ?? Encoding.UTF8; var dataBytes = GetComputeHash(body, encoding, encryptType); var signBytes = Convert.FromBase64String(signature); return rsasignformatter.VerifySignature(dataBytes, signBytes); } } catch (Exception ex) { throw ex; } }
最后按照java代码来翻译代码也没有成功,就用IKVM将jar包转换为dll终于达到目的。
第一步:将java代码打包,我这里用的idea打的包,百度下都有,这里不重复介绍。
https://www.cnblogs.com/qifengshi/p/6036870.html
https://jingyan.baidu.com/article/7e4409531fbf292fc1e2ef51.html
第二步:将jar包转换为dll。
转的步骤:https://www.cnblogs.com/rucwxb/p/7494586.html
这里要注意下:IKVM一定要用最新版本8.1.7版本,才能转java8,开始用的7.2版本,怎么转引用包都出问题。
第三步:将dll引用。