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

接着前面一篇C# Java间进行RSA加密解密交互(二)说吧,在上篇中为了实现

/** 
 * RSA加密 
 * @param text--待加密的明文 
 * @param key--公钥,由服务器端提供的经base64编码的字符串 
 * @return 
 */  
public static String RSAEncryptoWithPublicKey(String text, String key) {  
    String result = null;  
    ......
    return result;  
}
加密过程,采用了折中办法,由Java产生Java客户端所需要的公钥数据信息,经由服务器传给客户端,而密钥则保存在服务器端。

现在,从根本上解决问题,有C#直接产生密钥对,私钥保存在服务器端,公钥传送给客户端,而且公钥正好满足上述方法要求。不过,这里用到了第三方插件BouncyCastle.cs。由于源码太长了,这里就不贴出来了。自己可以到http://www.bouncycastle.org/csharp/或者 http://yun.baidu.com/pcloud/album/file?album_id=7143016160664723357&uk=3895283693&fsid=421719398459611下载。这里演示其在Java C#间交互加解密过程。

1、由C#生成及加解密过程

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Utilities.Collections; 
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Asn1; 

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            //生成密钥对
            RsaKeyPairGenerator rsaKeyPairGenerator = new RsaKeyPairGenerator();
            RsaKeyGenerationParameters rsaKeyGenerationParameters = new RsaKeyGenerationParameters(BigInteger.ValueOf(3), new Org.BouncyCastle.Security.SecureRandom(), 1024, 25);
            rsaKeyPairGenerator.Init(rsaKeyGenerationParameters);//初始化参数
            AsymmetricCipherKeyPair keyPair = rsaKeyPairGenerator.GenerateKeyPair();
            AsymmetricKeyParameter publicKey = keyPair.Public;//公钥
            AsymmetricKeyParameter privateKey = keyPair.Private;//私钥

            SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
            PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKey);

            Asn1Object asn1ObjectPublic = subjectPublicKeyInfo.ToAsn1Object();
            byte[] publicInfoByte = asn1ObjectPublic.GetEncoded();
            Asn1Object asn1ObjectPrivate = privateKeyInfo.ToAsn1Object();
            byte[] privateInfoByte = asn1ObjectPrivate.GetEncoded();

            //这里可以将密钥对保存到本地
            Console.WriteLine("PublicKey:\n" + Convert.ToBase64String(publicInfoByte));
            Console.WriteLine("PrivateKey:\n" + Convert.ToBase64String(privateInfoByte));

            //加密、解密
            Asn1Object pubKeyObj = Asn1Object.FromByteArray(publicInfoByte);//这里也可以从流中读取,从本地导入
            AsymmetricKeyParameter pubKey = PublicKeyFactory.CreateKey(SubjectPublicKeyInfo.GetInstance(pubKeyObj));
            IAsymmetricBlockCipher cipher = new RsaEngine();
            cipher.Init(true, pubKey);//true表示加密
            //加密
            string data = "成功了。。。";
            Console.WriteLine("\n明文:" + data);
            byte[] encryptData = cipher.ProcessBlock(Encoding.UTF8.GetBytes(data), 0, Encoding.UTF8.GetBytes(data).Length);
            Console.WriteLine("密文:" + Convert.ToBase64String(encryptData));
            //解密
            AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(privateInfoByte);
            cipher.Init(false, priKey);//false表示解密
            string decryptData = Encoding.UTF8.GetString(cipher.ProcessBlock(encryptData, 0, encryptData.Length));
            Console.WriteLine("解密后数据:" + decryptData);
            Console.Read();
        }
    }
}

运行结果:

