博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

windows phone 从cer中提出公钥然后再RSA加密的问题

Posted on 2013-04-16 11:50  ghwghw  阅读(1101)  评论(0编辑  收藏  举报

首先.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就是加密后得到的字符串。