接着前面一篇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 |