接着前面一篇文章C# Java间进行RSA加密解密交互,继续探讨这个问题。
在前面,虽然已经实现了C# Java间进行RSA加密解密交互,但是还是与项目中要求的有所出入。在项目中,客户端(Java)的加密是通过这么一个方法实现的:
- /**
- * RSA加密
- * @param text--待加密的明文
- * @param key--公钥,由服务器端提供的经base64编码的字符串
- * @return
- */
- public static String RSAEncryptoWithPublicKey(String text, String key) {
- String result = null;
- try {
- byte[] publicKeyByte = base64Decrypto(key);
- X509EncodedKeySpec x509 = new X509EncodedKeySpec(publicKeyByte);
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- PublicKey publicKey = keyFactory.generatePublic(x509);
- Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
- cipher.init(Cipher.ENCRYPT_MODE, publicKey);
- result = base64Encrypto(cipher.doFinal(text.getBytes()));
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- return result;
- }
/** * RSA加密 * @param text--待加密的明文 * @param key--公钥,由服务器端提供的经base64编码的字符串 * @return */ public static String RSAEncryptoWithPublicKey(String text, String key) { String result = null; try { byte[] publicKeyByte = base64Decrypto(key); X509EncodedKeySpec x509 = new X509EncodedKeySpec(publicKeyByte); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicKey = keyFactory.generatePublic(x509); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); result = base64Encrypto(cipher.doFinal(text.getBytes())); } catch (Exception e) { e.printStackTrace(); return null; } return result; }
在上一篇中的实现,需要客户端先做一次解析工作,而已经开发好的客户端是没有这一层的,所以得想个办法,在服务器端(C#)完成这项工作。但是经过多次尝试,依然未果。于是换一种方式,密钥对不由C#提供,而转而有Java提供,生成客户端需要的公钥形式,并解析公钥私钥,组装C# 的XML格式的密钥对字符串。
下面贴一下RSA密钥对生成代码(参考RSA的密钥把JAVA格式转换成C#的格式)
- import java.io.UnsupportedEncodingException;
- import java.lang.reflect.Method;
- import java.security.KeyFactory;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.NoSuchAlgorithmException;
- import java.security.PublicKey;
- import java.security.interfaces.RSAPrivateCrtKey;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.security.spec.X509EncodedKeySpec;
- import java.util.HashMap;
- /**
- * @author Administrator
- *
- */
- public class RSAJavaToCSharp {
- public static void main(String[] args) throws Exception {
- HashMap<String, Object> map = getKeys();
- RSAPublicKey publicKey = (RSAPublicKey) map.get("PUBLIC");
- RSAPrivateKey privateKey = (RSAPrivateKey) map.get("PRIVATE");
- String publicKeyString = getRSAPublicKeyAsNetFormat(publicKey.getEncoded());
- String privateKeyString = getRSAPrivateKeyAsNetFormat(privateKey.getEncoded());
- System.out.println(encodeBase64(publicKey.getEncoded()));//此处为客户端加密时需要的公钥字符串
- System.out.println(encodePublicKeyToXml(publicKey));
- System.out.println(publicKeyString);
- System.out.println(privateKeyString);
- }
- /**获取密钥对
- * @return
- * @throws NoSuchAlgorithmException
- */
- public static HashMap<String, Object> getKeys()
- throws NoSuchAlgorithmException {
- HashMap<String, Object> map = new HashMap<String, Object>();
- KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
- keyPairGen.initialize(1024);
- KeyPair keyPair = keyPairGen.generateKeyPair();
- RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
- map.put("PUBLIC", publicKey);
- map.put("PRIVATE", privateKey);
- return map;
- }
- /**
- * 私钥转换成C#格式
- * @param encodedPrivkey
- * @return
- */
- private static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivateKey) {
- try {
- StringBuffer buff = new StringBuffer(1024);
- PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(
- encodedPrivateKey);
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory
- .generatePrivate(pvkKeySpec);
- buff.append("<RSAKeyValue>");
- buff.append("<Modulus>"
- + encodeBase64(removeMSZero(pvkKey.getModulus()
- .toByteArray())) + "</Modulus>");
- buff.append("<Exponent>"
- + encodeBase64(removeMSZero(pvkKey.getPublicExponent()
- .toByteArray())) + "</Exponent>");
- buff.append("<P>"
- + encodeBase64(removeMSZero(pvkKey.getPrimeP()
- .toByteArray())) + "</P>");
- buff.append("<Q>"
- + encodeBase64(removeMSZero(pvkKey.getPrimeQ()
- .toByteArray())) + "</Q>");
- buff.append("<DP>"
- + encodeBase64(removeMSZero(pvkKey.getPrimeExponentP()
- .toByteArray())) + "</DP>");
- buff.append("<DQ>"
- + encodeBase64(removeMSZero(pvkKey.getPrimeExponentQ()
- .toByteArray())) + "</DQ>");
- buff.append("<InverseQ>"
- + encodeBase64(removeMSZero(pvkKey.getCrtCoefficient()
- .toByteArray())) + "</InverseQ>");
- buff.append("<D>"
- + encodeBase64(removeMSZero(pvkKey.getPrivateExponent()
- .toByteArray())) + "</D>");
- buff.append("</RSAKeyValue>");
- return buff.toString();
- } catch (Exception e) {
- System.err.println(e);
- return null;
- }
- }
- /**
- * 公钥转成C#格式
- * @param encodedPrivkey
- * @return
- */
- private static String getRSAPublicKeyAsNetFormat(byte[] encodedPublicKey) {
- try {
- StringBuffer buff = new StringBuffer(1024);
- //Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA public keys
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- RSAPublicKey pukKey = (RSAPublicKey) keyFactory
- .generatePublic(new X509EncodedKeySpec(encodedPublicKey));
- buff.append("<RSAKeyValue>");
- buff.append("<Modulus>"
- + encodeBase64(removeMSZero(pukKey.getModulus()
- .toByteArray())) + "</Modulus>");
- buff.append("<Exponent>"
- + encodeBase64(removeMSZero(pukKey.getPublicExponent()
- .toByteArray())) + "</Exponent>");
- buff.append("</RSAKeyValue>");
- return buff.toString();
- } catch (Exception e) {
- System.err.println(e);
- return null;
- }
- }
- /**
- * 公钥转换成C#格式
- * @param key
- * @return
- * @throws Exception
- */
- public static String encodePublicKeyToXml(PublicKey key) throws Exception {
- if (!RSAPublicKey.class.isInstance(key)) {
- return null;
- }
- RSAPublicKey pubKey = (RSAPublicKey) key;
- StringBuilder sb = new StringBuilder();
- sb.append("<RSAKeyValue>");
- sb.append("<Modulus>")
- .append(encodeBase64(removeMSZero(pubKey.getModulus()
- .toByteArray()))).append("</Modulus>");
- sb.append("<Exponent>")
- .append(encodeBase64(removeMSZero(pubKey.getPublicExponent()
- .toByteArray()))).append("</Exponent>");
- sb.append("</RSAKeyValue>");
- return sb.toString();
- }
- /**
- * @param data
- * @return
- */
- private static byte[] removeMSZero(byte[] data) {
- byte[] data1;
- int len = data.length;
- if (data[0] == 0) {
- data1 = new byte[data.length - 1];
- System.arraycopy(data, 1, data1, 0, len - 1);
- } else
- data1 = data;
- return data1;
- }
- /**
- * base64编码
- * @param input
- * @return
- * @throws Exception
- */
- public static String encodeBase64(byte[] input) throws Exception {
- Class clazz = Class
- .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
- Method mainMethod = clazz.getMethod("encode", byte[].class);
- mainMethod.setAccessible(true);
- Object retObj = mainMethod.invoke(null, new Object[] { input });
- return (String) retObj;
- }
- /**
- * base64解码
- * @param input
- * @return
- * @throws Exception
- */
- public static byte[] decodeBase64(String input) throws Exception {
- Class clazz = Class
- .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
- Method mainMethod = clazz.getMethod("decode", String.class);
- mainMethod.setAccessible(true);
- Object retObj = mainMethod.invoke(null, input);
- return (byte[]) retObj;
- }
- public static String byteToString(byte[] b)
- throws UnsupportedEncodingException {
- return new String(b, "utf-8");
- }
- }
import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; /** * @author Administrator * */ public class RSAJavaToCSharp { public static void main(String[] args) throws Exception { HashMap<String, Object> map = getKeys(); RSAPublicKey publicKey = (RSAPublicKey) map.get("PUBLIC"); RSAPrivateKey privateKey = (RSAPrivateKey) map.get("PRIVATE"); String publicKeyString = getRSAPublicKeyAsNetFormat(publicKey.getEncoded()); String privateKeyString = getRSAPrivateKeyAsNetFormat(privateKey.getEncoded()); System.out.println(encodeBase64(publicKey.getEncoded()));//此处为客户端加密时需要的公钥字符串 System.out.println(encodePublicKeyToXml(publicKey)); System.out.println(publicKeyString); System.out.println(privateKeyString); } /**获取密钥对 * @return * @throws NoSuchAlgorithmException */ public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException { HashMap<String, Object> map = new HashMap<String, Object>(); KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); map.put("PUBLIC", publicKey); map.put("PRIVATE", privateKey); return map; } /** * 私钥转换成C#格式 * @param encodedPrivkey * @return */ private static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivateKey) { try { StringBuffer buff = new StringBuffer(1024); PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec( encodedPrivateKey); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory .generatePrivate(pvkKeySpec); buff.append("<RSAKeyValue>"); buff.append("<Modulus>" + encodeBase64(removeMSZero(pvkKey.getModulus() .toByteArray())) + "</Modulus>"); buff.append("<Exponent>" + encodeBase64(removeMSZero(pvkKey.getPublicExponent() .toByteArray())) + "</Exponent>"); buff.append("<P>" + encodeBase64(removeMSZero(pvkKey.getPrimeP() .toByteArray())) + "</P>"); buff.append("<Q>" + encodeBase64(removeMSZero(pvkKey.getPrimeQ() .toByteArray())) + "</Q>"); buff.append("<DP>" + encodeBase64(removeMSZero(pvkKey.getPrimeExponentP() .toByteArray())) + "</DP>"); buff.append("<DQ>" + encodeBase64(removeMSZero(pvkKey.getPrimeExponentQ() .toByteArray())) + "</DQ>"); buff.append("<InverseQ>" + encodeBase64(removeMSZero(pvkKey.getCrtCoefficient() .toByteArray())) + "</InverseQ>"); buff.append("<D>" + encodeBase64(removeMSZero(pvkKey.getPrivateExponent() .toByteArray())) + "</D>"); buff.append("</RSAKeyValue>"); return buff.toString(); } catch (Exception e) { System.err.println(e); return null; } } /** * 公钥转成C#格式 * @param encodedPrivkey * @return */ private static String getRSAPublicKeyAsNetFormat(byte[] encodedPublicKey) { try { StringBuffer buff = new StringBuffer(1024); //Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA public keys KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKey pukKey = (RSAPublicKey) keyFactory .generatePublic(new X509EncodedKeySpec(encodedPublicKey)); buff.append("<RSAKeyValue>"); buff.append("<Modulus>" + encodeBase64(removeMSZero(pukKey.getModulus() .toByteArray())) + "</Modulus>"); buff.append("<Exponent>" + encodeBase64(removeMSZero(pukKey.getPublicExponent() .toByteArray())) + "</Exponent>"); buff.append("</RSAKeyValue>"); return buff.toString(); } catch (Exception e) { System.err.println(e); return null; } } /** * 公钥转换成C#格式 * @param key * @return * @throws Exception */ public static String encodePublicKeyToXml(PublicKey key) throws Exception { if (!RSAPublicKey.class.isInstance(key)) { return null; } RSAPublicKey pubKey = (RSAPublicKey) key; StringBuilder sb = new StringBuilder(); sb.append("<RSAKeyValue>"); sb.append("<Modulus>") .append(encodeBase64(removeMSZero(pubKey.getModulus() .toByteArray()))).append("</Modulus>"); sb.append("<Exponent>") .append(encodeBase64(removeMSZero(pubKey.getPublicExponent() .toByteArray()))).append("</Exponent>"); sb.append("</RSAKeyValue>"); return sb.toString(); } /** * @param data * @return */ private static byte[] removeMSZero(byte[] data) { byte[] data1; int len = data.length; if (data[0] == 0) { data1 = new byte[data.length - 1]; System.arraycopy(data, 1, data1, 0, len - 1); } else data1 = data; return data1; } /** * base64编码 * @param input * @return * @throws Exception */ public static String encodeBase64(byte[] input) throws Exception { Class clazz = Class .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64"); Method mainMethod = clazz.getMethod("encode", byte[].class); mainMethod.setAccessible(true); Object retObj = mainMethod.invoke(null, new Object[] { input }); return (String) retObj; } /** * base64解码 * @param input * @return * @throws Exception */ public static byte[] decodeBase64(String input) throws Exception { Class clazz = Class .forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64"); Method mainMethod = clazz.getMethod("decode", String.class); mainMethod.setAccessible(true); Object retObj = mainMethod.invoke(null, input); return (byte[]) retObj; } public static String byteToString(byte[] b) throws UnsupportedEncodingException { return new String(b, "utf-8"); } }
为了方便在服务器端使用,初始想法是想将java文件封装为.dll文件,共C#调用,测试后,发现这样做行不通,bug提示类找不到,这是因为java代码中还导入了其他jar包的缘故。
于是,退而求其次,将上述java文件Export为可执行的jar文件,并将生成的密钥对写入相应文件中。再由C#读取,提供给客户端。
---------------------------------------------------------------------------------------------