接着前面一篇文章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;
}
在上一篇中的實現,需要客戶端先做一次解析工作,而已經開發好的客戶端是沒有這一層的,所以得想個辦法,在服務器端(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");
}
}
爲了方便在服務器端使用,初始想法是想將java文件封裝爲.dll文件,共C#調用,測試後,發現這樣做行不通,bug提示類找不到,這是因爲java代碼中還導入了其他jar包的緣故。
於是,退而求其次,將上述java文件Export爲可執行的jar文件,並將生成的密鑰對寫入相應文件中。再由C#讀取,提供給客戶端。
---------------------------------------------------------------------------------------------