C# Java间进行RSA加密解密交互 .

这里,讲一下RSA算法加解密在C#Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益,但没能解决我的实际问题,终于,还是被我捣鼓出来了。

首先,介绍一下写这代码的目的:完成webService验证问题,服务器端采用C#开发,客户端采用Java开发。服务器端给客户端提供公钥,已进行数据加密,客户端加密后提数据提交给服务器,服务器用私钥对数据解密,进行验证。 

这里遇到的主要问题是C# RSACryptoServiceProvider类产生的公钥、私钥都是xml字符串数据,而java RSA算法要求的 Modulus、Exponent都是BigInteger类型,两者间的转换才是问题所在。 

关于Java 和 C#各自独立的进行RSA加密解密,大家可以看整两篇文章,java RSA加密解密实现() 和 C#RSA加密解密和签名与验证的实现 

接下来讲一下实现步骤:

首先由C# RSACryptoServiceProvider类生成公钥、私钥

  1. /// <summary>   
  2.        /// 生成公钥、私钥   
  3.        /// </summary>   
  4.        /// <returns>公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"</returns>   
  5.        public Dictionary<stringstring> createKeyPair()  
  6.        {  
  7.            Dictionary<stringstring> keyPair = new Dictionary<stringstring>();  
  8.            RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);  
  9.            keyPair.Add("PUBLIC", provider.ToXmlString(false));  
  10.            keyPair.Add("PRIVATE", provider.ToXmlString(true));  
  11.            return keyPair;  
  12.        }  
 /// <summary>
        /// 生成公钥、私钥
        /// </summary>
        /// <returns>公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"</returns>
        public Dictionary<string, string> createKeyPair()
        {
            Dictionary<string, string> keyPair = new Dictionary<string, string>();
            RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);
            keyPair.Add("PUBLIC", provider.ToXmlString(false));
            keyPair.Add("PRIVATE", provider.ToXmlString(true));
            return keyPair;
        }

如此处生成的公钥为

  1. <RSAKeyValue>  
  2.     <Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=  
  3.     </Modulus>  
  4.     <Exponent>AQAB</Exponent>  
  5. </RSAKeyValue>  
<RSAKeyValue>
	<Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=
	</Modulus>
	<Exponent>AQAB</Exponent>
</RSAKeyValue>
在客户端(Java)对C#提供的公钥提取Modulus和Exponent
  1. /** 
  2.      * 返回包含模数modulus和指数exponent的haspMap 
  3.      * @return 
  4.      * @throws MalformedURLException 
  5.      * @throws DocumentException 
  6.      */  
  7.     public static HashMap<String,String> rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{  
  8.         HashMap<String ,String> map = new HashMap<String, String>();   
  9.         Document doc = DocumentHelper.parseText(xmlPublicKey);  
  10.         String mudulus = (String) doc.getRootElement().element("Modulus").getData();  
  11.         String exponent = (String) doc.getRootElement().element("Exponent").getData();  
  12.         map.put("mudulus", mudulus);  
  13.         map.put("exponent", exponent);  
  14.         return map;  
  15.     }  
/**
	 * 返回包含模数modulus和指数exponent的haspMap
	 * @return
	 * @throws MalformedURLException
	 * @throws DocumentException
	 */
	public static HashMap<String,String> rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{
    	HashMap<String ,String> map = new HashMap<String, String>(); 
		Document doc = DocumentHelper.parseText(xmlPublicKey);
		String mudulus = (String) doc.getRootElement().element("Modulus").getData();
		String exponent = (String) doc.getRootElement().element("Exponent").getData();
		map.put("mudulus", mudulus);
		map.put("exponent", exponent);
		return map;
	}

用ModulusExponent产生公钥RSAPublicKeyjava

这里有个关键步骤先对MudolusExponent进行Base64解码,这个是由于C#生成的密钥对,其参数已经过Base64编码成String类型,而java RSA参数是未经base64编码的byte[]类型