PublicKey:
MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCzoQTA/zgahiaytyggCLoodqhuG8gRUXypUt+9HAtPsNhRHC2ksQazS8DnyyrfgrmPfv///AHURL2itn7L1gfrVcm7QDLwM/gXCjUV5lkRrlp7SDF6yxrF00PLWOvAae1eEmmg9ucymEjwq2pzEVMJyWslJdXjvYOSDstUMbqCtQIBAw==
PrivateKey:
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALOhBMD/OBqGJrK3KCAIuih2qG4byBFRfKlS370cC0+w2FEcLaSxBrNLwOfLKt+CuY9+///8AdREvaK2fsvWB+tVybtAMvAz+BcKNRXmWRGuWntIMXrLGsXTQ8tY68Bp7V4SaaD25zKYSPCranMRUwnJayUl1eO9g5IOy1QxuoK1AgEDAoGAd8Ct1f96vFlvIc9wFVsmxaRwSWfatjZTG4yVKL1c38s64L1zwyCvIjKAmodx6lcmX6n///1WjYMpFyRUh+QFRm9H60Ger3PfUII4epgVHqX20aRWy32cmW3Gp+r04p7ENja/Jey6HsdXb7Q32fdZKsLZOO2lvNdUu/5+LsP6wTMCQQDsFcBU1JFA3l6vZyi3b+nzZgoaCo6kMTTG4i/S/kf8cVPw5jaEVGUMhsXPkicWXNpppXNU4yA4gbNRN2XXnsjnAkEAwsgaCPBXxUq/l3k1Ssl5wgI2t6S66n6q57efpX4kf1W4z2Sxj3ufYL8DTYSFB/BvO3/cbHooQgLEv9aoNCOYAwJBAJ1j1Y3jC4CUPx+aGyT1RqJEBrwHCcLLeISWyoyphVL2N/XuzwLi7ghZ2TUMGg7okZvDojiXatBWd4t6Q+UUhe8CQQCB2rwF9Y/Y3H+6UM4x26aBVs8lGHycVHHvz7/DqW2qOSXfmHZfp7+V1KzeWFiv9Z98/+hIUXAsAdh/5HAiwmVXAkEAmo9GTWqbRP6BU75MPPnL42zq/4cQBI4yya03NDZjU1lwA2YvmFzJaM4mVmrsxNeDv6qY7Ibl/GDwIbAUaEHaAA==
明文:成功了。。。
密文:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC68tDDx2RzUu/BP/x93GcohXJeZeN4TZXUHEji3jjnyQV1yqDLdm5cOqjkqBQZHDZCq5fLhgg=
解密后数据:成功了。。。

2、公钥提供给Java客户端进行加密(这里也给出了解密过程)

若是依据C#端提供的密钥对在Java端进行加解密,加解密匹配方式还是有好几种的。就下面代码中的Cipher.getInstance参数,列举几种可行方案。

Java RSA 加解密参数transformation匹配方案
encrypt
Cipher.getInstance(transformation)
decrypt
Cipher.getInstance(transformation)
encrypt
Cipher.getInstance(transformation)
decrypt
Cipher.getInstance(transformation, 
new org.bouncycastle.jce.
provider.BouncyCastleProvider())
RSA RSA RSA RSA
RSA RSA/ECB/PKCS1Padding RSA RSA/ECB/PKCS1Padding
RSA/ECB/PKCS1Padding RSA RSA/ECB/PKCS1Padding RSA
RSA/ECB/PKCS1Padding RSA/ECB/PKCS1Padding RSA/ECB/PKCS1Padding RSA/ECB/PKCS1Padding
    RSA/ECB/NoPadding RSA
    RSA/ECB/NoPadding RSA/ECB/NoPadding

注意:代码中注释的地方很重要

import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 * @author 邓少林
 * 
 */
public class RSAUtil {
	private static int MAXENCRYPTSIZE = 117;
	private static int MAXDECRYPTSIZE = 128;

	/**
	 * @param publicKeyByte
	 * @return RSAPublicKey
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 */
	public static RSAPublicKey getPublicKey(byte[] publicKeyByte) throws NoSuchAlgorithmException, InvalidKeySpecException{
		X509EncodedKeySpec x509 = new X509EncodedKeySpec(publicKeyByte);		
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(x509);
		return publicKey;		
	}

