首先.net平台SDK提供的RSA加密由于加了随机数,所以在解密的时候必须也要在.net平台解密。如果要跟java平台这样的跨平台解密就会出问题。
参考文档:http://blog.csdn.net/lubiaopan/article/details/6233517
其中提到两种解决方案,一种是在.net平台是用BigInteger 来实现,另外一种是java端也用添加随机数的方式解决。
我下面主要写下用在.net平台用BigInteger 来实现的方式。
第一步:提取cer文件中的公钥
using (var cerStream = App.GetResourceStream(new Uri("/xxxx;component/cert.der", UriKind.Relative)).Stream) { byte[] cerBuffer = new byte[cerStream.Length]; cerStream.Read(cerBuffer, 0, cerBuffer.Length); System.Security.Cryptography.X509Certificates.X509Certificate cer = new System.Security.Cryptography.X509Certificates.X509Certificate(cerBuffer); string publickkey = cer.GetPublicKeyString(); }
第二步:将提取的公钥转换成能够进行RSA加密的字节流。
这里需要用到X509PublicKeyParser类,这个类windows phone SDK本身不提供,这里贴出该类的实现代码
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; namespace System.Security.Cryptography { /// <summary> /// Summary description for AbstractAsn1Container. /// </summary> internal abstract class AbstractAsn1Container { private int offset; private byte[] data; private byte tag; internal protected AbstractAsn1Container(byte[] abyte, int i, byte tag) { this.tag = tag; if (abyte[i] != tag) { throw new Exception("Invalid data. The tag byte is not valid"); } int length = DetermineLength(abyte, i + 1); int bytesInLengthField = DetermineLengthLen(abyte, i + 1); int start = i + bytesInLengthField + 1; this.offset = start + length; data = new byte[length]; Array.Copy(abyte, start, data, 0, length); } internal int Offset { get { return offset; } } internal byte[] Bytes { get { return this.data; } } internal protected virtual int DetermineLengthLen(byte[] abyte0, int i) { int j = abyte0[i] & 0xff; switch (j) { case 129: return 2; case 130: return 3; case 131: return 4; case 132: return 5; case 128: default: return 1; } } internal protected virtual int DetermineLength(byte[] abyte0, int i) { int j = abyte0[i] & 0xff; switch (j) { case 128: return DetermineIndefiniteLength(abyte0, i); case 129: return abyte0[i + 1] & 0xff; case 130: int k = (abyte0[i + 1] & 0xff) << 8; k |= abyte0[i + 2] & 0xff; return k; case 131: int l = (abyte0[i + 1] & 0xff) << 16; l |= (abyte0[i + 2] & 0xff) << 8; l |= abyte0[i + 3] & 0xff; return l; } return j; } internal protected virtual int DetermineIndefiniteLength(byte[] abyte0, int i) { if ((abyte0[i - 1] & 0xff & 0x20) == 0) throw new Exception("Invalid indefinite length."); int j = 0; int k; int l; for (i++; abyte0[i] != 0 && abyte0[i + 1] != 0; i += 1 + k + l) { j++; k = DetermineLengthLen(abyte0, i + 1); j += k; l = DetermineLength(abyte0, i + 1); j += l; } return j; } } internal class IntegerContainer : AbstractAsn1Container { internal IntegerContainer(byte[] abyte, int i) : base(abyte, i, 0x2) { } } internal class SequenceContainer : AbstractAsn1Container { internal SequenceContainer(byte[] abyte, int i) : base(abyte, i, 0x30) { } } public class X509PublicKeyParser { public static RSAParameters GetRSAPublicKeyParameters(byte[] bytes) { return GetRSAPublicKeyParameters(bytes, 0); } public static RSAParameters GetRSAPublicKeyParameters(byte[] bytes, int i) { SequenceContainer seq = new SequenceContainer(bytes, i); IntegerContainer modContainer = new IntegerContainer(seq.Bytes, 0); IntegerContainer expContainer = new IntegerContainer(seq.Bytes, modContainer.Offset); return LoadKeyData(modContainer.Bytes, 0, modContainer.Bytes.Length, expContainer.Bytes, 0, expContainer.Bytes.Length); } public static RSAParameters GetRSAPublicKeyParameters(X509Certificate cert) { return GetRSAPublicKeyParameters(cert.GetPublicKey(), 0); } private static RSAParameters LoadKeyData(byte[] abyte0, int i, int j, byte[] abyte1, int k, int l) { byte[] modulus = null; byte[] publicExponent = null; for (; abyte0[i] == 0; i++) j--; modulus = new byte[j]; Array.Copy(abyte0, i, modulus, 0, j); int i1 = modulus.Length * 8; int j1 = modulus[0] & 0xff; for (int k1 = j1 & 0x80; k1 == 0; k1 = j1 << 1 & 0xff) i1--; if (i1 < 256 || i1 > 4096) throw new Exception("Invalid RSA modulus size."); for (; abyte1[k] == 0; k++) l--; publicExponent = new byte[l]; Array.Copy(abyte1, k, publicExponent, 0, l); RSAParameters p = new RSAParameters(); p.Modulus = modulus; p.Exponent = publicExponent; return p; } } }
然后是用X509PublicKeyParser来转换公钥
System.Security.Cryptography.RSAParameters RSAKeyInfo; using (var cerStream = App.GetResourceStream(new Uri("/xxxx;component/cert.der", UriKind.Relative)).Stream) { byte[] cerBuffer = new byte[cerStream.Length]; cerStream.Read(cerBuffer, 0, cerBuffer.Length); System.Security.Cryptography.X509Certificates.X509Certificate cer = new System.Security.Cryptography.X509Certificates.X509Certificate(cerBuffer); RSAKeyInfo = X509PublicKeyParser.GetRSAPublicKeyParameters(cer.GetPublicKey()); }
第三步:使用BigInteger来加密数据,这里有一个BigInteger开源类库http://www.codeproject.com/Articles/2728/C-BigInteger-Class。
BigInteger bi_e = new BigInteger(RSAKeyInfo.Exponent); BigInteger bi_n = new BigInteger(RSAKeyInfo.Modulus); BigInteger bi_data = new BigInteger(System.Text.Encoding.UTF8.GetBytes("123456789")); BigInteger bi_encrypted = bi_data.modPow(bi_e, bi_n); //rsa加密后的Base64字符串 string rsaEncryptString = Convert.ToBase64String(bi_encrypted.getBytes());
rsaEncryptString就是加密后得到的字符串。