至于Base64编码、解码方法,参考这篇文章,java 编码和解码,想详细。

  1. public static byte[] decodeBase64(String input) throws Exception{    
  2.         Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");    
  3.         Method mainMethod= clazz.getMethod("decode", String.class);    
  4.         mainMethod.setAccessible(true);    
  5.          Object retObj=mainMethod.invoke(null, input);    
  6.          return (byte[])retObj;    
  7.     }  
  8.       
  9.     /** 
  10.      * 返回RSA公钥 
  11.      * @param modules 
  12.      * @param exponent 
  13.      * @return 
  14.      */  
  15.     public static PublicKey getPublicKey(String modulus, String exponent){  
  16.         try {   
  17.             byte[] m = decodeBase64(modulus);  
  18.             byte[] e = decodeBase64(exponent);  
  19.             BigInteger b1 = new BigInteger(1,m);    
  20.             BigInteger b2 = new BigInteger(1,e);    
  21.             KeyFactory keyFactory = KeyFactory.getInstance("RSA");    
  22.             RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);    
  23.             return (RSAPublicKey) keyFactory.generatePublic(keySpec);    
  24.         } catch (Exception e) {    
  25.             e.printStackTrace();    
  26.             return null;    
  27.         }     
  28.     }  
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;  
    }
	
	/**
	 * 返回RSA公钥
	 * @param modules
	 * @param exponent
	 * @return
	 */
	public static PublicKey getPublicKey(String modulus, String exponent){
		try { 
			byte[] m = decodeBase64(modulus);
			byte[] e = decodeBase64(exponent);
            BigInteger b1 = new BigInteger(1,m);  
            BigInteger b2 = new BigInteger(1,e);  
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);  
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);  
        } catch (Exception e) {  
            e.printStackTrace();  
            return null;  
        }	
	}

获得公钥后就可以进行RSA加密处理了,这里还有一点需要提的是,RSA加密解密都有最大长度限制,加密最大长度为117字节,解密最大长度是128字节,此外,此处加密得到的数据是经过Base64编码处理的

  1. public static String encrypt(byte[] source, PublicKey publicKey) throws Exception   {  
  2.         String encryptData ="";  
  3.         try {  
  4.             Cipher cipher = Cipher.getInstance("RSA");  
  5.             cipher.init(Cipher.ENCRYPT_MODE, publicKey);  
  6.             int length = source.length;  
  7.             int offset = 0;  
  8.             byte[] cache;  
  9.             ByteArrayOutputStream outStream = new ByteArrayOutputStream();  
  10.             int i = 0;  
  11.             while(length - offset > 0){  
  12.                 if(length - offset > MAXENCRYPTSIZE){  
  13.                     cache = cipher.doFinal(source, offset, MAXENCRYPTSIZE);  
  14.                 }else{  
  15.                     cache = cipher.doFinal(source, offset, length - offset);  
  16.                 }  
  17.                 outStream.write(cache, 0, cache.length);  
  18.                 i++;  
  19.                 offset = i * MAXENCRYPTSIZE;  
  20.             }  
  21.             return encodeBase64(outStream.toByteArray());  
  22.         } catch (NoSuchAlgorithmException e) {  
  23.             e.printStackTrace();  
  24.         } catch (NoSuchPaddingException e) {  
  25.             e.printStackTrace();  
  26.         } catch (InvalidKeyException e) {  
  27.             e.printStackTrace();  
  28.         } catch (IllegalBlockSizeException e) {  
  29.             e.printStackTrace();  
  30.         } catch (BadPaddingException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.         return encryptData;       
  34.     }  
public static String encrypt(byte[] source, PublicKey publicKey) throws Exception	{
		String encryptData ="";
		try {
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			int length = source.length;
			int offset = 0;
			byte[] cache;
			ByteArrayOutputStream outStream = new ByteArrayOutputStream();
			int i = 0;
			while(length - offset > 0){
				if(length - offset > MAXENCRYPTSIZE){
					cache = cipher.doFinal(source, offset, MAXENCRYPTSIZE);
				}else{
					cache = cipher.doFinal(source, offset, length - offset);
				}
				outStream.write(cache, 0, cache.length);
				i++;
				offset = i * MAXENCRYPTSIZE;
			}
			return encodeBase64(outStream.toByteArray());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return encryptData;		
	}

加密后的数据提交给C#服务器端进行解密,当然,这里也要注意最大长度限制问题

  1. /// <summary>   
  2.         /// RSA解密   
  3.         /// </summary>   
  4.         /// <param name="encryptData">经过Base64编码的密文</param>   
  5.         /// <param name="privateKey">私钥</param>   
  6.         /// <returns>RSA解密后的数据</returns>   
  7.         public static string decrypt(string encryptData, string privateKey)  
  8.         {  
  9.             string decryptData = "";  
  10.             try  
  11.             {  
  12.                 RSACryptoServiceProvider provider = new RSACryptoServiceProvider();  
  13.                 provider.FromXmlString(privateKey);  
  14.                 byte[] bEncrypt = Convert.FromBase64String(encryptData);                  
  15.                 int length = bEncrypt.Length;  
  16.                 int offset = 0;  
  17.                 string cache ;  
  18.                 int i = 0;  
  19.                 while (length - offset > 0)  
  20.                 {  
  21.                     if (length - offset > MAXDECRYPTSIZE)  
  22.                     {  
  23.                         cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, MAXDECRYPTSIZE), false));  
  24.                     }  
  25.                     else  
  26.                     {  
  27.                         cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, length - offset), false));  
  28.                     }  
  29.                     decryptData += cache;  
  30.                     i++;  
  31.                     offset = i*MAXDECRYPTSIZE;  
  32.                 }  
  33.             }  
  34.             catch(Exception e)  
  35.             {  
  36.                 throw e;  
  37.             }  
  38.             return decryptData;  
  39.         }  
  40.   
  41.         /// <summary>   
  42.         /// 截取字节数组部分字节   
  43.         /// </summary>   
  44.         /// <param name="input"></param>   
  45.         /// <param name="offset">起始偏移位</param>   
  46.         /// <param name="length">截取长度</param>   
  47.         /// <returns></returns>   
  48.         private static byte[] getSplit(byte[] input, int offset, int length)  
  49.         {   
  50.             byte[] output = new byte[length];  
  51.             for (int i = offset; i < offset + length; i++)  
  52.             {  
  53.                 output[i - offset] = input[i];  
  54.             }  
  55.             return output;  
  56.         }  