	public static RSAPrivateKey getPrivateKey(byte[] privateKeyByte) throws InvalidKeySpecException, NoSuchAlgorithmException {
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyByte);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
	}


	/**
	 * encrypt
	 * @param source
	 * @param publicKey
	 * @return Bute[] encryptData
	 * @throws Exception
	 */
	public static byte[] encrypt(PublicKey publicKey, byte[] source)
			throws Exception {
		try {
			//此处填充方式选择部填充 NoPadding,当然模式和填充方式选择其他的,在Java端可以正确加密解密,
			//但是解密后的密文提交给C#端,解密的得到的数据将产生乱码
			Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
			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 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 null;
	}

	/**RSA decrypt
	 * @param privateKey
	 * @param encryptData
	 * @return decryptData
	 * @throws IllegalBlockSizeException
	 * @throws BadPaddingException
	 * @throws InvalidKeyException
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchPaddingException
	 */
	public static byte[] decrypt(PrivateKey privateKey, byte[] encryptData)
			throws IllegalBlockSizeException, BadPaddingException,
			InvalidKeyException, NoSuchAlgorithmException,
			NoSuchPaddingException {
		//此处模式选择与加密对应,但是需要添加第二个参数new org.bouncycastle.jce.provider.BouncyCastleProvider()
		//若不添加第二个参数的话,解密后的数据前面出现大段空格符
		Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding", new org.bouncycastle.jce.provider.BouncyCastleProvider());
		cipher.init(Cipher.DECRYPT_MODE, privateKey);

		int length = encryptData.length;
		int offset = 0;
		int i = 0;
		byte[] cache;
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		while (length - offset > 0) {
			if (length - offset > MAXDECRYPTSIZE) {
				cache = cipher.doFinal(encryptData, offset, MAXDECRYPTSIZE);
			} else {
				cache = cipher.doFinal(encryptData, offset, length - offset);
			}
			outStream.write(cache, 0, cache.length);
			i++;
			offset = i * MAXDECRYPTSIZE;
		}
		return outStream.toByteArray();
	}

	/**
	 * base64编码
	 * 
	 * @param input
	 * @return output with base64 encoded
	 * @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 void main(String[] args) throws Exception {
		RSAPublicKey rsaPublicKey = getPublicKey(decodeBase64("MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCzoQTA/zgahiaytyggCLoodqhuG8gRUXypUt+9HAtPsNhRHC2ksQazS8DnyyrfgrmPfv///AHURL2itn7L1gfrVcm7QDLwM/gXCjUV5lkRrlp7SDF6yxrF00PLWOvAae1eEmmg9ucymEjwq2pzEVMJyWslJdXjvYOSDstUMbqCtQIBAw=="));
		byte[] encryptData = encrypt(rsaPublicKey, "成功了...".getBytes(Charset.forName("utf-8")));
		System.out.println("密文:\n" + encodeBase64(encryptData));
		RSAPrivateKey privateKey = getPrivateKey(decodeBase64("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALOhBMD/OBqGJrK3KCAIuih2qG4byBFRfKlS370cC0+w2FEcLaSxBrNLwOfLKt+CuY9+///8AdREvaK2fsvWB+tVybtAMvAz+BcKNRXmWRGuWntIMXrLGsXTQ8tY68Bp7V4SaaD25zKYSPCranMRUwnJayUl1eO9g5IOy1QxuoK1AgEDAoGAd8Ct1f96vFlvIc9wFVsmxaRwSWfatjZTG4yVKL1c38s64L1zwyCvIjKAmodx6lcmX6n///1WjYMpFyRUh+QFRm9H60Ger3PfUII4epgVHqX20aRWy32cmW3Gp+r04p7ENja/Jey6HsdXb7Q32fdZKsLZOO2lvNdUu/5+LsP6wTMCQQDsFcBU1JFA3l6vZyi3b+nzZgoaCo6kMTTG4i/S/kf8cVPw5jaEVGUMhsXPkicWXNpppXNU4yA4gbNRN2XXnsjnAkEAwsgaCPBXxUq/l3k1Ssl5wgI2t6S66n6q57efpX4kf1W4z2Sxj3ufYL8DTYSFB/BvO3/cbHooQgLEv9aoNCOYAwJBAJ1j1Y3jC4CUPx+aGyT1RqJEBrwHCcLLeISWyoyphVL2N/XuzwLi7ghZ2TUMGg7okZvDojiXatBWd4t6Q+UUhe8CQQCB2rwF9Y/Y3H+6UM4x26aBVs8lGHycVHHvz7/DqW2qOSXfmHZfp7+V1KzeWFiv9Z98/+hIUXAsAdh/5HAiwmVXAkEAmo9GTWqbRP6BU75MPPnL42zq/4cQBI4yya03NDZjU1lwA2YvmFzJaM4mVmrsxNeDv6qY7Ibl/GDwIbAUaEHaAA=="));
		System.out.println("解密后数据:" + new String(decrypt(privateKey, encryptData),"utf-8"));
	}
}

运行结果:

密文:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC68tDDx2RzUu/BP/x93GcohXJeZeN4TZXUHEji3jjnyQV1yqDLdm5cOqjkqBQZHDZCq5fLhgg=
解密后数据:成功了。。。

3、将加密后的密文提交给服务器端进行解密

static void Main(string[] args)
{
	IAsymmetricBlockCipher cipher = new RsaEngine();
	byte[] encryptData = Convert.FromBase64String("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC68tDDx2RzUu/BP/x93GcohXJeZeN4TZXUHEji3jjnyQV1yqDLdm5cOqjkqBQZHDZCq5fLhgg=");
	AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(Asn1Object.FromByteArray(Convert.FromBase64String("MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALOhBMD/OBqGJrK3KCAIuih2qG4byBFRfKlS370cC0+w2FEcLaSxBrNLwOfLKt+CuY9+///8AdREvaK2fsvWB+tVybtAMvAz+BcKNRXmWRGuWntIMXrLGsXTQ8tY68Bp7V4SaaD25zKYSPCranMRUwnJayUl1eO9g5IOy1QxuoK1AgEDAoGAd8Ct1f96vFlvIc9wFVsmxaRwSWfatjZTG4yVKL1c38s64L1zwyCvIjKAmodx6lcmX6n///1WjYMpFyRUh+QFRm9H60Ger3PfUII4epgVHqX20aRWy32cmW3Gp+r04p7ENja/Jey6HsdXb7Q32fdZKsLZOO2lvNdUu/5+LsP6wTMCQQDsFcBU1JFA3l6vZyi3b+nzZgoaCo6kMTTG4i/S/kf8cVPw5jaEVGUMhsXPkicWXNpppXNU4yA4gbNRN2XXnsjnAkEAwsgaCPBXxUq/l3k1Ssl5wgI2t6S66n6q57efpX4kf1W4z2Sxj3ufYL8DTYSFB/BvO3/cbHooQgLEv9aoNCOYAwJBAJ1j1Y3jC4CUPx+aGyT1RqJEBrwHCcLLeISWyoyphVL2N/XuzwLi7ghZ2TUMGg7okZvDojiXatBWd4t6Q+UUhe8CQQCB2rwF9Y/Y3H+6UM4x26aBVs8lGHycVHHvz7/DqW2qOSXfmHZfp7+V1KzeWFiv9Z98/+hIUXAsAdh/5HAiwmVXAkEAmo9GTWqbRP6BU75MPPnL42zq/4cQBI4yya03NDZjU1lwA2YvmFzJaM4mVmrsxNeDv6qY7Ibl/GDwIbAUaEHaAA=="))));
	cipher.Init(false, priKey);
	Console.WriteLine(Encoding.UTF8.GetString(cipher.ProcessBlock(encryptData, 0, encryptData.Length)));
	Console.WriteLine(Encoding.UTF8.GetString(cipher.ProcessBlock(encryptData, 0, encryptData.Length)).Equals("成功了。。。"));
	Console.Read();
}

运行结果:

成功了。。。
True
大家也试一试吧。

下面再简要的介绍一种交互方法。当然了,并非实现上面的要求,而与C# Java间进行RSA加密解密交互这篇中的略相似,相同的是都需要在客户端(Java)先进行解析。对于这种做法可以先参阅源码CryptoConvert.cs(namespace Mono.Security.Cryptography)源码地址:http://www.oschina.net/code/explore/mono-2.8.1/mcs/class/corlib/Mono.Security.Cryptography/CryptoConvert.cs
(此处所有处理都是针对密钥初始化长度为1024,其他情况类似分析)
1、C#端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //------------------------------------------------------------------------------------------
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            /*RSAParameters paras = rsa.ExportParameters(true);
            Console.WriteLine("-----------------------------------------------------------------------");
            Console.WriteLine("Exponent:" + Convert.ToBase64String(paras.Exponent));
            Console.WriteLine("Modulus:" + Convert.ToBase64String(paras.Modulus));
            Console.WriteLine("P:" + Convert.ToBase64String(paras.P));
            Console.WriteLine("Q:" + Convert.ToBase64String(paras.Q));
            Console.WriteLine("DP:" + Convert.ToBase64String(paras.DP));
            Console.WriteLine("DQ:" + Convert.ToBase64String(paras.DQ));
            Console.WriteLine("InversQ:" + Convert.ToBase64String(paras.InverseQ));
            Console.WriteLine("D:" + Convert.ToBase64String(paras.D));
            Console.WriteLine("-----------------------------------------------------------------------");
            Console.WriteLine("Exponent:" + paras.Exponent.Length + "\tModulus:" + paras.Modulus.Length + "\tP:" + paras.P.Length + "\tQ:" + paras.Q.Length + "\tDP:" + paras.DP.Length + "\tDQ:" + paras.DQ.Length + "\tInversQ:" + paras.InverseQ.Length + "\tD:" + paras.D.Length);
            Console.WriteLine("-----------------------------------------------------------------------");
            Console.WriteLine("the length of ExportCspBlobPublic:" + rsa.ExportCspBlob(false).Length);*/
            Console.WriteLine("ExportCspBlobPublic:\n" + Convert.ToBase64String(rsa.ExportCspBlob(false)));//导出公钥数据
            Console.WriteLine("-----------------------------------------------------------------------");
            //Console.WriteLine("the length of ExportCspBlobPrivate:" + rsa.ExportCspBlob(true).Length);
            Console.WriteLine("ExportCspBlobPrivate:\n" + Convert.ToBase64String(rsa.ExportCspBlob(true)));//导出私钥数据
            Console.WriteLine("-----------------------------------------------------------------------");
            Console.WriteLine("publicKeyResolve...");
            byte[] exportPublic = rsa.ExportCspBlob(false);
            Console.WriteLine(Convert.ToBase64String(PublicKeyResolve(exportPublic)));
            Console.WriteLine("-----------------------------------------------------------------------");
            Console.WriteLine("privateKeyResolve...");
            Dictionary privateKeyParamaters = PrivateKeyResolve(rsa.ExportCspBlob(true));
            foreach (string key in privateKeyParamaters.Keys)
            {
                Console.WriteLine(key + ":\n" + Convert.ToBase64String(privateKeyParamaters[key]));
            }
            Console.Read();
        }

        /// 
        /// 对ExportCspBlob(false)方法到处的私钥进行解析,提取私钥参数
        /// 
        /// RSA.ExportCspBlob(false)得到的包含私钥信息
        /// 公钥模数
        public static byte[] PublicKeyResolve(byte[] cspblobPublicKey)
        {
            byte[] modulus = new byte[128];
            Array.Reverse(cspblobPublicKey, 0, cspblobPublicKey.Length);
            Buffer.BlockCopy(cspblobPublicKey, 0, modulus, 0, 128);
            return modulus;
        }

        /// 
        /// 对ExportCspBlob(true)方法到处的私钥进行解析,提取私钥参数
        /// 
        /// RSA.ExportCspBlob(true)得到的包含私钥信息
        /// 私钥参数
        public static Dictionary PrivateKeyResolve(byte[] cspblobPrivateKey)
        {
            Dictionary privateKeyParameters = new Dictionary();

            Array.Reverse(cspblobPrivateKey, 0, cspblobPrivateKey.Length);
            int offset = 0;
            byte[] part = new byte[128];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, offset, part.Length);
            privateKeyParameters.Add("D", part);

            offset += part.Length;
            part = new byte[64];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, 0, part.Length);
            privateKeyParameters.Add("INVERSEQ", part);

            offset += part.Length;
            part = new byte[64];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, 0, part.Length);
            privateKeyParameters.Add("DQ", part);

            offset += part.Length;
            part = new byte[64];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, 0, part.Length);
            privateKeyParameters.Add("DP", part);

            offset += part.Length;
            part = new byte[64];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, 0, part.Length);
            privateKeyParameters.Add("Q", part);

            offset += part.Length;
            part = new byte[64];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, 0, part.Length);
            privateKeyParameters.Add("P", part);

            offset += part.Length;
            part = new byte[128];
            Buffer.BlockCopy(cspblobPrivateKey, offset, part, 0, part.Length);
            privateKeyParameters.Add("MODULUS", part);
            return privateKeyParameters;
        }
    }
}
运行结果:

ExportCspBlobPublic:
BgIAAACkAABSU0ExAAQAAAEAAQCdsw5SKF57lm1ez9Pu1CkEwRlW+fyEAFuz/N+mYe0iNyjA2ePhZoW4ZdwnaEBx9Gonskuch6pasypJhPr5bbvNVHQjtEEJSdFG1exKQ7AxpMmmft8PyhUcYqa15XUpebQaM0Zi+V1yiOqki54kCZSeGrMwa26+vJ4JCx3y+Fngmw==
-----------------------------------------------------------------------
ExportCspBlobPrivate:
BwIAAACkAABSU0EyAAQAAAEAAQCdsw5SKF57lm1ez9Pu1CkEwRlW+fyEAFuz/N+mYe0iNyjA2ePhZoW4ZdwnaEBx9Gonskuch6pasypJhPr5bbvNVHQjtEEJSdFG1exKQ7AxpMmmft8PyhUcYqa15XUpebQaM0Zi+V1yiOqki54kCZSeGrMwa26+vJ4JCx3y+Fngm9cPox4JtkoE0KVNsA98WFkAs3bseEqlcZhGbyLwBOBq7jeXJCFv5IZ8ZxDWrpWRz2HminmQEXjj54y9/FjJYs+r+b0J5W4GmZWBFkaO+0TkKoQAqK46x/c739e74GMf5p1ZyBNjiDPDts/CPf9OruGaTRM5t2HUA6pASU6De2rAR8nGRCxODmbeKb8w4Y/Q7b7eY4Omwr9sSAwDMlylXnrk4kyuuouHuP+Mb+LWppsv5WO+KfnT16CY5ZmpbfTlTV/oNppVgMSBKgdiI+FQFHJiCZh+4awb3tkOOIsdmWKEdg03NCbev3WbH6dU3ZDZFJ27zbTNhD4BlkyGmEkIQxfx895qWFJnqTOeEUQd1M5UGSDIEfIw51ByLKS/nPq1M3aUN4nRIm8EzDOa8529ZU0wLJvoipER8qpeb6AyKKGF6dcEq2HooM54+qF2oJXVc3CPwFTjmytbeKOq1waInDZfu0eWF5m5ET7WrXRjGA1txlPOhC4tBI6yJEgzdY5eVFJcqsYl8asHyaWIM07GZbS8opP1ePIv9YybeUEUg+Y4gsWBjTnmYgF4nEhLGmXtmGFQWbAnzQVsWqvmXb3RN5Y=
-----------------------------------------------------------------------
publicKeyResolve...
m+BZ+PIdCwmevL5uazCzGp6UCSSei6TqiHJd+WJGMxq0eSl15bWmYhwVyg/ffqbJpDGwQ0rs1UbRSQlBtCN0VM27bfn6hEkqs1qqh5xLsidq9HFAaCfcZbiFZuHj2cAoNyLtYabf/LNbAIT8+VYZwQQp1O7Tz15tlnteKFIOs50=
-----------------------------------------------------------------------
privateKeyResolve...
D:
ljfRvV3mq1psBc0nsFlQYZjtZRpLSJx4AWLmOY2BxYI45oMUQXmbjPUv8nj1k6K8tGXGTjOIpckHq/ElxqpcUlRejnUzSCSyjgQtLoTOU8ZtDRhjdK3WPhG5mReWR7tfNpyIBteqo3hbK5vjVMCPcHPVlaB2ofp4zqDoYasE1+k=
INVERSEQ:
haEoMqBvXqryEZGK6JssME1lvZ3zmjPMBG8i0Yk3lHYztfqcv6QsclDnMPIRyCAZVM7UHUQRnjOpZ1JYat7z8Q==
DQ:
F0MISZiGTJYBPoTNtM27nRTZkN1Upx+bdb/eJjQ3DXaEYpkdizgO2d4brOF+mAlichRQ4SNiByqBxIBVmjboXw==
DP:
TeX0bamZ5Zig19P5Kb5j5S+bptbib4z/uIeLuq5M4uR6XqVcMgMMSGy/wqaDY96+7dCP4TC/Kd5mDk4sRMbJRw==
Q:
wGp7g05JQKoD1GG3ORNNmuGuTv89ws+2wzOIYxPIWZ3mH2Pgu9ffO/fHOq6oAIQq5ET7jkYWgZWZBm7lCb35qw==
P:
z2LJWPy9jOfjeBGQeYrmYc+Rla7WEGd8huRvISSXN+5q4ATwIm9GmHGlSnjsdrMAWVh8D7BNpdAESrYJHqMP1w==
MODULUS:
m+BZ+PIdCwmevL5uazCzGp6UCSSei6TqiHJd+WJGMxq0eSl15bWmYhwVyg/ffqbJpDGwQ0rs1UbRSQlBtCN0VM27bfn6hEkqs1qqh5xLsidq9HFAaCfcZbiFZuHj2cAoNyLtYabf/LNbAIT8+VYZwQQp1O7Tz15tlnteKFIOs50=
2、Java端的解析(与C#端的类似,解析后,用参数构造密钥)
import java.util.Hashtable;


public class ExportCspBlobResolve {
	/**
	 * 解析公钥
	 * @param cspblobPublicKey由C# new RSACryptoServiceProvider().ExportCspBlob(false)提供
	 * @return RSA公钥的Modulus参数
	 */
	public static byte[] publicKeyResolve(byte[] cspblobPublicKey){
		int length = cspblobPublicKey.length;
		byte[] reversePublicKey = new byte[length];
		for (int i = 0; i < length; i++) {
			reversePublicKey[i] = cspblobPublicKey[length - 1 - i];
		}		
		byte[] part = new byte[128];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePublicKey[i];
		return part;		
	}
	
	/**
	 * 解析私钥
	 * @param cspblobPrivateKey由C# new RSACryptoServiceProvider().ExportCspBlob(true)提供
	 * @return 返回包含私钥参数的Hashtable
	 */
	public static Hashtable privateKeyResolve(byte[] cspblobPrivateKey) {
		Hashtable privateKeyParameters = new Hashtable();
		int length = cspblobPrivateKey.length;
		byte[] reversePrivateKey = new byte[length];
		for (int i = 0; i < length; i++) {
			reversePrivateKey[i] = cspblobPrivateKey[length - 1 - i];
		}
		int offset = 0;
		byte[] part = new byte[128];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("D", part);
		
		offset += part.length;
		part = new byte[64];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("INVERSEQ", part);
		
		offset += part.length;
		part = new byte[64];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("DQ", part);
		
		offset += part.length;
		part = new byte[64];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("DP", part);
		
		offset += part.length;
		part = new byte[64];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("Q", part);
		
		offset += part.length;
		part = new byte[64];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("P", part);
		
		offset += part.length;
		part = new byte[128];
		for (int i = 0; i < part.length; i++)
			part[i] = reversePrivateKey[offset + i];
		privateKeyParameters.put("MODULUS", part);
		return privateKeyParameters;
	}	
}

输入参数即为C#导出的ExportCspBlobPublic 和 ExportCspBlobPrivate,至于验证过程,这里就不再重复了。有兴趣的可以自己验证

顺便给个RSA参数在Java和C#间的对应关系

RSA参数在Java和C#间的对应关系
RSA for Java RSA for C# RSA forJava RSA for C#
PublicExPonent Exponent PrimeQ Q
Modules Modulus PrimeExponentP DP
PrivateExponent D PrimeExponentQ DQ
PrimeP P CrtCoefficient InverseQ
--------------------------------------------------------------------------------------------------------------------

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

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

你可能感兴趣的:(RSA)