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

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 原文: C# Java间进行RSA加密解密交互 这里,讲一下RSA算法加解密在C#和Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益,但没能解决我的实际问题,终于,还是被我捣鼓出来了。
原文: 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类生成公钥、私钥

 /// <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;
        }

如此处生成的公钥为

<RSAKeyValue>
	<Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=
	</Modulus>
	<Exponent>AQAB</Exponent>
</RSAKeyValue>
在客户端(Java)对C#提供的公钥提取Modulus和Exponent
/**
	 * 返回包含模数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 编码和解码,想详细。

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编码处理的

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#服务器端进行解密,当然,这里也要注意最大长度限制问题

/// <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加密解密交互(三)







目录
相关文章
|
2月前
|
开发框架 Java .NET
C#与Java
在动态且不断发展的软件开发世界中,Java 和 C# 是两个巨头,每个都有自己独特的优势、理念和生态系统。本文深入比较了 Java 和 C#,探讨了它们的历史背景、语言特性、性能指标、跨平台功能等。
C#与Java
|
2月前
|
存储 安全 算法
C#一分钟浅谈:数据加密与解密技术
【10月更文挑战第3天】在数字化时代,信息安全至关重要。数据加密作为保障信息不被未授权访问的有效手段,通过特定算法将明文转换为密文,确保即使数据被截获也难以解读。本文从基础概念入手,介绍C#中实现数据加密的方法,涵盖对称加密(如AES、DES)与非对称加密(如RSA),并通过具体示例代码演示如何使用`System.Security.Cryptography.Aes`类完成AES加密和解密过程。此外,还强调了密钥管理及安全策略的重要性。
87 4
|
2月前
|
人工智能 缓存 Java
深入解析Spring AI框架:在Java应用中实现智能化交互的关键
【10月更文挑战第12天】Spring AI 是 Spring 框架家族的新成员,旨在满足 Java 应用程序对人工智能集成的需求。它支持自然语言处理、图像识别等多种 AI 技术,并提供与云服务(如 OpenAI、Azure Cognitive Services)及本地模型的无缝集成。通过简单的配置和编码,开发者可轻松实现 AI 功能,同时应对模型切换、数据安全及性能优化等挑战。
212 3
|
4月前
|
前端开发 JavaScript Java
Ajax进行异步交互:提升Java Web应用的用户体验
Ajax 技术允许在不重载整个页面的情况下与服务器异步交换数据,通过局部更新页面内容,极大提升了 Java Web 应用的响应速度和用户体验。本文介绍 Ajax 的基本原理及其实现方式,包括使用 XMLHttpRequest 对象发送请求、处理响应数据,并在 Java Web 应用中集成 Ajax。此外,还探讨了 Ajax 如何通过减少页面刷新、实时数据更新等功能改善用户体验。
81 3
|
5月前
|
缓存 Java 编译器
Java演进问题之JVMCI JIT编译器与JVM的交互如何解决
Java演进问题之JVMCI JIT编译器与JVM的交互如何解决
|
4月前
|
Java C# 数据安全/隐私保护
如何 使 Java、C# md5 加密的值保持一致
如何 使 Java、C# md5 加密的值保持一致
63 0
|
4月前
|
C# 图形学 数据安全/隐私保护
Unity数据加密☀️ 二、使用Rider将C#代码生成DLL文件
Unity数据加密☀️ 二、使用Rider将C#代码生成DLL文件
|
4月前
|
Java C#
C# 和 java 基本数据类型
C# 和 java 基本数据类型
26 0
|
5月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
89 1
|
5月前
|
存储 算法 安全
如何在Java中实现加密解密
如何在Java中实现加密解密