/// <summary>
        /// RSA解密
        /// </summary>
        /// <param name="encryptData">经过Base64编码的密文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>RSA解密后的数据</returns>
        public static string decrypt(string encryptData, string privateKey)
        {
            string decryptData = "";
            try
            {
                RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
                provider.FromXmlString(privateKey);
                byte[] bEncrypt = Convert.FromBase64String(encryptData);                
                int length = bEncrypt.Length;
                int offset = 0;
                string cache ;
                int i = 0;
                while (length - offset > 0)
                {
                    if (length - offset > MAXDECRYPTSIZE)
                    {
                        cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, MAXDECRYPTSIZE), false));
                    }
                    else
                    {
                        cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, length - offset), false));
                    }
                    decryptData += cache;
                    i++;
                    offset = i*MAXDECRYPTSIZE;
                }
            }
            catch(Exception e)
            {
                throw e;
            }
            return decryptData;
        }

        /// <summary>
        /// 截取字节数组部分字节
        /// </summary>
        /// <param name="input"></param>
        /// <param name="offset">起始偏移位</param>
        /// <param name="length">截取长度</param>
        /// <returns></returns>
        private static byte[] getSplit(byte[] input, int offset, int length)
        { 
            byte[] output = new byte[length];
            for (int i = offset; i < offset + length; i++)
            {
                output[i - offset] = input[i];
            }
            return output;
        }
这样,就顺利完成了。

经过测试,这样做的确得到了正确的结果。

若是有什么地方有问题,还望大家指正!

----------------------------------------------------------------------------------------

C# Java间进行RSA加密解密交互(二)

C# Java间进行RSA加密解密交互(三)

 

转自:http://blog.csdn.net/dslinmy/article/details/37362661

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值