rsa介绍

rsa公钥加密算法是1977年由ron rivest、adi shamirh和lenadleman在(美国麻省理工学院)开发的。rsa取名来自开发他们三者的名字。
rsa的缺点:

  • 产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。

  • 分组长度太大,为保证安全性,n 至少也要 600bits以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,set(secure electronic transaction)协议中要求ca采用2048bits长的密钥,其他实体使用1024比特的密钥。c)rsa密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。

    保密级别 对称密钥长度(bit) rsa密钥长度(bit) ecc密钥长度(bit) 保密年限
    80 80 1024 160 2010
    112 112 2048 224 2030
    128 128 3072 256 2040
    192 192 7680 384 2080
    256 256 15360 512 2120

c#中rsa的相关操作

  • 生成公钥和私钥
struct rsasecretkey
{
    public rsasecretkey(string privatekey, string publickey)
    {
        privatekey = privatekey;
        publickey = publickey;
    }
    public string publickey { get; set; }
    public string privatekey { get; set; }
    public override string tostring()
    {
        return string.format(
            "privatekey: {0}\r\npublickey: {1}", privatekey, publickey);
    }
}

/// <summary>
/// generate rsa secret key
/// </summary>
/// <param name="keysize">the size of the key,must from 384 bits to 16384 bits in increments of 8 </param>
/// <returns></returns>
rsasecretkey generatersasecretkey(int keysize)
{
    rsasecretkey rsakey = new rsasecretkey();
    using (rsacryptoserviceprovider rsa = new rsacryptoserviceprovider(keysize))
    {
        rsakey.privatekey = rsa.toxmlstring(true);
        rsakey.publickey = rsa.toxmlstring(false);
    }
    return rsakey;
}

  • 实现公钥加密私钥解密
string rsaencrypt(string xmlpublickey,string content)
{
    string encryptedcontent = string.empty;
    using(rsacryptoserviceprovider rsa = new rsacryptoserviceprovider())
    {
        rsa.fromxmlstring(xmlpublickey);
        byte[] encrypteddata = rsa.encrypt(encoding.default.getbytes(content), false);
        encryptedcontent = convert.tobase64string(encrypteddata);
    }
    return encryptedcontent;
}

string rsadecrypt(string xmlprivatekey, string content)
{
    string decryptedcontent = string.empty;
    using (rsacryptoserviceprovider rsa = new rsacryptoserviceprovider())
    {
        rsa.fromxmlstring(xmlprivatekey);
        byte[] decrypteddata = rsa.decrypt(convert.frombase64string(content), false);
        decryptedcontent = encoding.getencoding("gb2312").getstring(decrypteddata);
    }
    return decryptedcontent;
}

密钥格式的转换

c#中rsa公钥和私钥的格式都是xml的,而在其他语言如java中,生成的rsa密钥就是普通的base64字符串,所以需要将c#xml格式的密钥转换成普通的base64字符串,同时也要实现base64密钥字符串生成c#中xml格式的密钥.
安装 bouncycastle 这个nuget包
pm > install-package bouncycastle
bouncycastle项目网址
bouncycastlegithub地址
构造一个rsakeyconventer

namespace rsa
{
    using system;
    using system.security.cryptography;
    using org.bouncycastle.asn1.pkcs;
    using org.bouncycastle.math;
    using org.bouncycastle.pkcs;
    using org.bouncycastle.asn1.x509;
    using org.bouncycastle.x509;
    using org.bouncycastle.security;
    using org.bouncycastle.crypto.parameters;

    public class rsakeyconverter
    {
        /// <summary>
        /// xml private key -> base64 private key string
        /// </summary>
        /// <param name="xmlprivatekey"></param>
        /// <returns></returns>
        public static string fromxmlprivatekey(string xmlprivatekey)
        {
            string result = string.empty;
            using(rsacryptoserviceprovider rsa = new rsacryptoserviceprovider())
            {
                rsa.fromxmlstring(xmlprivatekey);
                rsaparameters param = rsa.exportparameters(true);
                rsaprivatecrtkeyparameters privatekeyparam = new rsaprivatecrtkeyparameters(
                    new biginteger(1, param.modulus), new biginteger(1, param.exponent),
                    new biginteger(1, param.d), new biginteger(1, param.p),
                    new biginteger(1, param.q), new biginteger(1, param.dp),
                    new biginteger(1, param.dq), new biginteger(1, param.inverseq));
                privatekeyinfo privatekey = privatekeyinfofactory.createprivatekeyinfo(privatekeyparam);
               
                result = convert.tobase64string(privatekey.toasn1object().getencoded());
            }
            return result;
        }

        /// <summary>
        /// xml public key -> base64 public key string
        /// </summary>
        /// <param name="xmlpublickey"></param>
        /// <returns></returns>
        public static string fromxmlpublickey(string xmlpublickey)
        {
            string result = string.empty;
            using(rsacryptoserviceprovider rsa = new rsacryptoserviceprovider())
            {
                rsa.fromxmlstring(xmlpublickey);
                rsaparameters p = rsa.exportparameters(false);
                rsakeyparameters keyparams = new rsakeyparameters(
                    false, new biginteger(1,p.modulus), new biginteger(1, p.exponent));
                subjectpublickeyinfo publickeyinfo = subjectpublickeyinfofactory.createsubjectpublickeyinfo(keyparams);
                result = convert.tobase64string(publickeyinfo.toasn1object().getencoded());
            }
            return result;
        }

        /// <summary>
        /// base64 private key string -> xml private key
        /// </summary>
        /// <param name="privatekey"></param>
        /// <returns></returns>
        public static string toxmlprivatekey(string privatekey)
        {
            rsaprivatecrtkeyparameters privatekeyparams =
                privatekeyfactory.createkey(convert.frombase64string(privatekey)) as rsaprivatecrtkeyparameters;
            using(rsacryptoserviceprovider rsa = new rsacryptoserviceprovider())
            {
                rsaparameters rsaparams = new rsaparameters()
                {
                    modulus = privatekeyparams.modulus.tobytearrayunsigned(),
                    exponent = privatekeyparams.publicexponent.tobytearrayunsigned(),
                    d = privatekeyparams.exponent.tobytearrayunsigned(),
                    dp = privatekeyparams.dp.tobytearrayunsigned(),
                    dq = privatekeyparams.dq.tobytearrayunsigned(),
                    p = privatekeyparams.p.tobytearrayunsigned(),
                    q = privatekeyparams.q.tobytearrayunsigned(),
                    inverseq = privatekeyparams.qinv.tobytearrayunsigned()
                };
                rsa.importparameters(rsaparams);
                return rsa.toxmlstring(true);
            }
        }

        /// <summary>
        /// base64 public key string -> xml public key
        /// </summary>
        /// <param name="pubilckey"></param>
        /// <returns></returns>
        public static string toxmlpublickey(string pubilckey)
        {
            rsakeyparameters p = 
                publickeyfactory.createkey(convert.frombase64string(pubilckey)) as rsakeyparameters;
            using(rsacryptoserviceprovider rsa = new rsacryptoserviceprovider())
            {
                rsaparameters rsaparams = new rsaparameters
                {
                    modulus = p.modulus.tobytearrayunsigned(),
                    exponent = p.exponent.tobytearrayunsigned()
                };
                rsa.importparameters(rsaparams);
                return rsa.toxmlstring(false);
            }
        }
    }
}