C# RSA非對稱加密、解密及格式轉換


前言

本文主要介紹如何使用.Net自帶API結合BouncyCastle類庫實現RSA加密和解密,密鑰生成和密鑰格式轉換。

一、RSA介紹

RSA加密算法是1977年由Ron RivestAdi ShamirhLen Adleman在(美國麻省理工學院)開發的。RSA取名來自開發他們三者的名字。

RSA加密算法是一種非對稱加密算法,簡單來說,就是加密時使用一個鑰匙,解密時使用另一個鑰匙。因為加密的鑰匙是公開的,所又稱公鑰,解密的鑰匙是不公開的,所以稱為私鑰

RSA是被研究得最廣泛的公鑰算法,從提出到現在已近二十年,經歷了各種攻擊的考驗,逐漸為人們接受,普遍認為是目前最優秀的公鑰方案之一。

RSA的缺點主要有:

  • 產生密鑰很麻煩,受到素數產生技術的限制,因而難以做到一次一密。

  • 分組長度太大,為保證安全性,n至少也要600bits以上,使運算代價很高,尤其是速度較慢,較對稱密碼算法慢幾個數量級;且隨着大數分解技術的發展,這個長度還在增加,不利於數據格式的標准化。目前,SET(Secure Electronic Transaction)協議中要求CA采用2048bits長的密鑰,其他實體使用1024bits的密鑰。

  • 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

RSA的算法在這里就不贅述了,可以看看下面這張圖有利於理解。

二、C#代碼實現

2.1 生成公鑰/私鑰

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>
/// 生成`RSA`密鑰
/// </summary>
/// <param name="keySize">密鑰的大小,從384位到16384位,每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;
}

2.2 公鑰加密/私鑰解密

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;
}

2.3 密鑰格式轉換

C#RSA公鑰和私鑰的格式都是XML的,而在其他語言如java中,生成的RSA密鑰就是普通的Base64字符串,所以需要將C# xml格式的密鑰轉換成普通的Base64字符串,同時也要實現Base64密鑰字符串生成C# xml格式的密鑰。

安裝 BouncyCastle 這個NugetPM > Install-Package BouncyCastle

構造一個RSAKeyConventer

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;

namespace RSA
{
    public class RSAKeyConverter
    {
        /// <summary>
        /// 轉換"私鑰"格式
        /// </summary>
        /// <param name="xmlPrivateKey">xml格式私鑰</param>
        /// <returns>base64格式私鑰</returns>
        public static string ToBase64PrivateKey(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>
        /// 轉換"公鑰"格式
        /// </summary>
        /// <param name="xmlPublicKey">xml格式公鑰</param>
        /// <returns>base64格式公鑰</returns>
        public static string ToBase64PublicKey(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>
        /// 轉換"私鑰"格式
        /// </summary>
        /// <param name="privateKey">base64格式私鑰</param>
        /// <returns>xml格式私鑰</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>
        /// 轉換"公鑰"格式
        /// </summary>
        /// <param name="pubilcKey">base64格式公鑰</param>
        /// <returns>xml格式公鑰</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);
            }
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM