接着前面一篇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参数,列举几种可行方案。
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 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加密解密交互(二)