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参数,列举几种可行方案。
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<string, byte[]> privateKeyParamaters = PrivateKeyResolve(rsa.ExportCspBlob(true));
- foreach (string key in privateKeyParamaters.Keys)
- {
- Console.WriteLine(key + ":\n" + Convert.ToBase64String(privateKeyParamaters[key]));
- }
- Console.Read();
- }
- /// <summary>
- /// 对ExportCspBlob(false)方法到处的私钥进行解析,提取私钥参数
- /// </summary>
- /// <param name="cspblobPublicKey">RSA.ExportCspBlob(false)得到的包含私钥信息</param>
- /// <returns>公钥模数</returns>
- 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;
- }
- /// <summary>
- /// 对ExportCspBlob(true)方法到处的私钥进行解析,提取私钥参数
- /// </summary>
- /// <param name="cspblobPrivateKey">RSA.ExportCspBlob(true)得到的包含私钥信息</param>
- /// <returns>私钥参数</returns>
- public static Dictionary<string, byte[]> PrivateKeyResolve(byte[] cspblobPrivateKey)
- {
- Dictionary<string, byte[]> privateKeyParameters = new Dictionary<string, byte[]>();
- 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<String, byte[]> privateKeyResolve(byte[] cspblobPrivateKey) {
- Hashtable<String, byte[]> privateKeyParameters = new Hashtable<String, byte[]>();
- 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 |
--------------------------------------------------------------------------------------------------------------------